// ==============================================================
//	This file is part of Glest (www.glest.org)
//
//	Copyright (C) 2001-2005 Martio Figueroa
//
//	You can redistribute this code and/or modify it under
//	the terms of the GNU General Public License as published
//	by the Free Software Foundation; either version 2 of the
//	License, or (at your option) any later version
// ==============================================================

#include "menu_state_scenario.h"

#include "renderer.h"
#include "menu_state_new_game.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "menu_state_options.h"
#include "network_manager.h"
#include "config.h"
#include "auto_test.h"
#include "game.h"

#include "leak_dumper.h"

namespace Glest{ namespace Game{

using namespace	Shared::Xml;

// =====================================================
// 	class MenuStateScenario
// =====================================================

MenuStateScenario::MenuStateScenario(Program *program, MainMenu *mainMenu, const vector<string> &dirList, string autoloadScenarioName):
    MenuState(program, mainMenu, "scenario")
{
	containerName = "Scenario";
	enableScenarioTexturePreview = Config::getInstance().getBool("EnableScenarioTexturePreview","true");
	scenarioLogoTexture=NULL;
	previewLoadDelayTimer=time(NULL);
	needToLoadTextures=true;

	Lang &lang= Lang::getInstance();
	NetworkManager &networkManager= NetworkManager::getInstance();

	mainMessageBox.registerGraphicComponent(containerName,"mainMessageBox");
	mainMessageBox.init(lang.get("Ok"));
	mainMessageBox.setEnabled(false);
	mainMessageBoxState=0;

	this->autoloadScenarioName = autoloadScenarioName;
    vector<string> results;

	this->dirList = dirList;

	int startY=100;
	int startX=350;

	labelInfo.registerGraphicComponent(containerName,"labelInfo");
    labelInfo.init(startX, startY+130);
	labelInfo.setFont(CoreData::getInstance().getMenuFontNormal());
	labelInfo.setFont3D(CoreData::getInstance().getMenuFontNormal3D());

	buttonReturn.registerGraphicComponent(containerName,"buttonReturn");
    buttonReturn.init(startX, startY, 125);

    buttonPlayNow.registerGraphicComponent(containerName,"buttonPlayNow");
	buttonPlayNow.init(startX+175, startY, 125);

	listBoxScenario.registerGraphicComponent(containerName,"listBoxScenario");
    listBoxScenario.init(startX, startY+160, 190);

    labelScenario.registerGraphicComponent(containerName,"labelScenario");
	labelScenario.init(startX, startY+190);

	buttonReturn.setText(lang.get("Return"));
	buttonPlayNow.setText(lang.get("PlayNow"));

    labelScenario.setText(lang.get("Scenario"));

    //scenario listbox
	findDirs(dirList, results);
    scenarioFiles = results;
    //printf("scenarioFiles[0] [%s]\n",scenarioFiles[0].c_str());

	if(results.empty() == true) {
        throw runtime_error("There are no scenarios found to load");
	}
	for(int i= 0; i<results.size(); ++i){
		results[i] = formatString(results[i]);
	}
    listBoxScenario.setItems(results);

    try {
        loadScenarioInfo(Scenario::getScenarioPath(dirList, scenarioFiles[listBoxScenario.getSelectedItemIndex()]), &scenarioInfo );
        labelInfo.setText(scenarioInfo.desc);

        GraphicComponent::applyAllCustomProperties(containerName);

        networkManager.init(nrServer);
    }
	catch(const std::exception &ex) {
		char szBuf[4096]="";
		sprintf(szBuf,"In [%s::%s %d] Error detected:\n%s\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s",szBuf);

        mainMessageBoxState=1;
        showMessageBox( "Error: " + string(ex.what()), "Error detected", false);
	}
}

void MenuStateScenario::reloadUI() {
	Lang &lang= Lang::getInstance();

	console.resetFonts();
	mainMessageBox.init(lang.get("Ok"));
	labelInfo.setFont(CoreData::getInstance().getMenuFontNormal());
	labelInfo.setFont3D(CoreData::getInstance().getMenuFontNormal3D());

	buttonReturn.setText(lang.get("Return"));
	buttonPlayNow.setText(lang.get("PlayNow"));

    labelScenario.setText(lang.get("Scenario"));

	GraphicComponent::reloadFontsForRegisterGraphicComponents(containerName);
}

MenuStateScenario::~MenuStateScenario() {
	cleanupPreviewTexture();
}

void MenuStateScenario::cleanupPreviewTexture() {
	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] scenarioLogoTexture [%p]\n",__FILE__,__FUNCTION__,__LINE__,scenarioLogoTexture);

	if(scenarioLogoTexture != NULL) {
		Renderer::getInstance().endTexture(rsGlobal, scenarioLogoTexture, false);
	}
	scenarioLogoTexture = NULL;
}

void MenuStateScenario::mouseClick(int x, int y, MouseButton mouseButton) {
	CoreData &coreData= CoreData::getInstance();
	SoundRenderer &soundRenderer= SoundRenderer::getInstance();

	if(mainMessageBox.getEnabled()){
		int button= 1;
		if(mainMessageBox.mouseClick(x, y, button))
		{
			soundRenderer.playFx(coreData.getClickSoundA());
			if(button==1) {
				mainMessageBox.setEnabled(false);
			}
		}
	}
	else if(buttonReturn.mouseClick(x,y)){
		soundRenderer.playFx(coreData.getClickSoundA());
		mainMenu->setState(new MenuStateNewGame(program, mainMenu));
    }
	else if(buttonPlayNow.mouseClick(x,y)){
		soundRenderer.playFx(coreData.getClickSoundC());
		launchGame();
		return;
	}
    else if(listBoxScenario.mouseClick(x, y)){
        try {
            loadScenarioInfo(Scenario::getScenarioPath(dirList, scenarioFiles[listBoxScenario.getSelectedItemIndex()]), &scenarioInfo);
            labelInfo.setText(scenarioInfo.desc);
        }
        catch(const std::exception &ex) {
            char szBuf[4096]="";
            sprintf(szBuf,"In [%s::%s %d] Error detected:\n%s\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
            SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
            if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s",szBuf);

            mainMessageBoxState=1;
            showMessageBox( "Error: " + string(ex.what()), "Error detected", false);
        }
	}
}

void MenuStateScenario::mouseMove(int x, int y, const MouseState *ms){

	if (mainMessageBox.getEnabled()) {
		mainMessageBox.mouseMove(x, y);
	}

	listBoxScenario.mouseMove(x, y);

	buttonReturn.mouseMove(x, y);
	buttonPlayNow.mouseMove(x, y);
}

void MenuStateScenario::render(){

	Renderer &renderer= Renderer::getInstance();

	if(scenarioLogoTexture != NULL) {
		renderer.renderTextureQuad(300,350,400,300,scenarioLogoTexture,1.0f);
		//renderer.renderBackground(scenarioLogoTexture);
	}

	if(mainMessageBox.getEnabled()) {
		renderer.renderMessageBox(&mainMessageBox);
	}
	else {
		renderer.renderLabel(&labelInfo);
		renderer.renderLabel(&labelScenario);
		renderer.renderListBox(&listBoxScenario);

		renderer.renderButton(&buttonReturn);
		renderer.renderButton(&buttonPlayNow);
	}
	renderer.renderConsole(&console,false,true);
	if(program != NULL) program->renderProgramMsgBox();
}

void MenuStateScenario::update() {
	if(Config::getInstance().getBool("AutoTest")) {
		AutoTest::getInstance().updateScenario(this);
	}
	if(this->autoloadScenarioName != "") {
		listBoxScenario.setSelectedItem(formatString(this->autoloadScenarioName),false);

		if(listBoxScenario.getSelectedItem() != formatString(this->autoloadScenarioName)) {
			mainMessageBoxState=1;
			showMessageBox( "Could not find scenario name: " + formatString(this->autoloadScenarioName), "Scenario Missing", false);
			this->autoloadScenarioName = "";
		}
		else {
			loadScenarioInfo(Scenario::getScenarioPath(dirList, scenarioFiles[listBoxScenario.getSelectedItemIndex()]), &scenarioInfo);
			labelInfo.setText(scenarioInfo.desc);

			SoundRenderer &soundRenderer= SoundRenderer::getInstance();
			CoreData &coreData= CoreData::getInstance();
			soundRenderer.playFx(coreData.getClickSoundC());
			launchGame();
			return;
		}
	}

	if(needToLoadTextures) {
		// this delay is done to make it possible to switch faster
		if(difftime(time(NULL), previewLoadDelayTimer) >= 2){
			loadScenarioPreviewTexture();
			needToLoadTextures= false;
		}
	}
	console.update();
}

void MenuStateScenario::launchGame() {
	GameSettings gameSettings;
    loadGameSettings(&scenarioInfo, &gameSettings);
	program->setState(new Game(program, &gameSettings, false));
}

void MenuStateScenario::setScenario(int i) {
	listBoxScenario.setSelectedItemIndex(i);
	loadScenarioInfo(Scenario::getScenarioPath(dirList, scenarioFiles[listBoxScenario.getSelectedItemIndex()]), &scenarioInfo);
}

void MenuStateScenario::loadScenarioInfo(string file, ScenarioInfo *scenarioInfo) {
//    Lang &lang= Lang::getInstance();
//
//    XmlTree xmlTree;
//	xmlTree.load(file,Properties::getTagReplacementValues());
//
//    const XmlNode *scenarioNode= xmlTree.getRootNode();
//	const XmlNode *difficultyNode= scenarioNode->getChild("difficulty");
//	scenarioInfo->difficulty = difficultyNode->getAttribute("value")->getIntValue();
//	if( scenarioInfo->difficulty < dVeryEasy || scenarioInfo->difficulty > dInsane ) {
//		char szBuf[4096]="";
//		sprintf(szBuf,"Invalid difficulty value specified in scenario: %d must be between %d and %d",scenarioInfo->difficulty,dVeryEasy,dInsane);
//		throw std::runtime_error(szBuf);
//	}
//
//	const XmlNode *playersNode= scenarioNode->getChild("players");
//
//    for(int i= 0; i < GameConstants::maxPlayers; ++i) {
//    	XmlNode* playerNode=NULL;
//    	string factionTypeName="";
//    	ControlType factionControl;
//
//    	if(playersNode->hasChildAtIndex("player",i)){
//        	playerNode = playersNode->getChild("player", i);
//        	factionControl = strToControllerType( playerNode->getAttribute("control")->getValue() );
//
//        	if(playerNode->getAttribute("resource_multiplier",false)!=NULL) {
//        		// if a multiplier exists use it
//				scenarioInfo->resourceMultipliers[i]=playerNode->getAttribute("resource_multiplier")->getFloatValue();
//			}
//			else {
//				// if no multiplier exists use defaults
//				scenarioInfo->resourceMultipliers[i]=GameConstants::normalMultiplier;
//				if(factionControl==ctCpuEasy) {
//					scenarioInfo->resourceMultipliers[i]=GameConstants::easyMultiplier;
//				}
//				if(factionControl==ctCpuUltra) {
//					scenarioInfo->resourceMultipliers[i]=GameConstants::ultraMultiplier;
//				}
//				else if(factionControl==ctCpuMega) {
//					scenarioInfo->resourceMultipliers[i]=GameConstants::megaMultiplier;
//				}
//			}
//
//    	}
//        else {
//        	factionControl=ctClosed;
//        }
//
//        scenarioInfo->factionControls[i] = factionControl;
//
//        if(factionControl != ctClosed){
//            int teamIndex = playerNode->getAttribute("team")->getIntValue();
//
//            if( teamIndex < 1 || teamIndex > GameConstants::maxPlayers ) {
//        		char szBuf[4096]="";
//        		sprintf(szBuf,"Invalid team value specified in scenario: %d must be between %d and %d",teamIndex,1,GameConstants::maxPlayers);
//        		throw std::runtime_error(szBuf);
//            }
//
//            scenarioInfo->teams[i]= playerNode->getAttribute("team")->getIntValue();
//            scenarioInfo->factionTypeNames[i]= playerNode->getAttribute("faction")->getValue();
//        }
//
//        scenarioInfo->mapName = scenarioNode->getChild("map")->getAttribute("value")->getValue();
//        scenarioInfo->tilesetName = scenarioNode->getChild("tileset")->getAttribute("value")->getValue();
//        scenarioInfo->techTreeName = scenarioNode->getChild("tech-tree")->getAttribute("value")->getValue();
//        scenarioInfo->defaultUnits = scenarioNode->getChild("default-units")->getAttribute("value")->getBoolValue();
//        scenarioInfo->defaultResources = scenarioNode->getChild("default-resources")->getAttribute("value")->getBoolValue();
//        scenarioInfo->defaultVictoryConditions = scenarioNode->getChild("default-victory-conditions")->getAttribute("value")->getBoolValue();
//    }
//
//	//add player info
//    scenarioInfo->desc= lang.get("Player") + ": ";
//	for(int i=0; i<GameConstants::maxPlayers; ++i) {
//		if(scenarioInfo->factionControls[i] == ctHuman) {
//			scenarioInfo->desc+= formatString(scenarioInfo->factionTypeNames[i]);
//			break;
//		}
//	}
//
//	//add misc info
//	string difficultyString = "Difficulty" + intToStr(scenarioInfo->difficulty);
//
//	scenarioInfo->desc+= "\n";
//    scenarioInfo->desc+= lang.get("Difficulty") + ": " + lang.get(difficultyString) +"\n";
//    scenarioInfo->desc+= lang.get("Map") + ": " + formatString(scenarioInfo->mapName) + "\n";
//    scenarioInfo->desc+= lang.get("Tileset") + ": " + formatString(scenarioInfo->tilesetName) + "\n";
//	scenarioInfo->desc+= lang.get("TechTree") + ": " + formatString(scenarioInfo->techTreeName) + "\n";
//
//	if(scenarioNode->hasChild("fog-of-war") == true) {
//		if(scenarioNode->getChild("fog-of-war")->getAttribute("value")->getValue() == "explored") {
//			scenarioInfo->fogOfWar 				= true;
//			scenarioInfo->fogOfWar_exploredFlag = true;
//		}
//		else {
//			scenarioInfo->fogOfWar = scenarioNode->getChild("fog-of-war")->getAttribute("value")->getBoolValue();
//			scenarioInfo->fogOfWar_exploredFlag = false;
//		}
//		//printf("\nFOG OF WAR is set to [%d]\n",scenarioInfo->fogOfWar);
//	}
//	else {
//		scenarioInfo->fogOfWar 				= true;
//		scenarioInfo->fogOfWar_exploredFlag = false;
//	}
	//scenarioLogoTexture = NULL;

	Scenario::loadScenarioInfo(file, scenarioInfo);

	cleanupPreviewTexture();
	previewLoadDelayTimer=time(NULL);
	needToLoadTextures=true;
}

void MenuStateScenario::loadScenarioPreviewTexture(){
	if(enableScenarioTexturePreview == true) {
		GameSettings gameSettings;
		loadGameSettings(&scenarioInfo, &gameSettings);

		string scenarioLogo 	= "";
		bool loadingImageUsed 	= false;

		Game::extractScenarioLogoFile(&gameSettings, scenarioLogo, loadingImageUsed);

		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] scenarioLogo [%s]\n",__FILE__,__FUNCTION__,__LINE__,scenarioLogo.c_str());

		if(scenarioLogo != "") {
			cleanupPreviewTexture();
			scenarioLogoTexture = Renderer::findFactionLogoTexture(scenarioLogo);
		}
		else {
			cleanupPreviewTexture();
			scenarioLogoTexture = NULL;
		}
	}
}

void MenuStateScenario::loadGameSettings(const ScenarioInfo *scenarioInfo, GameSettings *gameSettings){
	if(listBoxScenario.getSelectedItemIndex() < 0) {
		char szBuf[1024]="";
		sprintf(szBuf,"listBoxScenario.getSelectedItemIndex() < 0, = %d",listBoxScenario.getSelectedItemIndex());
		throw runtime_error(szBuf);
	}
	else if(listBoxScenario.getSelectedItemIndex() >= scenarioFiles.size()) {
		char szBuf[1024]="";
		sprintf(szBuf,"listBoxScenario.getSelectedItemIndex() >= scenarioFiles.size(), = [%d][%d]",listBoxScenario.getSelectedItemIndex(),(int)scenarioFiles.size());
		throw runtime_error(szBuf);
	}

	Scenario::loadGameSettings(dirList,scenarioInfo, gameSettings, formatString(scenarioFiles[listBoxScenario.getSelectedItemIndex()]));

//	int factionCount= 0;
//
//	//printf("\n\n\n$$$$$$$$$$$$$ [%s]\n\n\n",scenarioFiles[listBoxScenario.getSelectedItemIndex()].c_str());
//
//	gameSettings->setDescription(formatString(scenarioFiles[listBoxScenario.getSelectedItemIndex()]));
//	gameSettings->setMap(scenarioInfo->mapName);
//    gameSettings->setTileset(scenarioInfo->tilesetName);
//    gameSettings->setTech(scenarioInfo->techTreeName);
//	gameSettings->setScenario(scenarioFiles[listBoxScenario.getSelectedItemIndex()]);
//	gameSettings->setScenarioDir(Scenario::getScenarioPath(dirList, scenarioFiles[listBoxScenario.getSelectedItemIndex()]));
//	gameSettings->setDefaultUnits(scenarioInfo->defaultUnits);
//	gameSettings->setDefaultResources(scenarioInfo->defaultResources);
//	gameSettings->setDefaultVictoryConditions(scenarioInfo->defaultVictoryConditions);
//
//    for(int i=0; i<GameConstants::maxPlayers; ++i){
//        ControlType ct= static_cast<ControlType>(scenarioInfo->factionControls[i]);
//		if(ct!=ctClosed){
//			if(ct==ctHuman){
//				gameSettings->setThisFactionIndex(factionCount);
//			}
//			gameSettings->setFactionControl(factionCount, ct);
//			gameSettings->setResourceMultiplierIndex(factionCount, (scenarioInfo->resourceMultipliers[i]-0.5f)/0.1f);
//            gameSettings->setTeam(factionCount, scenarioInfo->teams[i]-1);
//			gameSettings->setStartLocationIndex(factionCount, i);
//            gameSettings->setFactionTypeName(factionCount, scenarioInfo->factionTypeNames[i]);
//			factionCount++;
//		}
//    }
//
//	gameSettings->setFactionCount(factionCount);
//	gameSettings->setFogOfWar(scenarioInfo->fogOfWar);
//	uint32 valueFlags1 = gameSettings->getFlagTypes1();
//	if(scenarioInfo->fogOfWar == false || scenarioInfo->fogOfWar_exploredFlag) {
//        valueFlags1 |= ft1_show_map_resources;
//        gameSettings->setFlagTypes1(valueFlags1);
//	}
//	else {
//        valueFlags1 &= ~ft1_show_map_resources;
//        gameSettings->setFlagTypes1(valueFlags1);
//	}
//
//	gameSettings->setPathFinderType(static_cast<PathFinderType>(Config::getInstance().getInt("ScenarioPathFinderType",intToStr(pfBasic).c_str())));
}

void MenuStateScenario::showMessageBox(const string &text, const string &header, bool toggle){
	if(!toggle){
		mainMessageBox.setEnabled(false);
	}

	if(!mainMessageBox.getEnabled()){
		mainMessageBox.setText(text);
		mainMessageBox.setHeader(header);
		mainMessageBox.setEnabled(true);
	}
	else{
		mainMessageBox.setEnabled(false);
	}
}

void MenuStateScenario::keyDown(SDL_KeyboardEvent key) {
	Config &configKeys = Config::getInstance(std::pair<ConfigType,ConfigType>(cfgMainKeys,cfgUserKeys));
	//if(key == configKeys.getCharKey("SaveGUILayout")) {
	if(isKeyPressed(configKeys.getSDLKey("SaveGUILayout"),key) == true) {
		GraphicComponent::saveAllCustomProperties(containerName);
		//Lang &lang= Lang::getInstance();
		//console.addLine(lang.get("GUILayoutSaved") + " [" + (saved ? lang.get("Yes") : lang.get("No"))+ "]");
	}
}

}}//end namespace
