#ifndef LOADER_INCLUDE_H
#define LOADER_INCLUDE_H

#define PIGRECO 3.1415926535897932384626433832795f

#include <math.h>
#ifndef RELEASE_VERSION
	#define SEND_ERRORS_IDE_LEVEL 0
	#include "DebugSock.h"
#endif
#ifdef ENABLE_GAMEGRID
	#include "GameGrid.h"
#endif
#ifdef ENABLE_TTF_EXTENSION
	#include "GameTTF.h"
#endif
#include "GameFileSystem.h"
#include "GameFont.h"
#include "Utils.h"
#include "GameSettings.h"
#include "PFrogConsole.h"
#include "GameFPS.h"
#include "SimpleTextSmall.h"
#include "Compression/LZSoundData.h"
#include "compression/LZArchive.h"
#include <PocketFrog/PocketFrog.h>

#define MAX_LIBS 5

#define MAX_IMAGES 2000

#define MAX_GFX_FONTS 15

#ifdef ENABLE_AUDIO
	#define MAX_SOUNDS 500
	#define MAX_MUSICS 50
#endif
#ifdef ENABLE_TTF_EXTENSION
	#define MAX_FONTS 10
#endif
#define MAX_KEYS_BUFFER 255
#define MAX_TEMP_BUFFER_SIZE 8192
#ifdef ENABLE_GAMEGRID
	#define MAX_GAMEGRIDS 10
#endif

using namespace Frog;

extern "C" 
{ 
	#include <lua.h> 
	#include <luace.h> 
	#include <lauxlib.h> 
	#include <lualib.h> 

	#include "luasocket/luasocket.h" 
	#include "luasocket/mime.h" 
} 

class GameFont;

class Loader
{
private:
	lua_State * LUA;
	Utils *util;
#ifndef RELEASE_VERSION
	DebugSock *dsock;
#endif

	// larghezza / altezza schermo
	int _screenWidth, _screenHeight;

	// buffer temporaneo usato per sprintf vari, per non allocare ogni volta nuove stringhe
	char tmpbuffer[MAX_TEMP_BUFFER_SIZE];

#ifdef ENABLE_AUDIO
	// puntatore alla hekkus (inizializzata all'avvio dell'applicazione)
	hssSpeaker *hss_speaker;
#endif

	// colore trasparenza (impostato su init)
	Pixel transColor;

	// livello di blending corrente
	unsigned char _currentBlending;

	// funzioni trovate o no nello script principale
	bool lua_onMainLoop_found;
	bool lua_onQuit_found;
	bool lua_onMouseUp_found;
	bool lua_onMouseDown_found;
	bool lua_onMouseMove_found;
	bool lua_onButtonUp_found;
	bool lua_onButtonDown_found;
	bool lua_onGotFocus_found, lua_onLostFocus_found;
	bool lua_HaveTo_Call_MainScript, lua_MainScript_Called;

	// display pointer preso all'inizio della routine di draw
	// ci assicuriamo che dallo script LUA richiamiamo le funzioni di disegno
	// quando il buffer è disegnabile
	Display *DISPLAY;

	// disegna una linea orizzontale
	void _DrawHorizLine(Display *display, int LeftX, int RightX, int TopBotY, Pixel forecolor);

	// Tabella di conversione radianti->gradi
	float GRADE[360];

	// l'applicazione ha il focus
	bool _appHasFocus;

	// controlla il numero di parametri da una funzione LUA, torna true se 
	// è tutto ok e bisogna continuare
	bool checkParams(lua_State *pL, int num_expected, char *functname, bool isdrawingfunc);
	bool checkParams(lua_State *pL, int num_expected, int num_expected2, char *functname, bool isdrawingfunc);

	// risorse - fonts grafici
	int maxAllocatedGfxFonts;
	GameFont **gfxfonts;
	bool gfxfontsInit[MAX_GFX_FONTS];	// quali puntatori hai inizializzato

	// risorse - immagini
	int maxAllocatedImages;
	Surface **images;
	bool imagesInit[MAX_IMAGES];	// quali puntatori hai inizializzato

	// custom libraries
	int maxAllocatedLibs;
	HINSTANCE *libs;
	bool libsInit[MAX_LIBS];	// quali puntatori hai inizializzato

#ifdef ENABLE_AUDIO
	// risorse - suoni, musiche e relativi canali
	int maxAllocatedSounds, maxAllocatedMusics;
	LZSound **sounds;
	LZMusic **musics;
	hssChannel **soundsChannels, **musicsChannels;
	bool soundsInit[MAX_SOUNDS]; // quali puntatori hai inizializzato
	bool musicsInit[MAX_MUSICS]; // quali puntatori hai inizializzato
#endif

	// Gamegrids
#ifdef ENABLE_GAMEGRID
	int maxAllocatedGameGrids;
	GameGrid **gamegrids;
	bool gamegridsInit[MAX_GAMEGRIDS];	// quali puntatori hai inizializzato
#endif

	// fonts
#ifdef ENABLE_TTF_EXTENSION
	// tarocco per poter allocare l'oggetto libreria dinamicamente
	struct _ft_library {
		FT_Library lib; /* l'oggetto libreria */
	};
	struct _ft_library *ft_library;

	int maxAllocatedFonts;
	GameTTF **fonts;
	bool fontsInit[MAX_FONTS];	// quali puntatori hai inizializzato
#endif

	// buffer allocato dall'ultima chiamata di luaOpenRes
	char *openResBuffer; // tutto il buffer
	unsigned long openResLength;
	//linee trovate dopo il parsing del buffer in luaOpenRes (se richiesto
	struct _openResLine {
		int start, end;
	};
	struct _openResLine **openResLine;
	unsigned int openResNumLines;

	// puntatore alle costanti dei tasti
	PHAL::KeyList * keylist;

	// buffer di pressione testi
	unsigned short NUMKEYPRESS[MAX_KEYS_BUFFER];

	// oggetto settings usato all'interno delle funzioni di configurazione
	GameSettings *settings;

	// oggetto filesystem che gestisce i files scrivibili dall'utente nell'apposita dir
	GameFileSystem *fsystem;

	// conta quante volte siamo entrati nel main loop
	unsigned long mainloopCount;

	// smalltext usato in luaPrint
	SimpleTextSmall *smalltext;

	// flag per segnare l'uscita
	bool _shutDown;

	// stringa contenente la lista degli script da ignorare in fase di include
	// perchè avevano lunghezza zero. Corregge il fatto che lzab non mette i files
	// di lunghezza zero.
	// questo è un puntatore, viene mallocato e freato nel Blit.cpp
	char *_ignoredIncludeVoidScripts;

#ifndef RELEASE_VERSION
	// il modo step by step è abilitato
	bool _stepByStep, _doNextStep;
	bool _wantSetPause;	// vogliamo settare la pausa
	bool _announceWhereIsDebugger;	// settato a true all'inizio se siamo in modalità step, fa comunicare subito
									// via socket, dove si trova l'interprete
	// lista breakpoints
	struct breakpoint {
		char *file;
		unsigned long line;
		struct breakpoint *next;
	};
	struct breakpoint *breakpoints;
	// setta / unsetta breakpoint - torna true se lo aggiunge - false se lo toglie
	bool SwitchBreakPoint(char *file, unsigned long line);
	int ClearBreakpoints();
	int _numBreakpoints;

	// trova variabile nello stack corrente
	// se optindex è maggiore di 0, cerca la variabile per indice
	// invece che per nome
	int _FindVariableStack(lua_Debug *ar, char *varname, bool findUpValue);
	bool _SetVariableStackString(char *varname, int optindex, char *newvalue, char type);
	bool _SetVariableStackNumber(char *varname, int optindex, double newvalue, char type);
	bool _SetVariableStackBoolean(char *varname, int optindex, bool newvalue, char type);

	// l'editor ci ha dato l'ok per caricare lo script principale
	bool _editorIsReady;
#endif

	// ultime coordinate di click
	Point _lastClick;
	unsigned long _mouseIsDown;

	// avvia un msg di errore all'ide
	void SendErrorIDE(unsigned char loglevel, char *pattern, ...);

	// indice dell'ultima immagine selezionata come render target (se -1, è lo screen)
	int indexRenderTarget;
	void _FreeImage(int index);

	// effettua parsing linee file aperto con openres
	void _ParseResLines();

public:
	Loader(
		Pixel defaultTransColor,
#ifndef RELEASE_VERSION
		DebugSock *dsock, 
#endif
		Display *display, 
#ifdef ENABLE_AUDIO
		hssSpeaker *hss_speaker, 
#endif
		PHAL::KeyList * keylist, Utils *util,
		char *_ignoredIncludeVoidScripts
		);
	~Loader(void);
	void LoadMainScript( bool stepByStep );

#ifndef RELEASE_VERSION
	void OnDebugReceiveSocket(char *text);
	void _dumpLuaTable(lua_State* l,int idx);
#endif

	bool Shutdown();

	void draw(Display *display);
	void StylusUp( Point stylus );
	void StylusDown( Point stylus );
	void StylusMove( Point stylus );
	void ButtonUp(int button);
	void ButtonDown(int button);
	void GameLostFocus();
	void GameGotFocus();

	bool EditorIsReady();

	// Evento richiamato dalla main class quando il loader sta per essere distrutto
	void SignalQuit();

	// torna il livello di blending corrente
	unsigned char CurrentBlending();

	// LUA CALLS DISPATCHERS
	// misc
	int lua_Function_DebugSocket(lua_State *pL);
	int lua_Function_GetClock(lua_State *pL);
	int lua_Function_GetDate(lua_State *pL);
	int lua_Function_Include(lua_State *pL);
	int lua_Function_Getmemorystatus(lua_State *pL);
	int lua_Function_Getnumiterations(lua_State *pL);
	int lua_Function_Getfps(lua_State *pL);
	int lua_Function_Quit(lua_State *pL);
	int lua_Function_Windowfocused(lua_State *pL);
	// controls functions
	int lua_Function_KeyUp(lua_State *pL);
	int lua_Function_KeyLeft(lua_State *pL);
	int lua_Function_KeyRight(lua_State *pL);
	int lua_Function_KeyDown(lua_State *pL);
	int lua_Function_KeyFire1(lua_State *pL);
	int lua_Function_KeyFire2(lua_State *pL);
	int lua_Function_KeyFire3(lua_State *pL);
	int lua_Function_MouseDown(lua_State *pL);
	int lua_Function_MouseX(lua_State *pL);
	int lua_Function_MouseY(lua_State *pL);
	int lua_Function_MouseIn(lua_State *pL);
	int lua_Function_NumKeypress(lua_State *pL);
	// graphics functions
	int lua_Function_AddConsole(lua_State *pL);
	int lua_Function_Blending(lua_State *pL);
	int lua_Function_Circle(lua_State *pL, bool filled);
	int lua_Function_Clear(lua_State *pL);
	int lua_Function_Clipping(lua_State *pL);
	int lua_Function_ColorMask(lua_State *pL);
	int lua_Function_CreateImage(lua_State *pL);
	int lua_Function_DestroyImage(lua_State *pL);
	int lua_Function_DrawImage(lua_State *pL);
	int lua_Function_DrawRotateImage(lua_State *pL);
	int lua_Function_DrawRotateStretchImage(lua_State *pL);
	int lua_Function_DrawStretchImage(lua_State *pL);
	int lua_Function_GetColor(lua_State *pL);
	int lua_Function_ImageColor(lua_State *pL);
	int lua_Function_ImageWidth(lua_State *pL);
	int lua_Function_ImageHeight(lua_State *pL);
	int lua_Function_Line(lua_State *pL);
	int lua_Function_LoadImage(lua_State *pL);
	int lua_Function_Point(lua_State *pL);
	int lua_Function_Poly(lua_State *pL, bool filled);
	int lua_Function_Print(lua_State *pL);
	int lua_Function_Rect(lua_State *pL, bool filled);
	int lua_Function_RenderTarget(lua_State *pL);
	int lua_Function_ScreenWidth(lua_State *pL);
	int lua_Function_ScreenHeight(lua_State *pL);
	// sounds functions
#ifdef ENABLE_AUDIO
	int lua_Function_DestroyMusic(lua_State *pL);
	int lua_Function_DestroySound(lua_State *pL);
	int lua_Function_LoadMusic(lua_State *pL);
	int lua_Function_LoadSound(lua_State *pL);
	int lua_Function_PlayMusic(lua_State *pL);
	int lua_Function_PlaySound(lua_State *pL);
	int lua_Function_PauseSound(lua_State *pL);
	int lua_Function_ResumeSound(lua_State *pL);
	int lua_Function_PauseMusic(lua_State *pL);
	int lua_Function_ResumeMusic(lua_State *pL);
	int lua_Function_StopMusic(lua_State *pL);
	int lua_Function_StopSound(lua_State *pL);
	int lua_Function_MusicVolume(lua_State *pL);
	int lua_Function_SoundVolume(lua_State *pL);
	int lua_Function_StopAllSounds(lua_State *pL);
	int lua_Function_StopAllMusics(lua_State *pL);
#endif
	// config files functions
	int lua_Function_Openconfig(lua_State *pL);
	int lua_Function_OpenconfigExt(lua_State *pL);
	int lua_Function_Closeconfig(lua_State *pL);
	int lua_Function_Writeconfignumber(lua_State *pL);
	int lua_Function_Readconfignumber(lua_State *pL);
	int lua_Function_Writeconfigstring(lua_State *pL);
	int lua_Function_Readconfigstring(lua_State *pL);
	// debug hook handler
#ifndef RELEASE_VERSION
	void lua_Debug_HookRoutine(lua_State *L, lua_Debug *ar);
#endif
	// Gamegrids
#ifdef ENABLE_GAMEGRID
	int lua_Function_CreateGrid(lua_State *pL);
	int lua_Function_FillGrid(lua_State *pL);
	int lua_Function_DestroyGrid(lua_State *pL);
	int lua_Function_GridCell(lua_State *pL);
	int lua_Function_DrawGrid(lua_State *pL);
	int lua_Function_GridWorldX(lua_State *pL);
	int lua_Function_GridWorldY(lua_State *pL);
#endif
	// ttf fonts
#ifdef ENABLE_TTF_EXTENSION
	int lua_Function_LoadFont(lua_State *pL);
	int lua_Function_SetFont(lua_State *pL);
	int lua_Function_DrawText(lua_State *pL);
	int lua_Function_TextWidth(lua_State *pL);
	int lua_Function_DestroyFont(lua_State *pL);
#endif
	// custom libraries
	int lua_Function_LoadLibrary(lua_State *pL);
	int lua_Function_ExecLibrary(lua_State *pL);
	int lua_Function_FreeLibrary(lua_State *pL);
	// gfx fonts
	int lua_Function_LoadGfxFont(lua_State *pL);
	int lua_Function_DestroyGfxFont(lua_State *pL);
	int lua_Function_DrawGfxText(lua_State *pL);
	int lua_Function_GfxTextWidth(lua_State *pL);
	// resources
	int lua_Function_OpenRes(lua_State *pL);
	int lua_Function_OpenResExt(lua_State *pL);
	int lua_Function_GetRes(lua_State *pL);
	int lua_Function_GetResLine(lua_State *pL);
	int lua_Function_CloseRes(lua_State *pL);
	// filesystem
	int lua_Function_OpenFile(lua_State *pL);
	int lua_Function_WriteFile(lua_State *pL);
	int lua_Function_ReadFile(lua_State *pL);
	int lua_Function_CloseFile(lua_State *pL);
	int lua_Function_FileExists(lua_State *pL);
	int lua_Function_DeleteFile(lua_State *pL);
	int lua_Function_PosFile(lua_State *pL);
};

#endif
