/*
   Copyright (C) 2004 by James Gregory
   Part of the GalaxyHack project
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.
 
   See the COPYING file for more details.
*/

#include "LookupTables.h"
#include "Globals.h"
#include "Inlines.h"

#include <sstream>
#include <algorithm>

using std::istringstream;
using std::find;
using std::getline;

void SetupLookupTables() {
	//set up specifier lookup table	
	tokenLookup["#"] = TT_Comment;
	tokenLookup["if"] = TT_If;
	tokenLookup["else"] = TT_Else;
	tokenLookup["elif"] = TT_ElIf;
	//no TT_OpenB
	//no TT_CloseB
	tokenLookup["@"] = TT_Jump;
	tokenLookup["return"] = TT_Return;
	
	tokenLookup["starttimer"] = TT_StartTimer;
	
	tokenLookup["move"] = TT_Move;
	tokenLookup["moveaway"] = TT_MoveAway;
	tokenLookup["fire"] = TT_Fire;
	tokenLookup["patrol"] = TT_Patrol;
	
	tokenLookup["=="] = TT_Equal;
	tokenLookup["!="] = TT_NotEqual;
	tokenLookup[">"] = TT_GreaterThan;
	tokenLookup["<"] = TT_LessThan;
	tokenLookup[">="] = TT_GreaterThanEqual;
	tokenLookup["<="] = TT_LessThanEqual;
	tokenLookup["!"] = TT_Not;
	tokenLookup["&&"] = TT_And;
	tokenLookup["||"] = TT_Or;
	
	tokenLookup["+"] = TT_Add;
	tokenLookup["-"] = TT_Minus;
	tokenLookup["*"] = TT_Multiply;
	tokenLookup["/"] = TT_Divide;
	tokenLookup["%"] = TT_Modulo;

	tokenLookup["="] = TT_Assign;
	tokenLookup["++"] = TT_Increment;
	tokenLookup["--"] = TT_Decrement;

	tokenLookup["$"] = TT_ScriptVar;
	tokenLookup["$g"] = TT_SaveGroup;
	tokenLookup["$timer"] = TT_ScriptTimer;
	
	tokenLookup["$global"] = TT_GScriptVar;
	tokenLookup["$globalg"] = TT_GSaveGroup;

	tokenLookup["our"] = TT_Our;
	tokenLookup["aenemy"] = TT_AnyEnemy;
	tokenLookup["afriend"] = TT_AnyFriend;
	tokenLookup["aally"] = TT_AnyAlly;
	tokenLookup["numenemy"] = TT_NumEnemy;
	tokenLookup["numfriend"] = TT_NumFriend;
	tokenLookup["numally"] = TT_NumAlly;
	tokenLookup["nenemy"] = TT_NearestEnemy;
	tokenLookup["nfriend"] = TT_NearestFriend;
	tokenLookup["nally"] = TT_NearestAlly;
	tokenLookup["nedge"] = TT_NearestWorldEdge;

	tokenLookup["health"] = TT_Health;
	tokenLookup["shield"] = TT_Shield;
	tokenLookup["armour"] = TT_Armour;
	tokenLookup["maxhealth"] = TT_MaxHealth;
	tokenLookup["maxshield"] = TT_MaxShield;
	tokenLookup["maxarmour"] = TT_MaxArmour;
	tokenLookup["unitmaxshield"] = TT_UnitMaxShield;
	tokenLookup["unitmaxarmour"] = TT_UnitMaxArmour;
	tokenLookup["number"] = TT_Number;
	tokenLookup["speed"] = TT_Speed;
	tokenLookup["distance"] = TT_Distance;
	tokenLookup["smallrange"] = TT_SmallRange;
	tokenLookup["smallpower"] = TT_SmallPower;
	tokenLookup["bigrange"] = TT_BigRange;
	tokenLookup["bigpower"] = TT_BigPower;
	tokenLookup["bigtype"] = TT_BigType;
	tokenLookup["bigammo"] = TT_BigAmmo;
	tokenLookup["insmallrange"] = TT_InSmallRange;
	tokenLookup["inbigrange"] = TT_InBigRange;
	tokenLookup["ourinsmallrange"] = TT_OurInSmallRange;
	tokenLookup["ourinbigrange"] = TT_OurInBigRange;
	tokenLookup["left"] = TT_Left;
	tokenLookup["misstarget"] = TT_MissTarget;
	tokenLookup["torptarget"] = TT_TorpTarget;
	tokenLookup["type"] = TT_GroupType;
	
	tokenLookup["none"] = TT_None;
	tokenLookup["laser"] = TT_Laser;
	tokenLookup["missile"] = TT_Missile;
	tokenLookup["torpedo"] = TT_Torpedo;

	tokenLookup["capitalship"] = TT_CapitalShip;
	tokenLookup["frigate"] = TT_Frigate;
	tokenLookup["smallship"] = TT_SmallShip;

	tokenLookup["n"] = TT_N;
	tokenLookup["ne"] = TT_NE;
	tokenLookup["e"] = TT_E;
	tokenLookup["se"] = TT_SE;
	tokenLookup["s"] = TT_S;
	tokenLookup["sw"] = TT_SW;
	tokenLookup["w"] = TT_W;
	tokenLookup["nw"] = TT_NW;

	tokenLookup["northedge"] = TT_NorthEdge;
	tokenLookup["eastedge"] = TT_EastEdge;
	tokenLookup["southedge"] = TT_SouthEdge;
	tokenLookup["westedge"] = TT_WestEdge;

	tokenLookup["random"] = TT_Random;

	///////////

	//weapon lookup table
	WeaponDesc tempWeapon;

	tempWeapon.startAmmo = 0;
	tempWeapon.category = WCAT_None;

	tempWeapon.name = "None";
	tempWeapon.points = 0;
	tempWeapon.power = 0;
	tempWeapon.range = 0;
	tempWeapon.accuracy = 0;
	tempWeapon.reload = 0;
	tempWeapon.speed = 0;
	tempWeapon.length = 0;
	tempWeapon.FSWC = FS_WT_None;

	weaponLookup[WT_None] = tempWeapon;
	weaponLoadLookup[weaponLookup[WT_None].name] = WT_None;
	WCToWTLookup[FS_WT_None] = WT_None;


	/////

	string inputStr;
	FileToString(globalSettings.bdp + "gamedata/equip.dat", inputStr);
	istringstream input(inputStr);

	OptionSkipIter iter = input;
	OptionSkipIter fileEnd;

	////

	SkipToNextSection(input, iter, fileEnd);

	iter = find(iter, fileEnd, ',');
	iter.PlusPlusSS();
	globalSettings.SSCost = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	globalSettings.maxSSPoints = IterToInt(iter, fileEnd);

	iter = find(iter, fileEnd, ',');
	iter.PlusPlusSS();
	globalSettings.FrCost = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	globalSettings.maxFrPoints = IterToInt(iter, fileEnd);

	iter = find(iter, fileEnd, ',');
	iter.PlusPlusSS();
	globalSettings.LCSCost = IterToInt(iter, fileEnd);

	iter = find(iter, fileEnd, ',');
	iter.PlusPlusSS();
	globalSettings.MCSCost = IterToInt(iter, fileEnd);

	iter = find(iter, fileEnd, ',');
	iter.PlusPlusSS();
	globalSettings.HCSCost = IterToInt(iter, fileEnd);

	/////

	SkipToNextSection(input, iter, fileEnd);

	WeaponType wi = WT_Twin1;
	WindowChoice wj = FS_WT_Twin1;
	while (wi != WT_Torpedo3 + 1) {
		FillWeaponValues(wi, wj, input, iter, fileEnd);
		wi = static_cast<WeaponType>(wi + 1);
		wj = static_cast<WindowChoice>(wj + 1);
		iter.EqualsSS(input);
	}

	///

	SkipToNextSection(input, iter, fileEnd);

	EquipDesc tempEquip;

	tempEquip.points = 0;
	tempEquip.max = 0;
	tempEquip.recharge = 0;
	tempEquip.category = EQCAT_None;
	equipLookup["None"] = tempEquip;
	WCToETLookup[FS_ET_None] = "None";

	int ei = 0;
	WindowChoice ej = FS_ET_SSEngine1;
	while (ei != 22) {
		FillEquipValues(ei, ej, input, iter, fileEnd);
		++ei;
		ej = static_cast<WindowChoice>(ej + 1);
		iter.EqualsSS(input);
	}

	///

	uTypeToString[UT_CaShUnit] = "Capital ship";
	uTypeToString[UT_FrUnit] = "Frigate";
	uTypeToString[UT_SmShUnit] = "Small ship";

	csTypeToString[CST_Heavy] = "Heavy capital ship";
	csTypeToString[CST_Medium] = "Medium capital ship";
	csTypeToString[CST_Light] = "Light capital ship";

	stringToUType["Heavy capital ship"] = UT_CaShUnit;
	stringToUType["Medium capital ship"] = UT_CaShUnit;
	stringToUType["Light capital ship"] = UT_CaShUnit;
	stringToUType["Capital ship"] = UT_CaShUnit;
	stringToUType["Frigate"] = UT_FrUnit;
	stringToUType["Small ship"] = UT_SmShUnit;

	stringToCSType["Heavy capital ship"] = CST_Heavy;
	stringToCSType["Medium capital ship"] = CST_Medium;
	stringToCSType["Light capital ship"] = CST_Light;

	//colours
	if (!globalSettings.batch) {
		gold = JSDL.MapRGB(170, 170, 0);
		veryDarkGold = JSDL.MapRGB(80, 80, 0);
		veryDarkGreen = JSDL.MapRGB(0, globalSettings.howGreenIsGreen, 0);	
		lightBlue = JSDL.MapRGB(0, 255, 255);
		
		laserRed = JSDL.MapRGB(204, 0, 0);
		laserGreen = JSDL.MapRGB(0, 190, 0);
		laserBlue = JSDL.MapRGB(0, 0, 220);
		laserYellow = JSDL.MapRGB(214, 214, 0);
		missileGrey = JSDL.MapRGB(206, 206, 206);
		torpedoBlue = JSDL.MapRGB(36, 96, 226);
	
		sideRed = JSDL.MapRGB(160, 0, 0);
		sideGreen = JSDL.MapRGB(60, 150, 40);
		sideBlue = JSDL.MapRGB(40, 60, 150);
		sideYellow = JSDL.MapRGB(220, 200, 120);
	
		radarRed = JSDL.MapRGB(255, 80, 80);
		radarGreen = JSDL.MapRGB(60, 220, 40);
		radarBlue = JSDL.MapRGB(40, 60, 220);
		radarYellow = JSDL.MapRGB(230, 230, 0);
	
		black = 0;
		white = 0xFFFF;
		greyText = JSDL.MapRGB(150, 150, 150);
	}

	colorRect.w = 8;
	colorRect.h = 8;
}

void SkipToNextSection(istringstream& input, OptionSkipIter& iter, const OptionSkipIter& fileEnd) {
	while (!FindNotComment(iter, fileEnd)) {
		iter = find(iter, fileEnd, '\n');

		if (iter == fileEnd)
			throw runtime_error("Couldn't find the next section of the game data file");
		else
			++iter;
	}
}

void FillWeaponValues(WeaponType i, WindowChoice j, istringstream& input, OptionSkipIter& iter, const OptionSkipIter& fileEnd) {
	static WeaponDesc tempWeapon;

	getline(input, tempWeapon.name, ',');
	iter.EqualsSS(input);
	tempWeapon.points = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	tempWeapon.power = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	tempWeapon.range = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	tempWeapon.accuracy = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	tempWeapon.reload = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	tempWeapon.speed = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	tempWeapon.length = IterToInt(iter, fileEnd);

	if (i == WT_Twin1) {
		tempWeapon.category = WCAT_Twin;
		tempWeapon.startAmmo = maxAIInt;
	} else if (i == WT_BSSmall1)
		tempWeapon.category = WCAT_Small;
	else if (i == WT_BSLarge1)
		tempWeapon.category = WCAT_Large;
	else if (i == WT_Missile1) {
		tempWeapon.category = WCAT_Missile;
		tempWeapon.startAmmo = 2;
	} else if (i == WT_Torpedo1)
		tempWeapon.category = WCAT_Torpedo;

	tempWeapon.FSWC = j;
	weaponLookup[i] = tempWeapon;
	weaponLoadLookup[weaponLookup[i].name] = i;
	WCToWTLookup[j] = i;
}

void FillEquipValues(int i, WindowChoice j, istringstream& input, OptionSkipIter& iter, const OptionSkipIter& fileEnd) {
	static EquipDesc tempEquip;
	string tempName;

	getline(input, tempName, ',');
	iter.EqualsSS(input);
	tempEquip.points = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	tempEquip.max = IterToInt(iter, fileEnd);
	iter.PlusPlusSS();
	tempEquip.recharge = IterToInt(iter, fileEnd);

	if (i == 0) {
		tempEquip.category = EQCAT_SSEngine;
		globalSettings.defaultSSEngine = tempName;
	} else if (i == 3) {
		tempEquip.category = EQCAT_FrEngine;
		globalSettings.defaultFrEngine = tempName;
    } else if (i == 6) {
        tempEquip.category = EQCAT_CSEngine;
		globalSettings.defaultCSEngine = tempName;
	} else if (i == 7) {
		tempEquip.category = EQCAT_SSArmour;
		globalSettings.defaultSSArmour = tempName;
	} else if (i == 10) {
		tempEquip.category = EQCAT_FrArmour;
		globalSettings.defaultFrArmour = tempName;
	} else if (i == 13) {
		tempEquip.category = EQCAT_CSArmour;
		globalSettings.defaultLCSArmour = tempName;
	} else if (i == 14)
		globalSettings.defaultMCSArmour = tempName;
	else if (i == 15)
		globalSettings.defaultHCSArmour = tempName;
	else if (i == 16)
		tempEquip.category = EQCAT_SSShield;
	else if (i == 19)
		tempEquip.category = EQCAT_FrShield;

	tempEquip.FSEC = j;
	equipLookup[tempName] = tempEquip;
	WCToETLookup[j] = tempName;
}

