// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS)
// Copyright (C) 2025-present LeonOS 2 Developer Team
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

namespace UniLua
{
	// grep `NoTagMethodFlags' if num of TMS >= 32
	internal enum TMS
	{
		TM_INDEX,
		TM_NEWINDEX,
		TM_GC,
		TM_MODE,
		TM_LEN,
		TM_EQ,
		TM_ADD,
		TM_SUB,
		TM_MUL,
		TM_DIV,
		TM_MOD,
		TM_POW,
		TM_UNM,
		TM_LT,
		TM_LE,
		TM_CONCAT,
		TM_CALL,
		TM_N		/* number of elements in the enum */
	}

	public partial class LuaState
	{
		private string GetTagMethodName( TMS tm )
		{
			switch( tm )
			{
				case TMS.TM_INDEX: 		return "__index";
				case TMS.TM_NEWINDEX: 	return "__newindex";
				case TMS.TM_GC: 		return "__gc";
				case TMS.TM_MODE: 		return "__mode";
				case TMS.TM_LEN: 		return "__len";
				case TMS.TM_EQ: 		return "__eq";
				case TMS.TM_ADD: 		return "__add";
				case TMS.TM_SUB: 		return "__sub";
				case TMS.TM_MUL: 		return "__mul";
				case TMS.TM_DIV: 		return "__div";
				case TMS.TM_MOD: 		return "__mod";
				case TMS.TM_POW: 		return "__pow";
				case TMS.TM_UNM: 		return "__unm";
				case TMS.TM_LT: 		return "__lt";
				case TMS.TM_LE: 		return "__le";
				case TMS.TM_CONCAT: 	return "__concat";
				case TMS.TM_CALL: 		return "__call";
				default: throw new System.NotImplementedException();
			}
		}

		private StkId T_GetTM( LuaTable mt, TMS tm )
		{
			if( mt == null )
				return null;

			var res = mt.GetStr( GetTagMethodName( tm ) );
			if(res.V.TtIsNil()) // no tag method?
			{
				// cache this fact
				mt.NoTagMethodFlags |= 1u << (int)tm;
				return null;
			}
			else
				return res;
		}

		private StkId T_GetTMByObj( ref TValue o, TMS tm )
		{
			LuaTable mt = null;

			switch( o.Tt )
			{
				case (int)LuaType.LUA_TTABLE:
				{
					var tbl = o.HValue();
					mt = tbl.MetaTable;
					break;
				}
				case (int)LuaType.LUA_TUSERDATA:
				{
					var ud = o.RawUValue();
					mt = ud.MetaTable;
					break;
				}
				default:
				{
					mt = G.MetaTables[o.Tt];
					break;
				}
			}
			return (mt != null)
				 ? mt.GetStr( GetTagMethodName( tm ) )
				 : TheNilValue;
		}

	}

}

