#include <string>
#include "core.h"
#include "log.h"
#include "game_lua_help.h"

class LuaStateWrapper
{
public:
	LuaStateWrapper()
	{
		m_luaState = LuaPlus::LuaState::Create();
		m_luaState->OpenLibs();
	}

	~LuaStateWrapper()
	{
		LuaPlus::LuaState::Destroy(m_luaState);
	}

	LuaPlus::LuaState& operator()()
	{
		return *m_luaState;
	}

private:
	LuaPlus::LuaState* m_luaState;
};

LuaPlus::LuaState& GetLuaState()
{
	static LuaStateWrapper instance;
	return instance();
}

void luaError(int errorcode)
{
	LuaPlus::LuaState* state = &GetLuaState();
	LuaPlus::LuaStackObject stackObj(state, -1);
	const char* errorStr = stackObj.GetString();
	if (errorStr) {
		GetLuaState().SetTop(0);
	}
	else {
		errorStr = "Unknown lua error";
	}

	Core::Error(errorStr);
}

void luaError(int errorcode, const char* filename)
{
	LuaPlus::LuaState* state = &GetLuaState();
	LuaPlus::LuaStackObject stackObj(state, -1);
	std::string errorStr = stackObj.GetString();
	if (!errorStr.empty()) {
		GetLuaState().SetTop(0);
	}
	else {
		errorStr = "Unknown lua error";
	}

	Core::Error(errorStr.c_str());
}

void luaLoadScript(const char* filename)
{
	char buffer[260];
	snprintf(buffer, sizeof(buffer), "data/scripts/%s", filename);

	int result = 0;
	result = GetLuaState().DoFile(buffer);

	if (result != 0) {
		luaError(result, buffer);
	}
}

void luaDoString(const char* str)
{
	int result = 0;
	result = GetLuaState().DoString(str);

	if (result != 0) {
		luaError(result);
	}
}

void luaCallFunction(const char* name)
{
	LuaPlus::LuaObject onGameStart = GetLuaState().GetGlobal(name);
	if (onGameStart.IsFunction())
	{
		LuaPlus::LuaFunctionVoid function = onGameStart;
		function();
	}
	else
	{
		Msg("missing function '%s'", name);
	}
}

glm::mat4 getMatrixFromLua(LuaPlus::LuaObject& matrix)
{
	glm::mat4 return_matrix = glm::identity<glm::mat4>();
	return return_matrix;
}

void LuaPlusErrorFunction(const char* errorMsg)
{
	Core::Error(errorMsg);
}

namespace LuaPlus
{
	void (*g_errorFunction)(const char*) = LuaPlusErrorFunction;
}