// BLANKART
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file  lua_script.h
/// \brief Lua scripting basics

#ifndef LUA_SCRIPT_H
#define LUA_SCRIPT_H

#include "m_fixed.h"
#include "doomtype.h"
#include "d_player.h"
#include "g_state.h"
#include "taglist.h"
#include "g_game.h" // G_GamestateUsesLevel

#include "blua/lua.h"
#include "blua/lualib.h"
#include "blua/lauxlib.h"

#ifdef __cplusplus
extern "C" {
#endif

#define lua_optboolean(L, i) (!lua_isnoneornil(L, i) && lua_toboolean(L, i))
#define lua_opttrueboolean(L, i) (lua_isnoneornil(L, i) || lua_toboolean(L, i))

// fixed_t casting
// TODO add some distinction between fixed numbers and integer numbers
// for at least the purpose of printing and maybe math.
#define lua_tofixed(L, i) lua_tointeger(L, i)
#define luaL_checkfixed(L, i) luaL_checkinteger(L, i)
#define luaL_optfixed(L, i, d) luaL_optinteger(L, i, d)
#define lua_pushfixed(L, f) lua_pushinteger(L, f)

// angle_t casting
// TODO deal with signedness
#define luaL_checkangle(L, i) ((angle_t)luaL_checkinteger(L, i))
#define lua_pushangle(L, a) lua_pushinteger(L, a)

#ifdef _DEBUG
void LUA_ClearExtVars(void);
#endif

void LUA_ClearState(void);

extern INT32 lua_lumploading; // is LUA_LoadLump being called?
extern boolean lua_compatmode; // compatmode enabled for this lump/hook?

int LUA_GetErrorMessage(lua_State *L);
int LUA_Call(lua_State *L, int nargs, int nresults, int errorhandlerindex, boolean compat, boolean printerror);
void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults);
#ifdef LUA_ALLOW_BYTECODE
void LUA_DumpFile(const char *filename);
#endif
fixed_t LUA_EvalMath(const char *word);
void LUA_Step(void);
void LUA_Sync(savebuffer_t *save, boolean network, boolean compat);

void LUA_SetCFunctionField(lua_State *L, const char *name, lua_CFunction value);

void LUA_RegisterUserdataMetatable(
	lua_State *L,
	const char *name,
	lua_CFunction get,
	lua_CFunction set,
	lua_CFunction len
);

int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_WriteGlobals(lua_State *L, const char *word);

void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
void LUA_CVarChanged(void *cvar); // lua_consolelib.c
int Lua_optoption(lua_State *L, int narg,
	const char *def, const char *const lst[]);
void LUA_HookNetArchive(lua_CFunction archFunc, savebuffer_t *save);

void LUA_PushTaggableObjectArray
(		lua_State *L,
		const char *field,
		lua_CFunction iterator,
		lua_CFunction indexer,
		lua_CFunction counter,
		taggroup_t *garray[],
		size_t * max_elements,
		void * element_array,
		size_t sizeof_element,
		const char *meta);

void LUA_InsertTaggroupIterator
(		lua_State *L,
		taggroup_t *garray[],
		size_t * max_elements,
		void * element_array,
		size_t sizeof_element,
		const char * meta);

typedef enum {
	LPUSHED_NIL,
	LPUSHED_NEW,
	LPUSHED_EXISTING,
} lpushed_t;

void LUA_PushUserdata(lua_State *L, void *data, const char *meta);
lpushed_t LUA_RawPushUserdata(lua_State *L, void *data);

void LUA_InvalidateUserdata(void *data);

void LUA_InvalidateLevel(void);
void LUA_InvalidateMapthings(void);
void LUA_InvalidatePlayer(player_t *player);

// Console wrapper
void COM_Lua_f(void);

#define LUA_ErrInvalid(L, type) luaL_error(L, "accessed " type " doesn't exist anymore, please check 'valid' before using " type ".");

#define LUA_ErrSetDirectly(L, type, field) luaL_error(L, type " field " LUA_QL(field) " cannot be set directly.")

// Deprecation warnings
// Shows once upon use. Then doesn't show again.
#define LUA_Deprecated(L,this_func,use_instead)\
{\
	static UINT8 seen = 0;\
	if (!seen) {\
		seen = 1;\
		CONS_Alert(CONS_WARNING,"\"%s\" is deprecated in BlanKart.\nUse \"%s\" instead.\n", this_func, use_instead);\
	}\
}

// Warnings about incorrect function usage.
// Shows once, then never again, like deprecation
#define LUA_UsageWarning(L, warningmsg)\
{\
	static UINT8 seen = 0;\
	if (!seen) {\
		seen = 1;\
		CONS_Alert(CONS_WARNING,"%s\n", warningmsg);\
	}\
}

// uncomment if you want seg_t/node_t in Lua
// #define HAVE_LUA_SEGS

#define INLEVEL if (!G_GamestateUsesLevel())\
return luaL_error(L, "This can only be used in a level!");

#ifdef __cplusplus
} // extern "C"
#endif

#endif/*LUA_SCRIPT_H*/
