/*
* This code is released under the GNU General Public License.  See COPYING for 
* details.  Copyright 2003 John Spray: spray_john@users.sourceforge.net
*/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <physfs.h>
#include <SDL.h>
using namespace std;

#include "Config.h"

#include "Visual.h" //for the benefit of ConfigMenu(Game*,Visual*)
#include "Game.h"
#include "Menu.h"
#include "SoundCore.h"

Config::Config()
{
	screenx=640;
	screeny=480;
	bpp=32;
	fullscreen=0;
	volume=1.0f;
	verbose=0;
	actslow=0;
	skipmenu=0;
	keys.turnleft=SDLK_q;
	keys.turnright=SDLK_e;
	keys.strafeleft=SDLK_a;
	keys.straferight=SDLK_d;
	keys.forward=SDLK_w;
	keys.back=SDLK_s;
	keys.firemissile=SDLK_SPACE;
	keys.firecannon=SDLK_v;
	keys.camleft=SDLK_LEFT;
	keys.camright=SDLK_RIGHT;
	keys.togglegrab=SDLK_g;
	keys.fullscreen=SDLK_f;
	drawfps=0;
	texscale=1;
	mousespeed=0.5;
	twoplayer=0;
}

int Config::ParseArgs(int argc,char* argv[])
{
	float* argpointf=NULL;
	int* argpointd=NULL;
	int i;
	string arg;

	for(i=1;i<argc;i++){
		arg=argv[i];
		if(argpointf){
			sscanf(argv[i],"%f",argpointf);
			argpointf=NULL;
			continue;
		}
		else if(argpointd){
			sscanf(argv[i],"%d",argpointd);
			argpointd=NULL;
			continue;
		}
		else if(arg=="-fs" || arg=="--fullscreen")
			fullscreen=1;
		else if(arg=="-x" || arg=="--width")
			argpointd=&screenx;
		else if(arg=="-y" || arg=="--height")
			argpointd=&screeny;
		else if(arg=="-bpp")
			argpointd=&bpp;
		else if(arg=="-v" || arg=="--verbose")
			verbose=1;
		else if(arg=="-vv" || arg=="--reallyverbose")
			verbose=2;
		else if(arg=="--drawfps")
			drawfps=1;
		else if(arg=="-s" || arg=="--skipmenu")
			skipmenu=1;
		else if(arg=="-d" || arg=="--actslow")
			actslow=1;
		else if(arg=="-vol" || arg=="--volume")
			argpointf=&volume;
		else if(arg=="-h" || arg=="--help" || arg=="-?" ){
			Usage();
			return 1;
		}
		else{
			printf("Config::ParseArgs: Unrecognised option \"%s\".  -h for help.\n",argv[i]);
		}
	}

return 0;

}

void Config::Usage()
{
	printf(
	"\n"
	"Usage: excido [options]\n\n"
	"\t-x/--width [number] \t: set window's width\n"
	"\t-y/--height [number] \t: set window's height\n"
	"\t-bpp [number] \t\t: set color depth\n"
	"\t-vol/--volume [0.0-1.0] : set volume\n"
	"\t-fs/--fullscreen\t: be fullscreen\n"
	"\t-v/--verbose\t\t: be verbose\n"
	"\t-vv/--reallyverbose\t: be more verbose\n"
	"\t-s/--skipmenu\t\t: skip initial menu\n"
	"\t-d/--actslow\t\t: run at ~30fps\n"
	"\t--drawfps\t\t: show frames per second\n"
	"Warning: some options persist in excido.conf after being used\n"
	"as command-line options.  Including -fs, --drawfps, -x, -y, -bpp\n"
	"Excido is free software.  See COPYING for details.\n"
	"\n"
	);
}

void Config::Load(char* rcfile)
{
	PHYSFS_file* filehandle=NULL;
	char *wholefile;
	int filelength;

	string conffile;
	string lhs;
	string rhs;
	string curline;

	int* pointd=NULL;
	float* pointf=NULL;

	//open the file
	filehandle=PHYSFS_openRead(rcfile);

	if(!filehandle){
		printf("Config::Load: Can't open file %s\n",rcfile);
		printf("Config::Load: PHYSFS says: %s\n",PHYSFS_getLastError());
		return;
	}

	//how long is it (bytes)?
	filelength=PHYSFS_fileLength(filehandle);
	
	//allocate storage for whole file
	wholefile=(char*)malloc(filelength+1);

	//dump out of file, into char*
	filelength=PHYSFS_read(filehandle,wholefile,1,filelength);
	wholefile[filelength]='\0';

	//transfer that into a C++ string
	conffile=wholefile;

	//we're done with the C string
	free((void*)wholefile);

	//and we're done with the file
	if(!PHYSFS_close(filehandle))
		printf("Config::Load: PHYSFS_close failed with error %s\n",PHYSFS_getLastError());

	while(conffile.find("\n",0)!=string::npos){
		curline=conffile.substr(0,conffile.find("\n",0)); //grab up to the next newline
		conffile.erase(0,conffile.find("\n",0)+1); //scrub up to and including the newline
	
		if(curline.find("=",0)==string::npos || curline.size() == 0
		 || curline.substr(0,1)=="#") //lines without equals signs, empty lines, comment lines
			continue;

		lhs=curline.substr(0,curline.find("=",0)); // lhs is up to the equals
		curline.erase(0,curline.find("=",0)+1); // curline loses up to and including the equals
		rhs=curline;                           //rhs is what's left
	
		if(lhs=="screenx")
			pointd=&screenx;
		else if(lhs=="screeny")
			pointd=&screeny;
		else if(lhs=="bpp")
			pointd=&bpp;
		else if(lhs=="fullscreen")
			pointd=&fullscreen;
		else if(lhs=="drawfps")
			pointd=&drawfps;
		else if(lhs=="keys_turnleft")
			pointd=&keys.turnleft;
		else if(lhs=="keys_turnright")
			pointd=&keys.turnright;
		else if(lhs=="keys_strafeleft")
			pointd=&keys.strafeleft;
		else if(lhs=="keys_straferight")
			pointd=&keys.straferight;
		else if(lhs=="keys_forward")
			pointd=&keys.forward;
		else if(lhs=="keys_back")
			pointd=&keys.back;
		else if(lhs=="keys_camleft")
			pointd=&keys.camleft;
		else if(lhs=="keys_camright")
			pointd=&keys.camright;
		else if(lhs=="keys_firemissile")
			pointd=&keys.firemissile;
		else if(lhs=="keys_firecannon")
			pointd=&keys.firecannon;
		else if(lhs=="keys_fullscreen")
			pointd=&keys.fullscreen;
		else if(lhs=="keys_togglegrab")
			pointd=&keys.togglegrab;
		else if(lhs=="volume")
			pointf=&volume;
		else if(lhs=="mousespeed")
			pointf=&mousespeed;
		else
			cout << "Config::Load: unrecognised parameter: " << lhs << endl;

		if(pointd!=NULL){
			sscanf(rhs.c_str(),"%d",pointd);
			pointd=NULL;
		}
		else if(pointf!=NULL){
			sscanf(rhs.c_str(),"%f",pointf);
			pointf=NULL;
		}
	}

	return;
}

void Config::Dump(char* filename)
{
	PHYSFS_file* filehandle=NULL;
	char line[256];

	//open the file for writing
	filehandle=PHYSFS_openWrite(filename);

	if(!filehandle){
		printf("Config::Dump: Can't open file %s\n",filename);
		printf("Config::Dump: PHYSFS says: %s\n",PHYSFS_getLastError());
		return;
	}
	
	sprintf(line,"#This file is overwritten each time Excido runs.\n");
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"screenx=%d\n",screenx);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"screeny=%d\n",screeny);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"bpp=%d\n",bpp);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"fullscreen=%d\n",fullscreen);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"drawfps=%d\n",drawfps);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"volume=%f\n",volume);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"mousespeed=%f\n",mousespeed);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_turnleft=%d\n",keys.turnleft);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_turnright=%d\n",keys.turnright);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_strafeleft=%d\n",keys.strafeleft);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_straferight=%d\n",keys.straferight);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_forward=%d\n",keys.forward);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_back=%d\n",keys.back);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_camleft=%d\n",keys.camleft);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_camright=%d\n",keys.camright);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_firemissile=%d\n",keys.firemissile);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_firecannon=%d\n",keys.firecannon);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_fullscreen=%d\n",keys.fullscreen);
	PHYSFS_write(filehandle,line,1,strlen(line));
	sprintf(line,"keys_togglegrab=%d\n",keys.togglegrab);
	PHYSFS_write(filehandle,line,1,strlen(line));

	//and we're done with the file
	if(!PHYSFS_close(filehandle))
		printf("ScoreBoard::Load: PHYSFS_close failed with error %s\n",PHYSFS_getLastError());

	
}

void Config::ConfigMenu(Visual* menuvisual,SoundCore* menusound)
{
	int inmenu=1;
	menufunc retval;
	while(inmenu){
		Menu* menu;
		char* labels[]={"Volume: ","Mouse Sensitivity: ","Show FPS: ","Fullscreen: ","Video Resolution","Back",NULL};
		menufunc functions[]={MENU_FLOATONE,MENU_FLOATONE,MENU_BOOL,MENU_BOOL,MENU_SUB1,MENU_CONTINUE};
		void* targets[]={&volume,&mousespeed,&drawfps,&fullscreen,NULL,NULL};

		menu=new Menu(labels,functions,targets,menuvisual);
		menu->solidbackground=1;
		retval=menu->Happen();
		delete menu;

		if(retval==MENU_CONTINUE)
			inmenu=0;
		if(retval==MENU_SUB1)
			ConfigMenuRes(menuvisual);


		if(fullscreen && !(SDL_FULLSCREEN & menuvisual->game->screen->flags))
			SDL_WM_ToggleFullScreen(menuvisual->game->screen);
		if(!fullscreen && (SDL_FULLSCREEN & menuvisual->game->screen->flags))
			SDL_WM_ToggleFullScreen(menuvisual->game->screen);
		if(volume!=menusound->GetVolume()){
			menusound->SetVolume(volume);
			menusound->Update();
		}
	}
}

void Config::ConfigMenuRes(Visual* menuvisual)
{
	menufunc retval;

	Menu* menu;
	char* labels[]={"640x480","800x600","960x720","1024x768","1280x960",NULL};
	menufunc functions[]={MENU_SUB1,MENU_SUB2,MENU_SUB3,MENU_SUB4,MENU_SUB5};
	void* targets[]={NULL,NULL,NULL,NULL,NULL};

	menu=new Menu(labels,functions,targets,menuvisual);

	if(screenx==640)
		menu->Select(0);
	else if(screenx==800)
		menu->Select(1);
	else if(screenx==960)
		menu->Select(2);
	else if(screenx==1024)
		menu->Select(3);
	else if(screenx==1280)
		menu->Select(4);

	menu->solidbackground=1;
	retval=menu->Happen();
	delete menu;

	if(retval==MENU_SUB1){
		screenx=640;
		screeny=480;
	}
	else if(retval==MENU_SUB2){
		screenx=800;
		screeny=600;
	}
	else if(retval==MENU_SUB3){
		screenx=960;
		screeny=720;
	}
	else if(retval==MENU_SUB4){
		screenx=1024;
		screeny=768;
	}
	else if(retval==MENU_SUB5){
		screenx=1280;
		screeny=960;
	}
}
