#include "main.h"
#include <lua.h>
#include <lauxlib.h>
#include "lib_io.h"
#include "input.h"

static int lib_open(lua_State *L)
{
	const char *name = luaL_checkstring(L,1);
	Uint8 ioflags = luaL_checkint(L,2);
	if (!(ioflags & (1|1<<1)))
		return luaL_error(L,"No read or write operation given; Cannot open file.");
	if (name[0] == '/' || name[0] == '\\' || strstr(name,"..") || strstr(name,":") || strstr(name,"%"))
		return luaL_error(L,"No reverse or absolute folder navigation please.");
	Uint8 endian_force = 0;
	if (lua_gettop(L) >= 3 && !lua_isnil(L,3)) {
		if (lua_toboolean(L,3))
			endian_force = 1; // big endian
		else
			endian_force = 2; // little endian
	}
	Lua_File *data = lua_newuserdata(L, sizeof(Lua_File));
	data->endian = endian_force;
	char flags[4];
	int i = 0;
	if (ioflags & 1) {
		flags[i] = 'r';
		i++;
	}
	if (ioflags & (1<<1)) {
		flags[i] = 'w';
		i++;
	}
	if (ioflags & (1<<3)
	|| (!(ioflags & (1<<2))
		&& stricmp(&name[strlen(name)-3],"txt")
		&& stricmp(&name[strlen(name)-3],"log")
	)) { // Unless it's a txt, also make it a binary file.
		flags[i] = 'b';
		i++;
	}
	flags[i] = '\0';
	if (!(ioflags & (1<<1))) // Read can open from anywhere
		data->f = fopen(find_file(name),flags);
	else { // Write is restricted to own-directory: No cross-mod writing
		char *path;
		if (modpath)
		{
			path = malloc(strlen(modpath)+strlen(name)+2);
			sprintf(path,"%s/%s",modpath,name);
		} else {
			path = malloc(strlen(DEFAULTMOD)+strlen(name)+2);
			sprintf(path,"%s/%s",DEFAULTMOD,name);
		}
		data->f = fopen(path,flags);
		free(path);
	}

	luaL_getmetatable(L,"FILE*");
	lua_setmetatable(L,-2);
	return 1;
}

static int lib_exists(lua_State *L)
{
	lua_pushboolean(L,exists(find_file(luaL_checkstring(L,1))));
	return 1;
}

/*static inline int lib_binout(lua_State *L)
{
	int data = luaL_checkint(L,1);
	int bytes = luaL_optint(L,2,1);
	Uint8 endian_force = 0;
	if (lua_gettop(L) >= 3 && !lua_isnil(L,3)) {
		if (lua_toboolean(L,3))
			endian_force = 1; // big endian
		else
			endian_force = 2; // little endian
	}
	switch (bytes)
	{
	case 1: {
		Uint8 b = data;
		lua_pushlstring(L,&b,1);
		return 1;
	}
	case 2: {
		Uint16 b = data;
		if (endian_force == 1)
			b = SDL_SwapBE16(b);
		else if (endian_force == 2)
			b = SDL_SwapLE16(b);
		lua_pushlstring(L,(const char *)&b,2);
		return 1;
	}
	case 4: {
		if (endian_force == 1)
			data = SDL_SwapBE32(data);
		else if (endian_force == 2)
			data = SDL_SwapLE32(data);
		lua_pushlstring(L,(const char *)&data,4);
		return 1;
	}
	default:
		return luaL_error(L,"io.bin length must be 1, 2, or 4!");
	}
}

static inline int lib_binin(lua_State *L)
{
	const char *data = luaL_checkstring(L,1);
	int bytes = luaL_optint(L,2,1);
	Uint8 unsign = (lua_gettop(L) >= 3 && lua_toboolean(L,3));
	Uint8 endian_force = 0;
	if (lua_gettop(L) >= 4 && !lua_isnil(L,4)) {
		if (lua_toboolean(L,4))
			endian_force = 1; // big endian
		else
			endian_force = 2; // little endian
	}
	switch (bytes)
	{
	case 1: {
		Sint8 b = data[0];
		if (unsign)
			lua_pushinteger(L,(unsigned)b);
		else
			lua_pushinteger(L,b);
		return 1;
	}
	case 2: {
		Sint16 b;
		memcpy(&b,data,2);
		if (endian_force == 1)
			b = SDL_SwapBE16(b);
		else if (endian_force == 2)
			b = SDL_SwapLE16(b);
		if (unsign)
			lua_pushinteger(L,(unsigned)b);
		else
			lua_pushinteger(L,b);
		return 1;
	}
	case 4: {
		Sint32 b;
		memcpy(&b,data,4);
		if (endian_force == 1)
			b = SDL_SwapBE32(b);
		else if (endian_force == 2)
			b = SDL_SwapLE32(b);
		if (unsign)
			lua_pushinteger(L,(unsigned)b);
		else
			lua_pushinteger(L,b);
		return 1;
	}
	default:
		return luaL_error(L,"io.bin length must be 1, 2, or 4!");
	}
}

static int lib_binary(lua_State *L)
{
	if (lua_isnumber(L,1))
		return lib_binout(L);
	return lib_binin(L);
}*/

static luaL_Reg lib[] = {
	{"open",lib_open},
	{"exists",lib_exists},
	{NULL,NULL}
};

void agllib_io(lua_State *L, bool client)
{
	if (client) {
		lua_newtable(L);
		lua_setglobal(L,"input");

		int i;
		lua_newtable(L);
		for (i = 0; i < BTN_MAX; i++) {
			lua_pushnumber(L,i);
			lua_setfield(L,-2,btn_names[i]);
		}
		lua_setglobal(L,"BTN");
	}

	lua_newtable(L);
		lua_pushinteger(L,1);
		lua_setfield(L,-2,"READ");
		lua_pushinteger(L,1<<1);
		lua_setfield(L,-2,"WRITE");
		lua_pushinteger(L,1<<2);
		lua_setfield(L,-2,"TEXT");
	lua_setglobal(L,"IO");

	lua_newtable(L);
		lua_pushboolean(L,true);
		lua_setfield(L,-2,"BIG");
		lua_pushboolean(L,false);
		lua_setfield(L,-2,"LITTLE");
		lua_pushnil(L);
		lua_setfield(L,-2,"NATIVE");
	lua_setglobal(L,"ENDIAN");

	lua_newtable(L);
		lua_pushinteger(L,SEEK_SET);
		lua_setfield(L,-2,"SET");
		lua_pushinteger(L,SEEK_CUR);
		lua_setfield(L,-2,"CUR");
		lua_pushinteger(L,SEEK_END);
		lua_setfield(L,-2,"END");
	lua_setglobal(L,"SEEK");

	lua_pushboolean(L,false);
	lua_setglobal(L,"SIGNED");
	lua_pushboolean(L,true);
	lua_setglobal(L,"UNSIGNED");

	luaL_register(L,"io",lib);
	lua_pop(L,1);
}
