#include "main.h"
#include "input.h"
#include "gfx.h"
#include "sound.h"
#include "lua_config.h"
#include "ya_random.h"
#include "lua_main.h"

char *modpath = NULL;
bool wii_priority = false;

static inline void quit(void)
{
	Snd_Close();
	//Net_Quit();
	Lua_Close();
	//TTF_Quit();
	SDL_Quit();
	if (modpath)
		free(modpath);
}

int fatal_error(const char *fmt, ...)
{
	va_list argptr;
	va_start(argptr,fmt);
	int len = vfprintf(stderr,fmt,argptr);
	char msg[len];
	vsprintf(msg,fmt,argptr);
	va_end(argptr);
#ifdef __WIN32__
	// NOT THREAD SAFE: Message box appears for only a split second before client shuts down completely in such a case.
	MessageBox(0, msg, "Error", MB_ICONHAND);
#endif
	exit(1);
}

// ASCII hex to byte
char axtob(char *ptr)
{
	char i,c,val=0;
	for(i = 0; i < 2; i++) {
		c = *ptr++;
		if(c >= 'a') c &= 0x5f; // uppercase
		if(c < '0' || c > 'F') break;
		if(c < 'A' && c > '9') break;
		c -= 0x30;
		if(c > 9) c -= 7;
		val <<= 4;
		val |= c;
	}
	return val;
}

// File exists
bool exists(const char *path)
{
	FILE *f = fopen(path,"rb");
	if (!f)
		return false;
	fclose(f);
	return true;
}

// Find file at given path
char *find_file(const char *file)
{
	static char *path = NULL;
	if (modpath)
	{
		path = realloc(path,strlen(modpath)+strlen(file)+2);
		sprintf(path,"%s/%s",modpath,file);
	}
	if (!modpath || !exists(path))
	{
		path = realloc(path,strlen(DEFAULTMOD)+strlen(file)+2);
		sprintf(path,"%s/%s",DEFAULTMOD,file);
	}
	if (wii_priority && !exists(path))
	{
		path = realloc(path,strlen(WIIDATAPATH)+strlen(file)+2);
		sprintf(path,"%s/%s",WIIDATAPATH,file);
	}
	if (!exists(path))
	{
		path = realloc(path,strlen(DATAPATH)+strlen(file)+2);
		sprintf(path,"%s/%s",DATAPATH,file);
	}
	if (!wii_priority && !exists(path))
	{
		path = realloc(path,strlen(WIIDATAPATH)+strlen(file)+2);
		sprintf(path,"%s/%s",WIIDATAPATH,file);
	}
	if (!exists(path)) {
		// Last resort, try the application folder where Agora.exe is being run from.
		path = realloc(path,strlen(file)+1);
		strcpy(path,file);
	}
	return path;
}

// Find image at given path
char *find_image(const char *file, bool allow_wii)
{
	static const char *ext[] = {"bmp","pbm",NULL};
	char *path = NULL;
	Uint8 i;
	if (modpath)
		for (i = 0; ext[i]; i++) {
			path = realloc(path,strlen(modpath)+strlen(file)+strlen(ext[i])+3);
			sprintf(path,"%s/%s.%s",modpath,file,ext[i]);
			if (exists(path))
				return path;
		}
	for (i = 0; ext[i]; i++) {
		path = realloc(path,strlen(DEFAULTMOD)+strlen(file)+strlen(ext[i])+3);
		sprintf(path,"%s/%s.%s",DEFAULTMOD,file,ext[i]);
		if (exists(path))
			return path;
	}
	if (allow_wii) {
		for (i = 0; ext[i]; i++) {
			path = realloc(path,strlen(WIIDATAPATH)+strlen(file)+strlen(ext[i])+3);
			sprintf(path,"%s/%s.%s",WIIDATAPATH,file,ext[i]);
			if (exists(path))
				return path;
		}
	}
	for (i = 0; ext[i]; i++) {
		path = realloc(path,strlen(DATAPATH)+strlen(file)+strlen(ext[i])+3);
		sprintf(path,"%s/%s.%s",DATAPATH,file,ext[i]);
		if (exists(path))
			return path;
	}
	return NULL;
}

static bool GameLoop(bool think_only)
{
	SDL_Event event;
	while(SDL_PollEvent(&event))
		if(I_HandleEvent(event))
			return false;

	{
		Uint16 i;
		for (i = 0; i < BTN_MAX; i++)
			if (buttons & (1<<i))
				button_time[i]++;
	}

	// THINK
	Lua_Think();

	{
		Uint16 i;
		for (i = 0; i < BTN_MAX; i++)
			if (btn_end & (1<<i))
				button_time[i] = 0;
	}
	btn_start = 0;
	btn_end = 0;

	if (!think_only && (gfx_flags & GFX_CANDRAW))
	{
		// DRAW
		Lua_Draw();
		Gfx_Update();
	}
	return true;
}

int main(int argc, char *argv[])
{
	if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE) < 0)
		return fatal_error("SDL failed to initialize properly: %s\n", SDL_GetError());
	atexit(quit);
	//TTF_Init();

	Gfx_Init();
	//Net_Init();

	SDL_JoystickEventState(SDL_ENABLE);
	SDL_EnableKeyRepeat(0,0);
	ya_rand_init_with_seed(time(NULL));

	Uint32 next_tick = 0;
	Uint8 skip_count = 0;

	bool skip;
	Uint32 frames_drawn=0,frames_skipped=0;

	Uint32 start_tick = SDL_GetTicks();
	Uint32 game_loops = 0;
	Uint16 half_tick = 0;

	Lua_ReadConfig();
	Snd_Init();
	Lua_Init();
	Gfx_ReInit();
	bool could_draw = false;
	do {
		game_loops++;

		// Check FPS
		if (gfx_flags & GFX_CANDRAW) {
			Uint32 this_tick = SDL_GetTicks();
			if (!could_draw || this_tick-start_tick >= 1000) {
				could_draw = true;
				//printf("%.03f / %.03f FPS\n",frames_drawn/((this_tick-start_tick)/1000.0f),(frames_drawn+frames_skipped)/((this_tick-start_tick)/1000.0f));
				Lua_FPS(frames_drawn/((this_tick-start_tick)/1000.0f));
				start_tick = this_tick;
				frames_drawn = 0;
				frames_skipped = 0;
			}
		} else
			could_draw = false;

		// Delay frame
		if (gfx_flags & GFX_CANDRAW) {
			while(SDL_GetTicks() < next_tick)
				SDL_Delay(0);
		} else {
			Uint32 this_tick = SDL_GetTicks();
			if (next_tick > this_tick)
				SDL_Delay(next_tick - this_tick);
		}
		//next_tick += 16;
		//half_tick += 667;
		next_tick += 20;
		if (half_tick >= 1000) {
			next_tick += half_tick/1000;
			half_tick %= 1000;
		}

		// CHANGE GAMESTATE

		// Decide whether to skip drawing or not
		skip = (!(gfx_flags & GFX_CANDRAW) || SDL_GetTicks() >= next_tick);
		if (skip && (gfx_flags & GFX_CANDRAW)) {
			skip_count++;
			if (skip_count >= 30) {
				skip = false;
				next_tick = SDL_GetTicks();
			}
			if (skip)
				frames_skipped++;
		} else {
			skip_count = 0;
			frames_drawn++;
		}
	} while(GameLoop(skip));

	return 0;
}

#ifdef WIN32
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE res1, LPSTR args, int res2)
{
	SDL_SetModuleHandle(hInst); //GetModuleHandle(NULL)
	return SDL_main(0,NULL);
}
#endif
