// ---------------------------------------------------------------------------
// 
//   Lily Engine alpha
// 
//   Copyright (c) 2010 Clifford Jolly
//     http://cliffjolly.com
//     cliff@cliffjolly.com
// 
// ---------------------------------------------------------------------------
// 
//   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 2 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, write to the Free Software
//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
//   USA
// -------------------------- END HEADER -------------------------------------

// These are helpers for setting up Lua callbacks. Don't include them
// in normal code, or in other headers. It's actually context-dependent
// on the definition of WIDGET_TYPE!

// TODO: Make all the temporary variables used here consistent. Use a 
//   prefix or something so we don't bump into stuff the callback
//   writer might want to use.

extern "C" {
#include <lua.h>
}

#include "../console/console.h"

void widgetLuaSetFunctionInClass(lua_State *L, const std::string &className, const std::string &funcName, lua_CFunction func);
void widgetLuaCreateClass(lua_State *L, const std::string &className, const std::string &baseClass);

// Function definition for child classes to create an appropriate
// Lua table for itself.
#define WIDGET_GETLUATABLEFUNC(type) \
void type::getLuaTable(lua_State *L) { \
	lua_newtable(L); \
	cout << "1" << endl; \
	lua_pushstring(L, "uid"); \
	cout << "2" << endl; \
	lua_pushstring(L, getUID().c_str()); \
	cout << "3" << endl; \
	lua_settable(L, -3); \
	\
	cout << "4" << endl; \
	lua_getglobal(L, #type); \
	cout << "5" << endl; \
	cout << "5" << endl; \
	cout << "5" << endl; \
	cout << "5" << endl; \
	cout << "5" << endl; \
	cout << "5" << endl; \
	cout << "5" << endl; \
	cout << "5" << endl; \
	cout << "5" << endl; \
	lua_getfield(L, -1, "inheritFromMe"); \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	cout << "6" << endl; \
	lua_remove(L, -2); \
	\
	cout << "7" << endl; \
	lua_setmetatable(L, -2); \
} \

// For type verification.
#ifdef WIDGET_TYPE

#	define GET_WIDGET \
		WIDGET_TYPE *w = dynamic_cast<WIDGET_TYPE *>(widgetGetByUID(uid));

	WIDGET_GETLUATABLEFUNC(WIDGET_TYPE);

#else

#	define WIDGET_TYPE Widget
#	define GET_WIDGET \
		WIDGET_TYPE *w = widgetGetByUID(uid);

	WIDGET_GETLUATABLEFUNC(Widget);

#endif

// Quick macro to check the Lua stack for sanity.
#define CHECK_NUM_PARAMS(x) \
	int numParams = (x)+1; \
	if(numParams > lua_gettop(L)) { \
		Console::out("error") << "Not enough parameters for Lua callback " << __FUNCTION__ << "." << endl; \
		return 0; \
	}

#define GET_WIDGET_FROM_TABLE \
	if(!lua_istable(L, -numParams)) { \
		Console::out("error") << "Whatever you passed me as a Widget table isn't a Widget table." << endl; \
		return 0; \
	} \
	lua_getfield(L, -numParams, "uid"); \
	const char *lua_cstr_uid = lua_tostring(L, -1); \
	if(!lua_cstr_uid) { \
		Console::out("error") << "Whatever you passed me as a Widget UID isn't a Widget UID." << endl; \
		lua_pop(L, 1); \
		return 0; \
	} \
	\
	lua_pop(L, 1); \
	std::string uid = lua_cstr_uid; \
	GET_WIDGET \
	\
	if(!w) { \
		Console::out("error") << "Invalid Widget \"" << uid << "\"." << endl; \
		return 0; \
	} \
	

// Wraps up the return value to be sent back to Lua. (Pass the wanted
// RET_ macro in for the ret parameter.)

#define CALL_WIDGET_FUNC(func, ret) \
	GET_WIDGET_FROM_TABLE \
	ret(w->func); \
	
// No return value.
#define RET_NOTHING(x) \
	x; \
	return 0

// Bool return value.
#define RET_BOOL(x) \
	bool b = x; \
	lua_pushboolean(L, b); \
	return 1
	
// Number return.
#define RET_NUMBER(x) \
	float f = x; \
	lua_pushnumber(L, f); \
	return 1

// String return.
#define RET_STRING(x) \
	std::string s = x; \
	lua_pushstring(L, s.c_str()); \
	return 1

// String return.
#define RET_WIDGET(x) \
	std::string s = x ? x->getUID() : ""; \
	lua_pushstring(L, s.c_str()); \
	return 1
	
// Function definition
#define CB(func) \
	int widgetLuaCB##_##func(lua_State *L)

// Parameter types
#define PARAM_STRING(x, y) \
	std::string x = ""; \
	{ \
		const char *cstr = lua_tostring(L, y); \
		if(cstr) x = string(cstr); \
	}

#define PARAM_WIDGET(x, y) \
	PARAM_STRING(x##_##uid, y); \
	Widget *x = widgetGetByUID(x##_##uid);

#define PARAM_NUMBER(x, y) \
	float x = lua_tonumber(L, y)

//#define MAKE_LUA_CALLBACK(x) 
//	Console::out("lua") << "Adding Lua callback: widget_" #x << endl; 
//	lua_register(L, "widget_" #x, widgetLuaCB##_##x);

#define MAKE_LUA_CLASS(className, baseClassName) \
	widgetLuaCreateClass(L, #className, #baseClassName)

#define MAKE_LUA_CALLBACK(className, function) \
	Console::out("lua") << "Adding Lua callback: " #className "::" #function << endl; \
	widgetLuaSetFunctionInClass(L, #className, #function, widgetLuaCB##_##function)

#define WIDGET_BASECREATE(x) \
static int widgetLuaCB##_##create(lua_State *L) { \
	cout << "Creating a " #x << endl; \
	Widget *w = new x(); \
	w->getLuaTable(L); \
	return 1; \
}


