/** @file EABaseTypesLua.h
*	lua_State factory for EABaseTypes
*	@author Chris Burns (cburns@ea.com)
*
*	UX
*	(c) 2012 Electronic Arts Inc.
*/

#ifndef EABASETYPESLUA_EABASETYPESLUA_H
#define EABASETYPESLUA_EABASETYPESLUA_H

#include "EABaseTypes/autoref.h"
#include "EABaseTypes/string.h"

extern "C"
{
	struct lua_State;
}

namespace EA
{
	namespace Allocator
	{
		class ICoreAllocator;
	}

	namespace Types
	{
		class Factory;

		EABASETYPES_FORWARD_DECLARATION(class, Function)
		EABASETYPES_FORWARD_DECLARATION(class, UserData)

		EABASETYPES_FORWARD_DECLARATION(class, IFileHandler)

		class JsonLoader;
	}
}

namespace EA
{
	namespace Lua
	{
		/*!
		 *	create a new lua_State
		 *	@param[in]	luaAllocator	The allocator to use for LUA allocations (doesn't need to be threadsafe, should be a fast SBA)
		 *	@param[in]	allocator		The allocator to use for non-LUA allocations (file loading, etc)
		 *	@param[in]	factory			The factory to use for creating EA::Types::BaseTypes
		 *	@param[in]	fileHandler		The file handler to use for loading files
		 *	@param[in]	print			The function to use for printing (takes a string)
		 *	@param[in]	error			The error function (takes a string)
		 */
		lua_State *NewState(EA::Allocator::ICoreAllocator* luaAllocator,
							EA::Allocator::ICoreAllocator* allocator, 
							EA::Types::Factory* factory,
							EA::Types::IFileHandlerIn fileHandler,
							EA::Types::JsonLoader* jsonLoader,
							EA::Types::FunctionIn print,
							EA::Types::FunctionIn error);

		EA::Allocator::ICoreAllocator* GetAllocator(lua_State* L);

		EA::Types::Factory* GetFactory(lua_State* L);

		static const unsigned int CALLER_TYPE = 0x58430685;

		/*!
		 *	push a Function as a LUA value on the stack. 
		 *	@param[in]	L		lua_State* of the interpreter whose stack we are going to push this onto
		 *	@param[in]	value	EA::Types::FunctionIn to push as a LUA value
		 */
		void PushFunction(lua_State* L, EA::Types::FunctionIn value);

		/*!
		 *	push a UserData as a LUA value on the stack. 
		 *	@param[in]	L		lua_State* of the interpreter whose stack we are going to push this onto
		 *	@param[in]	value	EA::Types::UserDataIn to push as a LUA value
		 */
		void PushUserData(lua_State* L, EA::Types::UserDataIn value);

		/*!
		 * create a Function from a LUA value on the stack
		 *	@param[in]	L		lua_State* of the interpreter whose stack contains the value
		 *	@param[in]	index	index of the value
		 */
		EA::Types::FunctionReturn CreateFunction(lua_State* L, int index);

		/*!
		 *	Call a LUA function on the stack
		 *	This function behaves exactly like lua_call, except that it is not fatal on errors (it will assert and print out a backtrace instead of exiting)
		 *	@param	L			The lua_State
		 *	@param	nargs		The number of arguments on the stack
		 *	@param	nresults	The number of results to push (or LUA_MULTRET)
		 */
		void Call(lua_State *L, int nargs, int nresults);

		/*!
		 *	Get the current backtrace for this lua_State
		 *	@param	L		The lua_State
		 *	@param	level	The stack level to start from (0 being the current C function)
		 *	@return	EA::RawString	The backtrace
		 */
		EA::RawString GetBacktrace(lua_State* L, int level);

		/*!
		 *	Print the current backtrace for this lua_State
		 *	@param	L		The lua_State
		 *	@param	level	The stack level to start from (0 being the current C function)
		 */
		void PrintBacktrace(lua_State* L, int level);
	}
}

#endif /* EABASETYPESLUA_EABASETYPESLUA_H */
