#include	<stdlib.h>
#include	<stdio.h>
#include	<string.h>
#include	"gb.h"
#include	"gfxfunc.h"
#include	"readvars.h"
#include	"prefs.h"
#include	"keycodes.h"

#define	ELEMENTS(x)	(sizeof(x)/sizeof(x[0]))

char	*StringClone(char *from);
void	ReadStringArray(char *Variable, char *data, char **out, int number);
void	WriteStringArray(char *variable, char *output, char **strings, int number);

int	SlowDown=0;
int	ScrollOffset=0;
int	method=1;
int	SpritesOn=1,WindowOn=1,BackgroundOn=1;

GXPALETTE	GameBoyPalette[]={
	{0xff,0xff,0xff,0},{0xbb,0xbb,0xbb,0},{0x66,0x66,0x66,0},{0x00,0x00,0x00,0},
	{0xff,0xff,0xff,0},{0xbb,0xbb,0xbb,0},{0x66,0x66,0x66,0},{0x00,0x00,0x00,0},
	{0xff,0xff,0xff,0},{0xbb,0xbb,0xbb,0},{0x66,0x66,0x66,0},{0x00,0x00,0x00,0},
	{0xff,0xff,0xff,0},{0xbb,0xbb,0xbb,0},{0x66,0x66,0x66,0},{0x00,0x00,0x00,0}
						};
char	*TimeOutStrings[]={"End of demo"};
int		NTimeOutStrings=sizeof(TimeOutStrings)/sizeof(TimeOutStrings[0]);
char	*FontGfxName="gfx/topaz11.pic";
char	*FontCutName="gfx/topaz11.txt";
char	*TitleStrings[]={"Load Game","Save Game","Screen Grab","Palette Options"};
char	*MenuStrings[]={"Main menu","Load","Palette","Keys","Save","Grab","Quit","Cancel",
						"Dump Gfx"};
char	*FileStrings[]={"PARENT","VOLUMES","OK","CANCEL","READING..."};
char	*PaletteStrings[]={	"Red","Green","Blue","Okay","Cancel",
							"Back","Window","Sprite 0",
							"Sprite 1"};
char	*ErrorString[]={"Bad gameboy file",
						"Trouble reading disk"};
long	KeyPrefs[]={	KEY_NUMPAD6,    KEY_NUMPAD4,KEY_NUMPAD8, KEY_NUMPAD2,
						KEY_LEFTSHIFT,	KEY_TAB,	KEY_LEFTALT, KEY_CONTROL
//						KEY_Q,	KEY_W,	KEY_E, KEY_R
					};
int	NKeyPrefs=8;
char	*KeyStrings[]={	"Right","Left","Up","Down","Button A","Button B",
						"Select","Start","Keyboard options","Unnamed key"};
KEYNAMES	KeyNames[]={
{"Backspace",KEY_BACKSPACE},{"Escape",KEY_ESCAPE},
{"F1",KEY_F1},{"F2",KEY_F2},{"F3",KEY_F3},{"F4",KEY_F4},{"F5",KEY_F5},
{"F6",KEY_F6},{"F7"},{"F8",KEY_F8},{"F9",KEY_F9},{"F10",KEY_F10},
{"1",KEY_1},{"2",KEY_2},{"3",KEY_3},{"4",KEY_4},{"5",KEY_5},{"6",KEY_6},{"7",KEY_7},
{"8",KEY_8},{"9",KEY_9},{"0",KEY_0},{"-",KEY_MINUS},{"=",KEY_EQUALS},
{"Tab",KEY_TAB},{"Q",KEY_Q},{"W",KEY_W},{"E",KEY_E},{"R",KEY_R},{"T",KEY_T},{"Y",KEY_Y},
{"U",KEY_U},{"I",KEY_I},{"O",KEY_O},{"P",KEY_P},{"Square bracket(l)",KEY_LEFTSQUAREBRACKET},
{"Square bracket(r)",KEY_RIGHTSQUAREBRACKET},{"Return",KEY_RETURN},
{"Control",KEY_CONTROL},{"Caps lock",KEY_CAPSLOCK},{"A",KEY_A},{"S",KEY_S},{"D",KEY_D},{"F",KEY_F},
{"G",KEY_G},{"H",KEY_H},{"J",KEY_J},{"K",KEY_K},{"l",KEY_L},{"Semi colon",KEY_SEMICOLON},
{"Hash",KEY_HASH},
{"Left shift",KEY_LEFTSHIFT},{"Z",KEY_Z},{"X",KEY_X},{"C",KEY_C},{"V",KEY_V},{"B",KEY_B},{"N",KEY_N},
{"M",KEY_M},{"Comma",KEY_COMMA},{"Full stop",KEY_FULLSTOP},{"Forward slash",KEY_FORWARDSLASH},
{"Right shift",KEY_RIGHTSHIFT},
{"Left alt",KEY_LEFTALT},{"Left amiga",KEY_LEFTAMIGA},{"Space",KEY_SPACE},{"Right amiga",KEY_RIGHTAMIGA},
{"Right alt",KEY_RIGHTALT},
{"Delete",KEY_DELETE},{"Cursor left",KEY_CURSORLEFT},{"Cursor right",KEY_CURSORRIGHT},{"Cursor up",KEY_CURSORUP},
{"Cursor down",KEY_CURSORDOWN},
{"Left bracket",KEY_NUMPADLEFTBRACKET},{"Right bracket",KEY_NUMPADRIGHTBRACKET},{"Forward slash",KEY_NUMPADFORWARDSLASH},
{"7 (numpad)",KEY_NUMPAD7},{"8 (numpad)",KEY_NUMPAD8},{"9 (numpad)",KEY_NUMPAD9},{"-",KEY_NUMPADPLUS},
{"4 (numpad)",KEY_NUMPAD4},{"5 (numpad)",KEY_NUMPAD5},{"6 (numpad)",KEY_NUMPAD6},{"+",KEY_NUMPADMINUS},
{"1 (numpad)",KEY_NUMPAD1},{"2 (numpad)",KEY_NUMPAD2},{"3 (numpad)",KEY_NUMPAD3},{"Enter",KEY_ENTER},
{"0 (numpad)",KEY_NUMPAD0},{"Full stop (numpad)",KEY_NUMPADFULLSTOP}
};

	int	NKeyNames=sizeof(KeyNames)/sizeof(KeyNames[0]);
void	LoadPrefs(void)
{
	char			*data,*data2;
	size_t			size;
	char			VarName[256];
	VARIABLEHEADER	*header;
	VARIABLE		*var;
	int				j, left, row, number;
	KEYNAMES		*KeyPtr;
	char			*StringArray[10];

	GXPrintf("Loading variables\n");
	data=(char *)GXLoadFileToMemory("prefs",&size);
	if(!data)return;
	data2=(char *)GXGetMem(size+1, MEMF_ABORT);
	memcpy(data2, data, size);
	data2[size]=0;
	GXFreeMem(data);
	data=data2;
	
	//**************************************
	//	Read palette
	//**************************************
	for(j=0; j<16; j++){
		sprintf(VarName,"GB_PALETTE%d",j);
		header=FindVariable(VarName, data);
		if(header){
			if(header->Number==3){
				var=header->Data;
				if(var[0].Type==VARIABLE_NUMBER)
					GameBoyPalette[j].Red=var[0].Data.Number;
				if(var[1].Type==VARIABLE_NUMBER)
					GameBoyPalette[j].Green=var[1].Data.Number;
				if(var[2].Type==VARIABLE_NUMBER)
					GameBoyPalette[j].Blue=var[2].Data.Number;
			}else{
				GXPrintf("Wrong number of variables\n");
			}
			KillVariable(header);
		}else{
			GXPrintf("Couldnt find %s\n",VarName);
		}
	}

	//*******************************************************
	//	Read font names
	//*******************************************************
	FontGfxName=0;
	if(header=FindVariable("FONT_GFX",data)){
		var=header->Data;
		if(var->Type==VARIABLE_STRING){
			GXPrintf("%s\n",var->Data.String);
			FontGfxName=StringClone(var->Data.String);
		}
		KillVariable(header);
	}
	if(!FontGfxName){
		FontGfxName=StringClone("gfx/topaz11.iff");
	}
	FontCutName=0;
	if(header=FindVariable("FONT_CUT",data)){
		var=header->Data;
		if(var->Type==VARIABLE_STRING){
			GXPrintf("%s\n",var->Data.String);
			FontCutName=StringClone(var->Data.String);
		}
		KillVariable(header);
	}
	if(!FontCutName){
		FontCutName=StringClone("gfx/topaz11.txt");
	}

	//*******************************************************
	//	Keyboard prefs
	//*******************************************************
	if(header=FindVariable("KEY_PREFS",data)){
		if(header->Number==8){
			var=header->Data;
			for(j=0; j<8; j++,var++){
				if(var->Type==VARIABLE_NUMBER){
					KeyPrefs[j]=var->Data.Number;
				}
			}
		}
		KillVariable(header);
	}

	//*******************************************************
	//	Keyboard names
	//*******************************************************
	left=ELEMENTS(KeyNames);
	KeyPtr=KeyNames;
	row=0;
	do{
		number=left<10?left:10;
		sprintf(VarName,"KEYNAMES_%d",row);
		ReadStringArray(VarName, data, StringArray, number);
		for(j=0; j<number; j++){
			KeyPtr->Name=StringArray[j];
			KeyPtr++;
			left--;
		}
		row++;
	}while(left);


	//	Read button names and such like
	ReadStringArray("JOYPAD_NAMES", data, KeyStrings, ELEMENTS(KeyStrings));
	ReadStringArray("ERROR_MESSAGES", data, ErrorString, ELEMENTS(ErrorString));
	ReadStringArray("FILE_REQUESTOR", data, FileStrings, ELEMENTS(FileStrings));
	ReadStringArray("PALETTE_STRINGS", data, PaletteStrings, ELEMENTS(PaletteStrings));
	ReadStringArray("SIDE_MENU", data, MenuStrings, ELEMENTS(MenuStrings));
	ReadStringArray("TITLE_STRINGS", data, TitleStrings, ELEMENTS(TitleStrings));
	ReadStringArray("TIMEOUT_STRINGS", data, TimeOutStrings, ELEMENTS(TimeOutStrings));

	//	Read rendering method and gfx switches
//*******************************************************
#define	READNUMBER(name,output)						\
		if(header=FindVariable(name,data)){			\
			var=header->Data;						\
			if(var->Type==VARIABLE_NUMBER){			\
				output=var->Data.Number;			\
			}										\
			KillVariable(header);					\
		}
//*******************************************************
	READNUMBER("METHOD",method);
	READNUMBER("SPRITES_ON",SpritesOn);
	READNUMBER("WINDOW_ON",WindowOn);
	READNUMBER("BACKGROUND_ON",BackgroundOn);
	READNUMBER("SCROLL_OFFSET",ScrollOffset);	
	READNUMBER("SLOW_DOWN",SlowDown);	

	//	Read emulation constants
	READNUMBER("VERBOSE",Verbose);
	READNUMBER("VPERIOD",VPeriod);
	READNUMBER("UPERIOD",UPeriod);
	READNUMBER("LINEDELAY",LineDelay);
	READNUMBER("CHECKCRC",CheckCRC);	
	GXFreeMem(data);
}

void	ReadStringArray(char *Variable, char *data, char **out, int number)
{
	VARIABLEHEADER	*header;
	VARIABLE		*var;
	int	j;
	
	if(header=FindVariable(Variable, data)){
		if(header->Number==number){
			var=header->Data;
			for(j=0; j<number; j++,var++){
				if(var->Type==VARIABLE_STRING){
					out[j]=StringClone(var->Data.String);
				}
			}
		}
		KillVariable(header);
	}
}

void	WriteStringArray(char *variable, char *output, char **strings, int number)
{
	int	j;

	sprintf(output,"%s=",variable);
	for(j=0; j<number; j++){
		strcat(output,"\"");
		strcat(output,strings[j]);
		strcat(output,"\"");
		strcat(output,",");
	}
	j=strlen(output);
	output[j-1]='\n';
	output[j]=0;
}


char	*StringClone(char *from)
{
	char *to;
	
	to=(char *)GXGetMem( (strlen(from)+1)*sizeof(char), MEMF_ABORT);
	strcpy(to, from);
	return to;
}

#define	UPDATE_DATA		if(WriteData){						\
							strcpy(out,VarString);			\
							out+=strlen(VarString); 		\
						}else{								\
							LengthData+=strlen(VarString);		\
						}
void	SavePrefs(void)
{
	char		VarString[256],*data,*out;
	int			WriteData,icolor,left;
	GXPALETTE	*pal;
	size_t		LengthData;
	char		*StringArray[10],VarName[64];
	int				j, row, number;
	KEYNAMES		*KeyPtr;

	LengthData=0;
	for(WriteData=0; WriteData<2; WriteData++){

		sprintf(VarString,"SLOW_DOWN=%d\n",SlowDown);
		UPDATE_DATA
		sprintf(VarString,"VERBOSE=%d\n",Verbose);
		UPDATE_DATA
		sprintf(VarString,"VPERIOD=%d\n",VPeriod);
		UPDATE_DATA
		sprintf(VarString,"UPERIOD=%d\n",UPeriod);
		UPDATE_DATA
		sprintf(VarString,"LINEDELAY=%d\n",LineDelay);
		UPDATE_DATA
		sprintf(VarString,"CHECKCRC=%d\n",CheckCRC);	
		UPDATE_DATA

		sprintf(VarString,"SCROLL_OFFSET=%d\n",ScrollOffset);
		UPDATE_DATA
		sprintf(VarString,"METHOD=%d\n",method);
		UPDATE_DATA
		sprintf(VarString,"SPRITES_ON=%d\n",SpritesOn);
		UPDATE_DATA
		sprintf(VarString,"WINDOW_ON=%d\n",WindowOn);
		UPDATE_DATA
		sprintf(VarString,"BACKGROUND_ON=%d\n",BackgroundOn);
		UPDATE_DATA

		//	Write palette
		pal=GameBoyPalette;
		for(icolor=0; icolor<16; icolor++){
			sprintf(VarString,"GB_PALETTE%d=%d,%d,%d\n",
					icolor,
					(int)pal->Red,(int)pal->Green,(int)pal->Blue);
			UPDATE_DATA
			pal++;
		}
		
		//Write font data
		sprintf(VarString,"FONT_GFX=\"%s\"\n",FontGfxName);
		UPDATE_DATA
		sprintf(VarString,"FONT_CUT=\"%s\"\n",FontCutName);
		UPDATE_DATA

		//	Key prefs
		sprintf(VarString, "KEY_PREFS=%d,%d,%d,%d,%d,%d,%d,%d\n",
			(int)KeyPrefs[0],
			(int)KeyPrefs[1],
			(int)KeyPrefs[2],
			(int)KeyPrefs[3],
			(int)KeyPrefs[4],
			(int)KeyPrefs[5],
			(int)KeyPrefs[6],
			(int)KeyPrefs[7]
		);
		UPDATE_DATA
		WriteStringArray("JOYPAD_NAMES", VarString, KeyStrings, ELEMENTS(KeyStrings)); 
		UPDATE_DATA
		WriteStringArray("ERROR_MESSAGES", VarString, ErrorString, ELEMENTS(ErrorString)); 
		UPDATE_DATA
		WriteStringArray("FILE_REQUESTOR", VarString, FileStrings, ELEMENTS(FileStrings)); 
		UPDATE_DATA
		WriteStringArray("PALETTE_STRINGS", VarString, PaletteStrings, ELEMENTS(PaletteStrings));
		UPDATE_DATA
		WriteStringArray("SIDE_MENU", VarString, MenuStrings, ELEMENTS(MenuStrings)); 
		UPDATE_DATA
		WriteStringArray("TITLE_STRINGS", VarString, TitleStrings, ELEMENTS(TitleStrings));
		UPDATE_DATA
		WriteStringArray("TIMEOUT_STRINGS", VarString, TimeOutStrings, ELEMENTS(TimeOutStrings));
		UPDATE_DATA


		left=ELEMENTS(KeyNames);
		KeyPtr=KeyNames;
		row=0;
		do{
			number=left<10?left:10;
			for(j=0; j<number; j++){
				StringArray[j]=KeyPtr->Name;
				KeyPtr++;
				left--;
			}
			sprintf(VarName,"KEYNAMES_%d",row);
			WriteStringArray(VarName, VarString, StringArray, number);
			UPDATE_DATA
			row++;
		}while(left);

		if(WriteData){
			GXSaveMemoryToFile(data, LengthData, "prefs");
			GXFreeMem(data);
		}else{
			LengthData++;
			data=(char *)GXGetMem(LengthData, MEMF_ABORT);
			out=data;
		}
	}
}
