/** @file luaencoder.cpp
 *  Encoder implementation for LUA
 * 	@headerfile luaencoder.h "ux_base/luaencoder.h"
 *	@author Chris Burns (cburns@ea.com)
 *
 *	UX
 *	(c) 2011 Electronic Arts Inc. 
 */

#include "EABaseTypesLua/luaencoder.h"
#include "EABaseTypesLua/EABaseTypesLua.h"

namespace EA
{
	namespace Lua
	{
		LuaEncoder::LuaEncoder(lua_State* L):
			mL(L),
			mStackBase(lua_gettop(L))
		{
		}

		void LuaEncoder::Reset()
		{
			lua_settop(mL, mStackBase);
		}

		void LuaEncoder::BeginArray()
		{
			lua_checkstack(mL, 2);

			lua_newtable(mL);
		}

		void LuaEncoder::BeginArrayValue(size_t index)
		{
			lua_pushinteger(mL, static_cast<int>(index) + 1);
		}
		
		void LuaEncoder::EndArrayValue(size_t index)
		{
			lua_settable(mL, -3);
		}

		void LuaEncoder::BeginObject()
		{
			lua_checkstack(mL, 2);

			lua_newtable(mL);
		}

		void LuaEncoder::BeginObjectValue(const char* key, size_t length)
		{
			lua_pushlstring(mL, key, length);
		}

		void LuaEncoder::EndObjectValue(const char* key, size_t length)
		{
			lua_settable(mL, -3);
		}

		//lint -efunc(730, UX::LuaEncoder::Boolean)
		void LuaEncoder::Boolean(bool boolean)
		{
			lua_checkstack(mL, 1);

			lua_pushboolean(mL, boolean);
		}

		void LuaEncoder::Number(EA::BaseTypeFloat number)
		{
			lua_checkstack(mL, 1);

			lua_pushnumber(mL, static_cast<lua_Number>(number));
		}

		void LuaEncoder::String(const char* str, size_t length)
		{
			lua_checkstack(mL, 1);

			lua_pushlstring(mL, str, length);
		}

		void LuaEncoder::Function(EA::Types::FunctionIn function)
		{
			lua_checkstack(mL, 1);
			
			EA::Lua::PushFunction(mL, function);
		}

		void LuaEncoder::UserData(EA::Types::UserDataIn userData)
		{
			lua_checkstack(mL, 1);
			
			EA::Lua::PushUserData(mL, userData);
		}

		void LuaEncoder::Null()
		{
			lua_checkstack(mL, 1);

			lua_pushnil(mL);
		}

		bool IsArray(lua_State* L, int index)
		{
			// a LUA table is an array if it has some contiguous 1-based keys
			bool result = false;

			lua_checkstack(L, 2);

			lua_pushnil(L);
			if(lua_next(L, index) == 0)
			{
				// consider empty tables to be arrays
				result = true;
			}
			else
			{
				lua_pop(L, 2);

				int arrayIndex = 0;

				bool condition = true;

				do
				{
					arrayIndex++;

					lua_pushinteger(L, arrayIndex);

					lua_gettable(L, index);

					condition = !lua_isnil(L, -1);
					
					lua_pop(L, 1);
				}
				while(condition);

				result = arrayIndex > 1;
			}

			return result;
		}
	}
}
