#include "hypermenu.h"
#include <string>
#include <sstream>
#include <iostream>

#include "menusys.h"

using namespace hm;
using namespace std;

static ConfigFile *configFile;
static Menu *menu;
static struct menureturn mr;
static FileMenu* loadrommenu;

class myActionHandler : public ActionHandler
{

	int action(Menu *source);
	void change(Menu *source);
	void enter(Menu *source);

};

int myActionHandler::action(Menu *source)
{
	if (source->getName() == "saveoptions")
	{
		configFile->clear();
		menu->addValues(configFile);
		configFile->save("ssnes.cfg");
		return 0;
	}

	strncpy (mr.title, source->getTitle().c_str(), 255);
	strncpy (mr.name, source->getName().c_str(), 255);
	strncpy (mr.value, source->getValue().c_str(), 255);
	// return false to carry on with menu, 1 to exit menu
	return 1;
}

void myActionHandler::change(Menu *source)
{
	printf("Caught change event: [%s] = (%s,%s) \n",source->getTitle().c_str(),source->getName().c_str(),source->getValue().c_str());
	if (source->getName() == "absromdir")
	{
		if (source->getValue() == "true")
			loadrommenu->setValue("/mnt/sd/roms/snes");
		else
			loadrommenu->setValue("roms");
	}
}

void myActionHandler::enter(Menu *source)
{

	printf("Caught enter event: [%s] = (%s,%s) \n",source->getTitle().c_str(),source->getName().c_str(),source->getValue().c_str());

}

void parseconfig (void)
{
	string temp;
	
	if (configFile->getValueByName("wantscale") == "true")
		mr.wantscale = 1;
	else
		mr.wantscale = 0;

	if (configFile->getValueByName("fpsdisplay") == "true")
		mr.wantfps = 1;
	else
		mr.wantfps = 0;

	if (configFile->getValueByName("absromdir") == "true")
		mr.romdir = 1;
	else
		mr.romdir = 0;

	if (configFile->getValueByName("snesjoytype") == "true")
		mr.joytype = 1;
	else
		mr.joytype = 0;
		
	if (configFile->getValueByName("apuenable") == "true")
		mr.apuenable = 1;
	else
		mr.apuenable = 0;
		
	if (configFile->getValueByName("apumute") == "true")
		mr.apumute = 1;
	else
		mr.apumute = 0;

	if (configFile->getValueByName("vsync") == "false")
		mr.vsyncenable = 0;
	else
		mr.vsyncenable = 1;
		
	if (configFile->getValueByName("fpslimit") == "false")
		mr.fpslimit = 0;
	else
		mr.fpslimit = 1;

	if (configFile->getValueByName("fastsprites") == "true")
		mr.fastsprites = 0;
	else
		mr.fastsprites = 0;
		
	if (configFile->getValueByName("squidgetranshack") == "true")
		mr.squidgetranshack = 1;
	else
		mr.squidgetranshack = 0;
		  	
	temp = configFile->getValueByName("lowbattval");
	if (temp == "2.7V") mr.lowbattval = 27;
	else if (temp == "2.6V") mr.lowbattval = 26;
	else if (temp == "2.5V") mr.lowbattval = 25;
	else if (temp == "2.4V") mr.lowbattval = 24;
	else if (temp == "2.3V") mr.lowbattval = 23;
	else if (temp == "2.2V") mr.lowbattval = 22;
	else if (temp == "2.1V") mr.lowbattval = 21;
	else if (temp == "2.0V") mr.lowbattval = 20;
	else mr.lowbattval = 0;

	mr.fskip = configFile->getIntValueByName("fskip");
}

void applyDefaultConfig (ConfigFile *cf)
{
	cf->clear();
	cf->addVariable ("loadrom", "roms");
	cf->addVariable ("wantscale", "false");
	cf->addVariable ("fpsdisplay", "false");
	cf->addVariable ("vsync", "true");
	cf->addVariable ("absromdir","false");
	cf->addVariable ("snesjoytype","false");
	cf->addVariable ("apuenable","false");
	cf->addVariable ("apumute","true");
	cf->addVariable ("fskip","1");
	cf->addVariable ("fpslimit","false");
	cf->addVariable ("fastsprites","false");
	cf->addVariable ("squidgetranshack", "false");
	cf->addVariable ("lowbattval", "2.4V");
}

struct menureturn *domenu(int sel)
{
	Surface *surface;

	mr.title[0] = 0;
	mr.name[0] = 0;
	mr.value[0] = 0;

	// initialize system
	msystem.initSystem();

	// try initializing a drawing surface
	try
	{
		surface = new Surface(320,240);
		Image* background = new Image("skin/background.png");
		surface->drawImage(background,0,0);
		surface->flip();
	} catch (string message) {
		// probably an image that couldn't be found
		cout << "error initializing surface: " << message << endl;
		exit(1);
	}

	// build the menu tree
	try
	{

		// create a new instance ouf our custom action handler
		myActionHandler *actionHandler = new myActionHandler();

		ConfigFile *skinConfig = new ConfigFile();
		skinConfig->load("skin/skin.cfg");

		int wxp, wyp, wxs, wys, mt;
		mt = skinConfig->getIntValueByName("menutype");

		// initialize our menu tree root
		if (mt == 0)
		{
			wxs = 260;
			wys = 220;
			wxp = -1;
			wyp = -1;
			menu = new Menu("SquidgeSNES",surface);
		}
		else
		{
			wxp = skinConfig->getIntValueByName("menuxpos");
			wyp = skinConfig->getIntValueByName("menuypos");
			wxs = skinConfig->getIntValueByName("menuxsize");
			wys = skinConfig->getIntValueByName("menuysize");

			menu = new SquidgeMenu ("SquidgeSNES", surface);
		}

		menu->setWindowSize(wxs,wys); // 260x160 for new menu
		menu->setWindowPosition(wxp, wyp); //(320-260)/2,44

		delete(skinConfig);

		// return to game
		ActionMenu *rtgaction = new ActionMenu("Return to game");
		rtgaction->setActionHandler(actionHandler);
		rtgaction->setConfirm(false,"");
		rtgaction->setName("returntogame");
		rtgaction->setIcon(new Image("skin/icons/continue.png"));
		rtgaction->setSecondaryIcon(new Image("skin/icons/loadrom.png"));
		menu->appendChild(rtgaction);

		// load rom
		loadrommenu = new FileMenu("Load ROM", surface);
		loadrommenu->setIcon(new Image("skin/icons/loadrom.png"));
		loadrommenu->setActionHandler(actionHandler);
		loadrommenu->setName("loadrom");
		loadrommenu->setValue ("roms");
		loadrommenu->addFileExtension(".smc", new Image("skin/file.png"));
		menu->appendChild(loadrommenu);

		// Load state
		ActionMenu *loadstate = new ActionMenu("Load state");
		loadstate->setActionHandler(actionHandler);
		loadstate->setName("loadstate");
		loadstate->setIcon(new Image("skin/icons/loadstate.png"));
		menu->appendChild(loadstate);

		// Save state
		ActionMenu *savestate = new ActionMenu("Save state");
		savestate->setActionHandler(actionHandler);
		savestate->setName("savestate");
		savestate->setIcon(new Image("skin/icons/savestate.png"));
		menu->appendChild(savestate);

		// Reset snes
		ActionMenu *rsaction = new ActionMenu("Reset SNES");
		rsaction->setActionHandler(actionHandler);
		rsaction->setConfirm(true,"ROM will be restarted");
		rsaction->setName("resetaction");
		rsaction->setIcon(new Image("skin/icons/resetsnes.png"));
		menu->appendChild(rsaction);

		//
		// Create the configuration menu
		//
		
		Menu* configmenu = new Menu("Settings");
		configmenu->setIcon(new Image("skin/icons/settings.png"));
		configmenu->setWindowSize(200,200);
		menu->appendChild(configmenu);

		//
		// Configuration menu: Graphics
		//

		CheckboxMenu *wantscale = new CheckboxMenu("Use full screen scaling");
		wantscale->setName("wantscale");
		configmenu->appendChild(wantscale);

		CheckboxMenu *fpsdisplay = new CheckboxMenu("Show FPS");
		fpsdisplay->setName("fpsdisplay");
		configmenu->appendChild(fpsdisplay);

		CheckboxMenu *vsync = new CheckboxMenu ("Enable vsync");
		vsync->setName("vsync");
		configmenu->appendChild(vsync);

		CheckboxMenu *fpslimit = new CheckboxMenu ("FPS limiter");
		fpslimit->setName("fpslimit");
		configmenu->appendChild(fpslimit);

		CheckboxMenu *transhack = new CheckboxMenu ("Transhack-A V0.1");
		transhack->setName("squidgetranshack");
		configmenu->appendChild(transhack);

		SelectMenu *fskip = new SelectMenu("Frameskip");
		fskip->setName("fskip");
		for (int i = 0; i < 10; i ++)
		{
			char str[256];

			sprintf (str, "%d", i);
			fskip->addOption(str);
		}
		configmenu->appendChild(fskip);
		
		CheckboxMenu *fastsprites = new CheckboxMenu ("Fast sprites");
		fastsprites->setName("fastsprites");
		configmenu->appendChild(fastsprites);

		//
		// Configuration menu: Audio
		//

		SeparatorMenu *sepmenu = new SeparatorMenu("");
		configmenu->appendChild(sepmenu);

		CheckboxMenu *apuenable = new CheckboxMenu("Audio processor enable");
		apuenable->setName("apuenable");
		configmenu->appendChild(apuenable);

		CheckboxMenu *apumute = new CheckboxMenu("Audio processor mute");
		apumute->setName("apumute");
		configmenu->appendChild(apumute);

		//
		// Configuration menu: Miscellaneous
		//

		configmenu->appendChild(sepmenu);

		CheckboxMenu *absromdir = new CheckboxMenu("Use absolute rom dir");
		absromdir->setName("absromdir");
		absromdir->setActionHandler(actionHandler);
		configmenu->appendChild(absromdir);

		CheckboxMenu *snesjoytype = new CheckboxMenu("SNES action buttons");
		snesjoytype->setName("snesjoytype");
		configmenu->appendChild(snesjoytype);
		
		SelectMenu *lowbattval = new SelectMenu ("Battery warning");
		lowbattval->setName("lowbattval");
		lowbattval->addOption("disabled");
		lowbattval->addOption("2.7V");
		lowbattval->addOption("2.6V");
		lowbattval->addOption("2.5V");
		lowbattval->addOption("2.4V");
		lowbattval->addOption("2.3V");
		lowbattval->addOption("2.2V");
		lowbattval->addOption("2.1V");
		lowbattval->addOption("2.0V");
		configmenu->appendChild(lowbattval);

		configmenu->appendChild(sepmenu);

		// Save options //
		ActionMenu *saveopts = new ActionMenu("Save options");
		saveopts->setActionHandler(actionHandler);
		saveopts->setConfirm(true, "Save current config?");
		saveopts->setName("saveoptions");
		configmenu->appendChild(saveopts);

		// end of config menu

		ActionMenu *exitaction = new ActionMenu("Exit");
		exitaction->setIcon(new Image("skin/icons/exit.png"));
		exitaction->setActionHandler(actionHandler);
		exitaction->setConfirm(true,"");
		exitaction->setName("exitaction");
		menu->appendChild(exitaction);

	} catch (string message)
	{
		// probably an image that couldn't be found
		cout << "error building menu tree: " << message << endl;
		exit(2);
	}

	configFile = new ConfigFile();
	applyDefaultConfig(configFile);
	configFile->load("ssnes.cfg");
	menu->getValues(configFile);
	menu->setSelected (sel);
	menu->enter();
	parseconfig();

	// de-init system
	msystem.deInitSystem();

	//done

	delete configFile;

	return &mr;
}

struct menureturn *skipmenu(void)
{
	msystem.initSystem();
	configFile = new ConfigFile();
	configFile->load("ssnes.cfg");
	parseconfig();
	msystem.deInitSystem();
	delete configFile;
	return &mr;
}


