Configuration::Configuration()
{
	printf("Reading configuration file.\n");
	log("Reading configuration file.\n");

	Object* tempObj = doParseFile("configuration.txt");
	if (tempObj == NULL)
	{
		log("Could not parse file configuration.txt\n");
		exit(-1);
	}
	vector<Object*> obj = tempObj->getValue("configuration");
	if (obj.size() != 1)
	{
		printf("Configuration file must contain exactly one configuration section.");
		log("Configuration file must contain exactly one configuration section.");
		exit (-2);
	}

	startDate	= date(obj[0]->getLeaf("start_date"));
	if (startDate < date("1835.1.1"))
	{
		log("Warning: start dates prior to 1835 are likely to cause crashes!\n");
	}
	maxLiteracy	= atof(obj[0]->getLeaf("max_literacy").c_str());
	V2Path		= obj[0]->getLeaf("v2directory");
	EU3Path		= obj[0]->getLeaf("EU3directory");
	EU3gametype	= obj[0]->getLeaf("EU3gametype");
	V2gametype	= obj[0]->getLeaf("V2gametype");
	removetype	= obj[0]->getLeaf("removetype");
}
void V2FactoryFactory::loadRequiredTechs(string filename)
{
	Object* obj = doParseFile(filename.c_str());
	if (obj == NULL)
	{
		log("Could not parse file %s\n", filename.c_str());
		exit(-1);
	}
	vector<Object*> techObjs = obj->getLeaves();
	for (vector<Object*>::iterator itr = techObjs.begin(); itr != techObjs.end(); ++itr)
	{
		vector<Object*> building = (*itr)->getValue("activate_building");
		for (vector<Object*>::iterator bitr = building.begin(); bitr != building.end(); ++bitr)
		{
			factoryTechReqs.insert(make_pair((*bitr)->getLeaf(), (*itr)->getKey()));
		}
	}
}
void V2FactoryFactory::loadRequiredInventions(string filename)
{
	Object* obj = doParseFile(filename.c_str());
	if (obj == NULL)
	{
		log("Could not parse file %s\n", filename.c_str());
		exit(-1);
	}
	vector<Object*> invObjs = obj->getLeaves();
	for (vector<Object*>::iterator itr = invObjs.begin(); itr != invObjs.end(); ++itr)
	{
		vector<Object*> effect = (*itr)->getValue("effect");
		if (effect.size() == 0)
		{
			continue;
		}
		vector<Object*> building = effect[0]->getValue("activate_building");
		for (vector<Object*>::iterator bitr = building.begin(); bitr != building.end(); ++bitr)
		{
			factoryInventionReqs.insert(make_pair((*bitr)->getLeaf(), (*itr)->getKey()));
		}
	}
}
// Converts the given EU3 save into a V2 mod.
// Returns 0 on success or a non-zero failure code on error.
int ConvertEU3ToV2(const std::string& EU3SaveFileName)
{
	Object*	obj;				// generic object
	ifstream	read;				// ifstream for reading files

	char curDir[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, curDir);
	LOG(LogLevel::Debug) << "Current directory is " << curDir;

	Configuration::getInstance();

	//Get V2 install location
	LOG(LogLevel::Info) << "Get V2 Install Path";
	string V2Loc = Configuration::getV2Path();
	struct _stat st;
	if (V2Loc.empty() || (_stat(V2Loc.c_str(), &st) != 0))
	{
		LOG(LogLevel::Error) << "No Victoria 2 path was specified in configuration.txt, or the path was invalid";
		return (-1);
	}
	else
	{
		LOG(LogLevel::Debug) << "Victoria 2 install path is " << V2Loc;
	}

	// Get V2 Documents Directory
	LOG(LogLevel::Debug) << "Get V2 Documents directory";
	string V2DocLoc = Configuration::getV2DocumentsPath();
	if (V2DocLoc.empty() || (_stat(V2DocLoc.c_str(), &st) != 0))
	{
		LOG(LogLevel::Error) << "No Victoria 2 documents directory was specified in configuration.txt, or the path was invalid";
		return (-1);
	}
	else
	{
		LOG(LogLevel::Debug) << "Victoria 2 documents directory is " << V2DocLoc;
	}

	//Get EU3 install location
	LOG(LogLevel::Debug) << "Get EU3 Install Path";
	string EU3Loc = Configuration::getEU3Path();
	if (EU3Loc.empty() || (_stat(EU3Loc.c_str(), &st) != 0))
	{
		LOG(LogLevel::Error) << "No Europa Universalis 3 path was specified in configuration.txt, or the path was invalid";
		return (-1);
	}
	else
	{
		LOG(LogLevel::Debug) << "EU3 install path is " << EU3Loc;
	}

	// Get EU3 Mod
	LOG(LogLevel::Debug) << "Get EU3 Mod";
	string fullModPath;
	string modName = Configuration::getEU3Mod();
	if (modName != "")
	{
		fullModPath = EU3Loc + "\\mod\\" + modName;
		if (fullModPath.empty() || (_stat(fullModPath.c_str(), &st) != 0))
		{
			LOG(LogLevel::Error) << modName << " could not be found at the specified directory.  A valid path and mod must be specified.";
			return (-1);
		}
		else
		{
			LOG(LogLevel::Debug) << "EU3 Mod directory is " << fullModPath;
		}
	}

	//get output name
	const int slash	= EU3SaveFileName.find_last_of("\\");				// the last slash in the save's filename
	string outputName	= EU3SaveFileName.substr(slash + 1, EU3SaveFileName.length());
	const int length	= outputName.find_first_of(".");						// the first period after the slash
	outputName			= outputName.substr(0, length);						// the name to use to output the mod
	int dash = outputName.find_first_of('-');
	while (dash != string::npos)
	{
		outputName.replace(dash, 1, "_");
		dash = outputName.find_first_of('-');
	}
	int space = outputName.find_first_of(' ');
	while (space != string::npos)
	{
		outputName.replace(space, 1, "_");
		space = outputName.find_first_of(' ');
	}
	Configuration::setOutputName(outputName);
	LOG(LogLevel::Info) << "Using output name " << outputName;

	LOG(LogLevel::Info) << "* Importing EU3 save *";

	// Parse EU3 Save
	LOG(LogLevel::Info) << "Parsing save";
	obj = doParseFile(EU3SaveFileName.c_str());
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file " << EU3SaveFileName;
		exit(-1);
	}

	// Read all localisations.
	LOG(LogLevel::Info) << "Reading localisation";
	EU3Localisation localisation;
	localisation.ReadFromAllFilesInFolder(Configuration::getEU3Path() + "\\localisation");
	if (!fullModPath.empty())
	{
		LOG(LogLevel::Debug) << "Reading mod localisation";
		localisation.ReadFromAllFilesInFolder(fullModPath + "\\localisation");
	}

	// Construct world from EU3 save.
	LOG(LogLevel::Info) << "Building world";
	EU3World sourceWorld(obj);

	// Read EU3 common\countries
	LOG(LogLevel::Info) << "Reading EU3 common\\countries";
	{
		ifstream commonCountries(Configuration::getEU3Path() + "\\common\\countries.txt");
		sourceWorld.readCommonCountries(commonCountries, Configuration::getEU3Path());
		if (!fullModPath.empty())
		{
			ifstream convertedCommonCountries(fullModPath + "\\common\\countries.txt");
			sourceWorld.readCommonCountries(convertedCommonCountries, fullModPath);
		}
	}

	// Figure out what EU3 gametype we're using
	WorldType game = sourceWorld.getWorldType();
	switch (game)
	{
		case VeryOld:
			LOG(LogLevel::Error) << "EU3 game appears to be from an old version; only IN, HttT, and DW are supported.";
			exit(1);
		case InNomine:
			LOG(LogLevel::Info) << "Game type is: EU3 In Nomine.  EXPERIMENTAL.";
			break;
		case HeirToTheThrone:
			LOG(LogLevel::Info) << "Game type is: EU3 Heir to the Throne.";
			break;
		case DivineWind:
			LOG(LogLevel::Info) << "Game type is: EU3 Divine Wind.";
			break;
		default:
			LOG(LogLevel::Error) << "Error: Could not determine savegame type.";
			exit(1);
	}

	sourceWorld.setLocalisations(localisation);

	// Resolve unit types
	LOG(LogLevel::Info) << "Resolving unit types.";
	RegimentTypeMap rtm;
	read.open("unit_strength.txt");
	if (read.is_open())
	{
		read.close();
		read.clear();
		LOG(LogLevel::Info) << "\tReading unit strengths from unit_strength.txt";
		obj = doParseFile("unit_strength.txt");
		if (obj == NULL)
		{
			LOG(LogLevel::Error) << "Could not parse file unit_strength.txt";
			exit(-1);
		}
		for (int i = 0; i < num_reg_categories; ++i)
		{
			AddCategoryToRegimentTypeMap(obj, (RegimentCategory)i, RegimentCategoryNames[i], rtm);
		}
	}
	else
	{
		LOG(LogLevel::Info) << "Reading unit strengths from EU3 installation folder";
		struct _finddata_t unitFileData;
		intptr_t fileListing;
		if ( (fileListing = _findfirst( (EU3Loc + "\\common\\units\\*.txt").c_str(), &unitFileData)) == -1L)
		{
			LOG(LogLevel::Info) << "Could not open units directory.";
			return -1;
		}
		do
		{
			if (strcmp(unitFileData.name, ".") == 0 || strcmp(unitFileData.name, "..") == 0 )
			{
				continue;
			}
			string unitFilename = unitFileData.name;
			string unitName = unitFilename.substr(0, unitFilename.find_first_of('.'));
			AddUnitFileToRegimentTypeMap((EU3Loc + "\\common\\units"), unitName, rtm);
		} while(_findnext(fileListing, &unitFileData) == 0);
		_findclose(fileListing);
	}
	read.close();
	read.clear();
	sourceWorld.resolveRegimentTypes(rtm);


	// Merge nations
	LOG(LogLevel::Info) << "Merging nations.";
	obj = doParseFile("merge_nations.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file merge_nations.txt";
		exit(-1);
	}
	mergeNations(sourceWorld, obj);


	// Parse V2 input file
	LOG(LogLevel::Info) << "Parsing Vicky2 data";
	vector<pair<string, string>> minorityPops;
	minorityPops.push_back(make_pair("ashkenazi","jewish"));
	minorityPops.push_back(make_pair("sephardic","jewish"));
	minorityPops.push_back(make_pair("","jewish"));
	V2World destWorld(minorityPops);


	// Construct factory factory
	LOG(LogLevel::Info) << "Determining factory allocation rules.";
	V2FactoryFactory factoryBuilder;


	// Parse province mappings
	LOG(LogLevel::Info) << "Parsing province mappings";
	obj = doParseFile("province_mappings.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file province_mappings.txt";
		exit(-1);
	}
	provinceMapping			provinceMap;
	inverseProvinceMapping	inverseProvinceMap;
	resettableMap				resettableProvinces;
	initProvinceMap(obj, sourceWorld.getWorldType(), provinceMap, inverseProvinceMap, resettableProvinces);
	sourceWorld.checkAllProvincesMapped(inverseProvinceMap);
	sourceWorld.setEU3WorldProvinceMappings(inverseProvinceMap);


	// Get country mappings
	LOG(LogLevel::Info) << "Getting country mappings";
	CountryMapping countryMap;
	countryMap.ReadRules("country_mappings.txt");

	// Get adjacencies
	LOG(LogLevel::Info) << "Importing adjacencies";
	adjacencyMapping adjacencyMap = initAdjacencyMap();

	// Generate continent mapping
	LOG(LogLevel::Info) << "Finding Continents";
	string EU3Mod = Configuration::getEU3Mod();
	continentMapping continentMap;
	if (EU3Mod != "")
	{
		string continentFile = Configuration::getEU3Path() + "\\mod\\" + EU3Mod + "\\map\\continent.txt";
		if ((_stat(continentFile.c_str(), &st) == 0))
		{
			obj = doParseFile(continentFile.c_str());
			if ((obj != NULL) && (obj->getLeaves().size() > 0))
			{
				initContinentMap(obj, continentMap);
			}
		}
	}
	if (continentMap.size() == 0)
	{
		obj = doParseFile((EU3Loc + "\\map\\continent.txt").c_str());
		if (obj == NULL)
		{
			LOG(LogLevel::Error) << "Could not parse file " << EU3Loc << "\\map\\continent.txt";
			exit(-1);
		}
		if (obj->getLeaves().size() < 1)
		{
			LOG(LogLevel::Error) << "Failed to parse continent.txt";
			return 1;
		}
		initContinentMap(obj, continentMap);
	}
	if (continentMap.size() == 0)
	{
		LOG(LogLevel::Warning) << "No continent mappings found - may lead to problems later";
	}
	
	// Generate region mapping
	LOG(LogLevel::Info) << "Parsing region structure";
	if (_stat(".\\blankMod\\output\\map\\region.txt", &st) == 0)
	{
		obj = doParseFile(".\\blankMod\\output\\map\\region.txt");
		if (obj == NULL)
		{
			LOG(LogLevel::Error) << "Could not parse file .\\blankMod\\output\\map\\region.txt";
			exit(-1);
		}
	}
	else
	{
		obj = doParseFile((V2Loc + "\\map\\region.txt").c_str());
		if (obj == NULL)
		{
			LOG(LogLevel::Error) << "Could not parse file " << V2Loc << "\\map\\region.txt";
			exit(-1);
		}
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Could not parse region.txt";
		return 1;
	}
	stateMapping		stateMap;
	stateIndexMapping stateIndexMap;
	initStateMap(obj, stateMap, stateIndexMap);


	// Parse Culture Mappings
	LOG(LogLevel::Info) << "Parsing culture mappings";
	obj = doParseFile("cultureMap.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file cultureMap.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse cultureMap.txt";
		return 1;
	}
	cultureMapping cultureMap;
	cultureMap = initCultureMap(obj->getLeaves()[0]);
	obj = doParseFile("slaveCultureMap.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file slaveCultureMap.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse slaveCultureMap.txt";
		return 1;
	}
	cultureMapping slaveCultureMap;
	slaveCultureMap = initCultureMap(obj->getLeaves()[0]);

	unionCulturesMap			unionCultures;
	inverseUnionCulturesMap	inverseUnionCultures;
	if (EU3Mod != "")
	{
		string modCultureFile = Configuration::getEU3Path() + "\\mod\\" + EU3Mod + "\\common\\cultures.txt";
		if ((_stat(modCultureFile.c_str(), &st) == 0))
		{
			obj = doParseFile(modCultureFile.c_str());
			if ((obj != NULL) && (obj->getLeaves().size() > 0))
			{
				initUnionCultures(obj, unionCultures, inverseUnionCultures);
			}
		}
	}
	if (unionCultures.size() == 0)
	{
		obj = doParseFile((EU3Loc + "\\common\\cultures.txt").c_str());
		if (obj == NULL)
		{
			LOG(LogLevel::Error) << "Could not parse file " << EU3Loc << "\\common\\cultures.txt";
			exit(-1);
		}
		initUnionCultures(obj, unionCultures, inverseUnionCultures);
	}
	sourceWorld.checkAllEU3CulturesMapped(cultureMap, inverseUnionCultures);

	// Parse EU3 Religions
	LOG(LogLevel::Info) << "Parsing EU3 religions";
	bool parsedReligions = false;
	if (EU3Mod != "")
	{
		string modReligionFile = Configuration::getEU3Path() + "\\mod\\" + EU3Mod + "\\common\\religion.txt";
		if ((_stat(modReligionFile.c_str(), &st) == 0))
		{
			obj = doParseFile(modReligionFile.c_str());
			if ((obj != NULL) && (obj->getLeaves().size() > 0))
			{
				EU3Religion::parseReligions(obj);
				parsedReligions = true;
			}
		}
	}
	if (!parsedReligions)
	{
		obj = doParseFile((EU3Loc + "\\common\\religion.txt").c_str());
		if (obj == NULL)
		{
			LOG(LogLevel::Error) << "Could not parse file " << EU3Loc << "\\common\\religion.txt";
			exit(-1);
		}
		if (obj->getLeaves().size() < 1)
		{
			LOG(LogLevel::Error) << "Failed to parse religion.txt.";
			return 1;
		}
		EU3Religion::parseReligions(obj);
	}

	// Parse Religion Mappings
	LOG(LogLevel::Info) << "Parsing religion mappings";
	obj = doParseFile("religionMap.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file religionMap.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse religionMap.txt";
		return 1;
	}
	religionMapping religionMap;
	religionMap = initReligionMap(obj->getLeaves()[0]);
	sourceWorld.checkAllEU3ReligionsMapped(religionMap);


	//Parse unions mapping
	LOG(LogLevel::Info) << "Parsing union mappings";
	obj = doParseFile("unions.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file unions.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse unions.txt";
		return 1;
	}
	unionMapping unionMap;
	unionMap = initUnionMap(obj->getLeaves()[0]);


	//Parse government mapping
	LOG(LogLevel::Info) << "Parsing governments mappings";
	initParser();
	obj = doParseFile("governmentMapping.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file governmentMapping.txt";
		exit(-1);
	}
	governmentMapping governmentMap;
	governmentMap = initGovernmentMap(obj->getLeaves()[0]);


	//Parse tech schools
	LOG(LogLevel::Info) << "Parsing tech schools.";
	initParser();
	obj = doParseFile("blocked_tech_schools.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file blocked_tech_schools.txt";
		exit(-1);
	}
	vector<string> blockedTechSchools;
	blockedTechSchools = initBlockedTechSchools(obj);
	initParser();
	obj = doParseFile( (V2Loc + "\\common\\technology.txt").c_str() );
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file " << V2Loc << "\\common\\technology.txt";
		exit(-1);
	}
	vector<techSchool> techSchools;
	techSchools = initTechSchools(obj, blockedTechSchools);


	// Get Leader traits
	LOG(LogLevel::Info) << "Getting leader traits";
	V2LeaderTraits lt;
	map<int, int> leaderIDMap; // <EU3, V2>

	// Parse EU4 Regions
	LOG(LogLevel::Info) << "Parsing EU4 regions";
	obj = doParseFile((EU3Loc + "\\map\\region.txt").c_str());
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file " << EU3Loc << "\\map\\region.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse region.txt";
		return 1;
	}
	EU3RegionsMapping EU3RegionsMap;
	initEU3RegionMap(obj, EU3RegionsMap);
	if (EU3Mod != "")
	{
		string modRegionFile = Configuration::getEU3Path() + "\\mod\\" + EU3Mod + "\\map\\region.txt";
		if ((_stat(modRegionFile.c_str(), &st) == 0))
		{
			obj = doParseFile(modRegionFile.c_str());
			if (obj == NULL)
			{
				LOG(LogLevel::Error) << "Could not parse file " << modRegionFile;
				exit(-1);
			}
			EU3Religion::parseReligions(obj);
		}
	}

	// Create Country Mapping
	removeEmptyNations(sourceWorld);
	if (Configuration::getRemovetype() == "dead")
	{
		removeDeadLandlessNations(sourceWorld);
	}
	else if (Configuration::getRemovetype() == "all")
	{
		removeLandlessNations(sourceWorld);
	}
	countryMap.CreateMapping(sourceWorld, destWorld);


	// Convert
	LOG(LogLevel::Info) << "Converting countries";
	destWorld.convertCountries(sourceWorld, countryMap, cultureMap, unionCultures, religionMap, governmentMap, inverseProvinceMap, techSchools, leaderIDMap, lt, EU3RegionsMap);
	destWorld.scalePrestige();
	LOG(LogLevel::Info) << "Converting provinces";
	destWorld.convertProvinces(sourceWorld, provinceMap, resettableProvinces, countryMap, cultureMap, slaveCultureMap, religionMap, stateIndexMap, EU3RegionsMap);
	LOG(LogLevel::Info) << "Converting diplomacy";
	destWorld.convertDiplomacy(sourceWorld, countryMap);
	LOG(LogLevel::Info) << "Setting colonies";
	destWorld.setupColonies(adjacencyMap, continentMap);
	LOG(LogLevel::Info) << "Creating states";
	destWorld.setupStates(stateMap);
	LOG(LogLevel::Info) << "Setting unciv reforms";
	destWorld.convertUncivReforms();
	LOG(LogLevel::Info) << "Converting techs";
	destWorld.convertTechs(sourceWorld);
	LOG(LogLevel::Info) << "Allocating starting factories";
	destWorld.allocateFactories(sourceWorld, factoryBuilder);
	LOG(LogLevel::Info) << "Creating pops";
	destWorld.setupPops(sourceWorld);
	LOG(LogLevel::Info) << "Adding unions";
	destWorld.addUnions(unionMap);
	LOG(LogLevel::Info) << "Converting armies and navies";
	destWorld.convertArmies(sourceWorld, inverseProvinceMap, leaderIDMap, adjacencyMap);

	// Output results
	LOG(LogLevel::Info) << "Outputting mod";
	system("%systemroot%\\System32\\xcopy blankMod output /E /Q /Y /I");
	FILE* modFile;
	if (fopen_s(&modFile, ("Output\\" + Configuration::getOutputName() + ".mod").c_str(), "w") != 0)
	{
		LOG(LogLevel::Error) << "Could not create .mod file";
		exit(-1);
	}
	fprintf(modFile, "name = \"Converted - %s\"\n", Configuration::getOutputName().c_str());
	fprintf(modFile, "path = \"mod/%s\"\n", Configuration::getOutputName().c_str());
	fprintf(modFile, "user_dir = \"%s\"\n", Configuration::getOutputName().c_str());
	fprintf(modFile, "replace = \"history/provinces\"\n");
	fprintf(modFile, "replace = \"history/countries\"\n");
	fprintf(modFile, "replace = \"history/diplomacy\"\n");
	fprintf(modFile, "replace = \"history/units\"\n");
	fprintf(modFile, "replace = \"history/pops/1836.1.1\"\n");
	fprintf(modFile, "replace = \"common/religion.txt\"\n");
	fprintf(modFile, "replace = \"common/cultures.txt\"\n");
	fprintf(modFile, "replace = \"gfx/interface/icon_religion.dds\"\n");
	fprintf(modFile, "replace = \"localisation/text.csv\"\n");
	fprintf(modFile, "replace = \"localisation/0_Names.csv\"\n");
	fprintf(modFile, "replace = \"localisation/0_Cultures.csv\"\n");
	fprintf(modFile, "replace = \"history/wars\"\n");
	fclose(modFile);
	string renameCommand = "move /Y output\\output output\\" + Configuration::getOutputName();
	system(renameCommand.c_str());
	destWorld.output();

	LOG(LogLevel::Info) << "* Conversion complete *";
	return 0;
}
V2FactoryFactory::V2FactoryFactory(string V2Loc)
{
	// load required techs/inventions
	factoryTechReqs.clear();
	loadRequiredTechs(V2Loc + "\\technologies\\army_tech.txt");
	loadRequiredTechs(V2Loc + "\\technologies\\commerce_tech.txt");
	loadRequiredTechs(V2Loc + "\\technologies\\culture_tech.txt");
	loadRequiredTechs(V2Loc + "\\technologies\\industry_tech.txt");
	loadRequiredTechs(V2Loc + "\\technologies\\navy_tech.txt");
	factoryInventionReqs.clear();
	loadRequiredInventions(V2Loc + "\\inventions\\army_inventions.txt");
	loadRequiredInventions(V2Loc + "\\inventions\\commerce_inventions.txt");
	loadRequiredInventions(V2Loc + "\\inventions\\culture_inventions.txt");
	loadRequiredInventions(V2Loc + "\\inventions\\industry_inventions.txt");
	loadRequiredInventions(V2Loc + "\\inventions\\navy_inventions.txt");

	// load factory types
	factoryTypes.clear();
	Object* obj = doParseFile((V2Loc + "\\common\\production_types.txt").c_str());
	if (obj == NULL)
	{
		log("Could not parse file %s\n", (V2Loc + "\\common\\production_types.txt").c_str());
		exit(-1);
	}
	vector<Object*> factoryObjs = obj->getLeaves();
	for (vector<Object*>::iterator itr = factoryObjs.begin(); itr != factoryObjs.end(); ++itr)
	{
		V2FactoryType* ft = new V2FactoryType(*itr);
		map<string,string>::iterator reqitr = factoryTechReqs.find(ft->name);
		if (reqitr != factoryTechReqs.end())
		{
			ft->requireTech = reqitr->second;
		}
		reqitr = factoryInventionReqs.find(ft->name);
		if (reqitr != factoryInventionReqs.end())
		{
			for (int i = 0; i <= VANILLA_naval_exercises; ++i)
			{
				if ((Configuration::getV2Gametype() != "HOD") && (reqitr->second == vanillaInventionNames[i])) 
				{
					ft->vanillaRequiredInvention = (vanillaInventionType)i;
					break;
				}
				else if ((Configuration::getV2Gametype() != "HOD") && (reqitr->second == HODInventionNames[i])) 
				{
					ft->HODRequiredInvention = (HODInventionType)i;
					break;
				}
			}
		}
		factoryTypes[ft->name] = ft;
	}

	factoryCounts.clear();
	obj = doParseFile("starting_factories.txt");
	if (obj == NULL)
	{
		log("Could not parse file starting_factories.txt\n");
		exit(-1);
	}
	vector<Object*> top = obj->getValue("starting_factories");
	if (top.size() != 1)
	{
		log("Error: Could not load starting factory list!\n");
		printf("Error: Could not load starting factory list!\n");
		exit(-1);
	}
	vector<Object*> factories = top[0]->getLeaves();
	for (vector<Object*>::iterator itr = factories.begin(); itr != factories.end(); ++itr)
	{
		string factoryType = (*itr)->getKey();
		int count = atoi((*itr)->getLeaf().c_str());

		map<string, V2FactoryType*>::iterator t = factoryTypes.find(factoryType);
		if (t == factoryTypes.end())
		{
			log("Error: Could not locate V2 factory type for starting factories of type %s!\n", factoryType.c_str());
			continue;
		}
		factoryCounts.push_back(pair<V2FactoryType*, int>(t->second, count));
	}
}
void AddUnitFileToRegimentTypeMap(string directory, string name, RegimentTypeMap& rtm)
{
	Object* obj = doParseFile((directory + "\\" + name + ".txt").c_str());
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file " << directory << '\\' << name << ".txt";
		exit(-1);
	}

	int rc = -1;
	vector<Object*> typeObj = obj->getValue("type");
	if (typeObj.size() < 1)
	{
		LOG(LogLevel::Warning) << "Unit file for " << name << " has no type";
		return;
	}
	string type = typeObj[0]->getLeaf();
	for (int i = 0; i < num_reg_categories; ++i)
	{
		if (type == RegimentCategoryNames[i])
			rc = i;
	}
	if (rc == -1)
	{
		LOG(LogLevel::Warning) << "Unit file for " << name << " has unrecognized type " << type;
		return;
	}

	int unitStrength = 0;
	vector<Object*> strObj;
	strObj = obj->getValue("maneuver");
	if (strObj.size() > 0)
		unitStrength += atoi(strObj[0]->getLeaf().c_str());
	strObj = obj->getValue("offensive_morale");
	if (strObj.size() > 0)
		unitStrength += atoi(strObj[0]->getLeaf().c_str());
	strObj = obj->getValue("defensive_morale");
	if (strObj.size() > 0)
		unitStrength += atoi(strObj[0]->getLeaf().c_str());
	strObj = obj->getValue("offensive_fire");
	if (strObj.size() > 0)
		unitStrength += atoi(strObj[0]->getLeaf().c_str());
	strObj = obj->getValue("defensive_fire");
	if (strObj.size() > 0)
		unitStrength += atoi(strObj[0]->getLeaf().c_str());
	strObj = obj->getValue("offensive_shock");
	if (strObj.size() > 0)
		unitStrength += atoi(strObj[0]->getLeaf().c_str());
	strObj = obj->getValue("defensive_shock");
	if (strObj.size() > 0)
		unitStrength += atoi(strObj[0]->getLeaf().c_str());
	strObj = obj->getValue("hull_size");
	if (strObj.size() > 0)
		unitStrength += atoi(strObj[0]->getLeaf().c_str());

	// give all transports equal weight for 1-to-1 conversion
	if (rc == transport)
	{
		unitStrength = 24;
	}

	if (unitStrength == 0)
	{
		LOG(LogLevel::Warning) << "Unit " << name << " has no strength";
		return;
	}

	rtm[name] = pair<RegimentCategory, int>((RegimentCategory)rc, unitStrength);
}
bool Configuration::Init(std::string sConfigPath)
{
	std::string sSave = "";
	std::string sName = "";
	std::string sHoi3Dir = "";
	std::string sHoi3ModDir = "";
	std::string sDefconDir = "";
	std::string sSuperpowerOption = "";

	Object* ConfigFile = doParseFile(sConfigPath.c_str());

	if (nullptr == ConfigFile)
	{
		LOG(LogLevel::Error) << "Could not open the configuration file.";
		return false;
	}
		

	std::vector<Object*> Configs = ConfigFile->getValue("configuration");

	if (Configs.empty())
	{
		LOG(LogLevel::Error) << "Could not read the configuration file.";
		return false;
	}
	Object* Config = Configs.at(0);

	for (auto ConfigLeaf : Config->getLeaves())
	{
		if (ConfigLeaf->getKey() == "save")
			sSave = ConfigLeaf->getLeaf();
		else if (ConfigLeaf->getKey() == "HOI3directory")
			sHoi3Dir = ConfigLeaf->getLeaf();
		else if (ConfigLeaf->getKey() == "HOI3ModDirectory")
			sHoi3ModDir = ConfigLeaf->getLeaf();
		else if (ConfigLeaf->getKey() == "DEFCONdirectory")
			sDefconDir = ConfigLeaf->getLeaf();
		else if (ConfigLeaf->getKey() == "superpowers")
		{
			sSuperpowerOption = ConfigLeaf->getLeaf();
			if (sSuperpowerOption == "custom")
				m_SuperpowerOption = Superpowers::Custom;
			else if (sSuperpowerOption == "factions")
				m_SuperpowerOption = Superpowers::Factions;
			else
				m_SuperpowerOption = Superpowers::Powerful;
		}
		else if (ConfigLeaf->getKey().size() == 5)
		{
			if (ConfigLeaf->getKey().substr(0, 4) == "side")
			{
				int index = ConfigLeaf->getKey().at(4) - '0' - 1;
				if (index > 5) continue;

				for (std::string Tag : ConfigLeaf->getTokens())
					m_Sides[index].push_back(Tag);
			}
		}
	}

	m_SavePath = sSave;
	m_Hoi3Path = sHoi3Dir;
	m_DefconPath = sDefconDir;
	m_Hoi3ModPath = sHoi3ModDir;

	// Sanity checks
	if (m_SavePath.empty())
	{
		LOG(LogLevel::Error) << "No Hearts Of Iron 3 save file specified.";
		return false;
	}

	if (m_Hoi3Path.empty())
	{
		LOG(LogLevel::Error) << "No path to Hearts Of Iron 3 specified.";
		return false;
	}

	if (m_DefconPath.empty())
	{
		LOG(LogLevel::Warning) << "No path to DEFCON specified. The created mod will not be copied into place.";
	}

	if (m_SuperpowerOption == Superpowers::Custom)
	{
		int iEmptySides = 0;
		for (int i = 0; i < 6; i++)
		{
			if (m_Sides[i].empty())
			{
				LOG(LogLevel::Warning) << "Custom superpowers chosen, but side " << i << " is empty.";
				iEmptySides++;
			}
		}
		if (iEmptySides == 6)
		{
			LOG(LogLevel::Error) << "This nuclear war has no sides. World peace!";
			return false;
		}
		else if (iEmptySides == 5)
		{
			LOG(LogLevel::Error) << "This nuclear war has only one side. World conquest ensues!";
			return false;
		}
	}
	return true;
}
void HoI3Province::init(int newNumber)
{
	num				= newNumber;
	name			= "";

	points = 0;
	metal = oil = rare_materials = energy = manpower = leadership = 0.0;
	industry = 0;
	is_coastal = false;
	is_land = false;
	is_blacklisted_port = false;
	avg_mil = 0.0;

	char sNum[8];
	sprintf_s(sNum, 8, "%d", num);
	string HoI3Loc = Configuration::getHoI3Path();

	string parentDir = HoI3Loc + "\\history\\provinces\\*";
	string folder;
	struct _finddata_t	dirData;
	intptr_t			dirListing;
	if ( (dirListing = _findfirst(parentDir.c_str(), &dirData)) != -1L)
	{
		do
		{
			string filename = HoI3Loc + "\\history\\provinces\\" + dirData.name + "\\" + sNum + "*.txt";
			struct _finddata_t	fileData;
			intptr_t			fileListing;
			if ( (fileListing = _findfirst(filename.c_str(), &fileData)) != -1L)
			{
				Object* obj = doParseFile( (HoI3Loc + "\\history\\provinces\\" + dirData.name + "\\" + fileData.name).c_str() );

				vector<Object*> results = obj->getValue("owner");
				if (results.size() > 0)
				{
					is_land = true;
				}
					
				results = obj->getValue("points");
				if (results.size() > 0)
				{
					points = atoi(results[0]->getLeaf().c_str());
				}

				results = obj->getValue("metal");
				if (results.size() > 0)
				{
					metal = atof(results[0]->getLeaf().c_str());
				}

				results = obj->getValue("crude_oil");
				if (results.size() > 0)
				{
					oil = atof(results[0]->getLeaf().c_str());
				}

				results = obj->getValue("rare_materials");
				if (results.size() > 0)
				{
					rare_materials = atof(results[0]->getLeaf().c_str());
				}

				results = obj->getValue("energy");
				if (results.size() > 0)
				{
					energy = atof(results[0]->getLeaf().c_str());
				}

				results = obj->getValue("manpower");
				if (results.size() > 0)
				{
					manpower = atof(results[0]->getLeaf().c_str());
				}

				results = obj->getValue("leadership");
				if (results.size() > 0)
				{
					leadership = atof(results[0]->getLeaf().c_str());
				}

#ifdef IND_DIAG
				results = obj->getValue("industry");
				if (results.size() > 0)
				{
					int temp_industry = atoi(results[0]->getLeaf().c_str());
					map<int, int>::iterator itr = industryDistribution.find(temp_industry);
					if (itr == industryDistribution.end())
						industryDistribution[temp_industry] = 1;
					else
						++itr->second;
				}
#endif

				_findclose(fileListing);
				break;
			}
			_findclose(fileListing);
		} while (_findnext(dirListing, &dirData) == 0);
	}
	_findclose(dirListing);

	naval_base = air_base = land_fort = coastal_fort = anti_air = infrastructure = 0;

	// hack for naval bases.  some coastal provinces can't have a naval base at all.
	static vector<int> port_blacklist;
	if (port_blacklist.size() == 0)
	{
		int temp = 0;
		ifstream s("port_blacklist.txt");
		while (s.good() && !s.eof())
		{
			s >> temp;
			port_blacklist.push_back(temp);
		}
		s.close();
	}
// Converts the given V2 save into a HOI3 mod.
// Returns 0 on success or a non-zero failure code on error.
int ConvertV2ToHoI3(const std::string& V2SaveFileName)
{
	LOG(LogLevel::Info) << "Converter version 1.2";
	Object*	obj;					// generic object

	Configuration::getInstance();

	char curDir[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, curDir);
	LOG(LogLevel::Debug) << "Current directory is " << curDir;

	// Get HoI3 install location
	LOG(LogLevel::Debug) << "Get HoI3 Install Path";
	string HoI3Loc = Configuration::getHoI3Path();	// the HOI3 install location as stated in the configuration file
	struct _stat st;										// the file info
	if (HoI3Loc.empty() || (_stat(HoI3Loc.c_str(), &st) != 0))
	{
		LOG(LogLevel::Error) << "No HoI3 path was specified in configuration.txt, or the path was invalid";
		return (-1);
	}
	else
	{
		LOG(LogLevel::Debug) << "HoI3 path install path is " << HoI3Loc;
	}

	// Get HOI3 Documents Directory
	LOG(LogLevel::Debug) << "Get HOI3 Documents directory";
	string HoI3DocLoc = Configuration::getHoI3DocumentsPath();	// the HoI3 My Documents location as stated in the configuration file
	if (HoI3DocLoc.empty() || (_stat(HoI3DocLoc.c_str(), &st) != 0))
	{
		LOG(LogLevel::Error) << "No HoI3 documents directory was specified in configuration.txt, or the path was invalid";
		return (-1);
	}
	else
	{
		LOG(LogLevel::Debug) << "HoI3 documents directory is " << HoI3DocLoc;
	}

	// Get V2 install location
	LOG(LogLevel::Debug) << "Get V2 Install Path";
	string V2Loc = Configuration::getV2Path();	// the V2 install location as stated in the configuration file
	if (V2Loc.empty() || (_stat(V2Loc.c_str(), &st) != 0))
	{
		LOG(LogLevel::Error) << "No Victoria 2 path was specified in configuration.txt, or the path was invalid";
		return (-1);
	}
	else
	{
		LOG(LogLevel::Debug) << "Victoria 2 install path is " << V2Loc;
	}

	// Get V2 Mod directory
	map<string, string> possibleMods; // name, path
	LOG(LogLevel::Debug) << "Get V2 Documents Directory";
	string V2DocumentsLoc = Configuration::getV2DocumentsPath();	// the Victoria 2 My Documents location as stated in the configuration file
	if (V2DocumentsLoc.empty() || (_stat(V2DocumentsLoc.c_str(), &st) != 0))
	{
		LOG(LogLevel::Error) << "No Victoria 2 documents directory was specified in configuration.txt, or the path was invalid";
		return (-1);
	}
	else
	{
		LOG(LogLevel::Debug) << "Victoria 2 Documents directory is " << V2DocumentsLoc;
	}

	// Sanity check Vic2 mods
	LOG(LogLevel::Debug) << "Double-check Vic2 mods";
	vector<string> vic2Mods = Configuration::getVic2Mods();
	for (auto itr: vic2Mods)
	{
		LOG(LogLevel::Debug) << "\tExpecting a mod with name " << itr;
	}

	set<string> fileNames;
	WinUtils::GetAllFilesInFolder(Configuration::getV2Path() + "\\mod", fileNames);
	for (set<string>::iterator itr = fileNames.begin(); itr != fileNames.end(); itr++)
	{
		const int pos = itr->find_last_of('.');	// the position of the last period in the filename
		if (itr->substr(pos, itr->length()) == ".mod")
		{
			string folderName = itr->substr(0, pos);
			if (WinUtils::doesFolderExist(Configuration::getV2Path() + "\\mod\\" + folderName))
			{
				LOG(LogLevel::Debug) << "\tFound mod with name " << folderName;
			}
		}
	}

	// get inventions
	LOG(LogLevel::Info) << "Getting inventions";
	inventionNumToName iNumToname;
	getInventionNums(iNumToname);

	// parse technologies
	LOG(LogLevel::Info) << "Parsing Vic2 technologies";
	map<string, string> armyTechs;
	obj = doParseFile((Configuration::getV2Path() + "\\technologies\\army_tech.txt").c_str());
	if (obj != NULL)
	{
		for (auto tech: obj->getLeaves())
		{
			armyTechs.insert(make_pair(tech->getKey(), tech->getKey()));
		}
	}
	map<string, string> navyTechs;
	obj = doParseFile((Configuration::getV2Path() + "\\technologies\\navy_tech.txt").c_str());
	if (obj != NULL)
	{
		for (auto tech: obj->getLeaves())
		{
			navyTechs.insert(make_pair(tech->getKey(), tech->getKey()));
		}
	}

	// parse continents
	LOG(LogLevel::Info) << "Parsing continents";
	continentMapping continentMap;
	obj = doParseFile((Configuration::getV2Path() + "\\map\\continent.txt").c_str());
	if (obj != NULL)
	{
		initContinentMap(obj, continentMap);
	}

	//get output name
	const int slash	= V2SaveFileName.find_last_of("\\");				// the last slash in the save's filename
	string outputName = V2SaveFileName.substr(slash + 1, V2SaveFileName.length());
	const int length	= outputName.find_first_of(".");						// the first period after the slash
	outputName			= outputName.substr(0, length);						// the name to use to output the mod
	int dash = outputName.find_first_of('-');									// the first (if any) dask in the output name
	while (dash != string::npos)
	{
		outputName.replace(dash, 1, "_");
		dash = outputName.find_first_of('-');
	}
	int space = outputName.find_first_of(' ');	// the first space (if any) in the output name
	while (space != string::npos)
	{
		outputName.replace(space, 1, "_");
		space = outputName.find_first_of(' ');
	}
	Configuration::setOutputName(outputName);
	LOG(LogLevel::Info) << "Using output name " << outputName;

	string outputFolder = string(curDir) + "\\output\\" + Configuration::getOutputName();
	if (WinUtils::doesFolderExist(outputFolder.c_str()))
	{
		LOG(LogLevel::Error) << "Output folder " << Configuration::getOutputName() << " already exists! Clear the output folder before running again!";
		exit(0);
	}

	// Parse government mapping
	LOG(LogLevel::Info) << "Parsing governments mappings";
	initParser();
	obj = doParseFile("governmentMapping.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file governmentMapping.txt";
		exit(-1);
	}
	governmentMapper::getInstance()->initGovernmentMap(obj->getLeaves()[0]);

	// Parse issues
	LOG(LogLevel::Info) << "Parsing governments reforms";
	for (auto itr : vic2Mods)
	{
		if (WinUtils::DoesFileExist(Configuration::getV2Path() + "\\mod\\" + itr + "\\common\\issues.txt"))
		{
			obj = doParseFile((Configuration::getV2Path() + "\\mod\\" + itr + "\\common\\issues.txt").c_str());
			if (obj != NULL)
			{
				governmentMapper::getInstance()->initReforms(obj);
				break;
			}
		}
	}
	if (!governmentMapper::getInstance()->areReformsInitialized())
	{
		obj = doParseFile((Configuration::getV2Path() + "\\common\\issues.txt").c_str());
		if (obj != NULL)
		{
			governmentMapper::getInstance()->initReforms(obj);
		}
	}

	LOG(LogLevel::Info) << "* Importing V2 save *";

	//	Parse V2 Save
	LOG(LogLevel::Info) << "Parsing save";
	obj = doParseFile(V2SaveFileName.c_str());
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file " << V2SaveFileName << ". File is likely missing.";
		exit(-1);
	}

	// Construct world from V2 save.
	LOG(LogLevel::Info) << "Building world";
	V2World sourceWorld(obj, iNumToname, armyTechs, navyTechs, continentMap);

	// Read all localisations.
	LOG(LogLevel::Info) << "Reading localisation";
	V2Localisation localisation;
	localisation.ReadFromAllFilesInFolder(Configuration::getV2Path() + "\\localisation");
	for (auto itr: vic2Mods)
	{
		LOG(LogLevel::Debug) << "Reading mod localisation";
		localisation.ReadFromAllFilesInFolder(Configuration::getV2Path() + "\\mod\\" + itr + "\\localisation");
	}

	sourceWorld.setLocalisations(localisation);


	// Merge nations
	LOG(LogLevel::Info) << "Merging nations";
	obj = doParseFile("merge_nations.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file merge_nations.txt";
		exit(-1);
	}
	mergeNations(sourceWorld, obj);

	// Parse province mappings
	LOG(LogLevel::Info) << "Parsing province mappings";
	obj = doParseFile("province_mappings.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file province_mappings.txt";
		exit(-1);
	}
	provinceMapping			provinceMap;
	inverseProvinceMapping	inverseProvinceMap;
	resettableMap				resettableProvinces;
	initProvinceMap(obj, provinceMap, inverseProvinceMap, resettableProvinces);
	sourceWorld.checkAllProvincesMapped(inverseProvinceMap);

	// Parse HoI3 data files
	LOG(LogLevel::Info) << "Parsing HoI3 data";
	HoI3World destWorld;
	destWorld.importProvinces(provinceMap);
	destWorld.checkCoastalProvinces();

	// Get country mappings
	CountryMapping countryMap;
	countryMap.ReadRules("country_mappings.txt");
	destWorld.importPotentialCountries();
	countryMap.CreateMapping(sourceWorld, destWorld);

	// Get adjacencies
	LOG(LogLevel::Info) << "Importing HoI3 adjacencies";
	HoI3AdjacencyMapping HoI3AdjacencyMap = initHoI3AdjacencyMap();

	// Leaders
	map<int, int> leaderIDMap; // <V2, HoI3>

	// Parse government jobs
	LOG(LogLevel::Info) << "Parsing government jobs";
	initParser();
	obj = doParseFile("governmentJobs.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file governmentJobs.txt";
		exit(-1);
	}
	governmentJobsMap governmentJobs;
	initGovernmentJobTypes(obj->getLeaves()[0], governmentJobs);

	// Parse leader traits
	LOG(LogLevel::Info) << "Parsing government jobs";
	initParser();
	obj = doParseFile("leader_traits.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file leader_traits.txt";
		exit(-1);
	}
	leaderTraitsMap leaderTraits;
	initLeaderTraitsMap(obj->getLeaves()[0], leaderTraits);

	// parse names
	LOG(LogLevel::Info) << "Parsing names";
	namesMapping namesMap;
	vic2Mods = Configuration::getVic2Mods();
	for (auto itr: vic2Mods)
	{
		LOG(LogLevel::Debug) << "Reading mod cultures";
		obj = doParseFile((Configuration::getV2Path() + "\\mod\\" + itr + "\\common\\cultures.txt").c_str());
		if (obj != NULL)
		{
			initNamesMapping(obj, namesMap);
		}
	}
	obj = doParseFile((Configuration::getV2Path() + "\\common\\cultures.txt").c_str());
	if (obj != NULL)
	{
		initNamesMapping(obj, namesMap);
	}

	// parse portraits list
	LOG(LogLevel::Info) << "Parsing portraits list";
	portraitMapping portraitMap;
	obj = doParseFile("portraits.txt");
	if (obj != NULL)
	{
		initPortraitMapping(obj, portraitMap);
	}

	// parse culture mapping
	LOG(LogLevel::Info) << "Parsing culture mappings";
	obj = doParseFile("culture_map.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file culture_map.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse culture_map.txt";
		return 1;
	}
	cultureMapping cultureMap;
	cultureMap = initCultureMap(obj->getLeaves()[0]);

	// parse personality mapping
	LOG(LogLevel::Info) << "Parsing personality mappings";
	obj = doParseFile("personality_map.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file personality_map.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse personality_map.txt";
		return 1;
	}
	personalityMap landPersonalityMap;
	personalityMap seaPersonalityMap;
	initLeaderPersonalityMap(obj->getLeaves()[0], landPersonalityMap, seaPersonalityMap);

	// parse background mapping
	LOG(LogLevel::Info) << "Parsing background mappings";
	obj = doParseFile("background_map.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file background_map.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse background_map.txt";
		return 1;
	}
	backgroundMap landBackgroundMap;
	backgroundMap seaBackgroundMap;
	initLeaderBackgroundMap(obj->getLeaves()[0], landBackgroundMap, seaBackgroundMap);

	// parse AI focus data
	LOG(LogLevel::Info) << "Parsing AI focuses";
	obj = doParseFile("ai_focus.txt");
	if (obj == NULL)
	{
		LOG(LogLevel::Error) << "Could not parse file ai_focus.txt";
		exit(-1);
	}
	if (obj->getLeaves().size() < 1)
	{
		LOG(LogLevel::Error) << "Failed to parse ai_focus.txt";
		return 1;
	}
	AIFocusModifiers focusModifiers;
	initAIFocusModifiers(obj, focusModifiers);

	// Convert
	LOG(LogLevel::Info) << "Converting countries";
	destWorld.convertCountries(sourceWorld, countryMap, inverseProvinceMap, leaderIDMap, localisation, governmentJobs, leaderTraits, namesMap, portraitMap, cultureMap, landPersonalityMap, seaPersonalityMap, landBackgroundMap, seaBackgroundMap);
	LOG(LogLevel::Info) << "Converting provinces";
	destWorld.convertProvinceOwners(sourceWorld, provinceMap, countryMap);
	destWorld.convertNavalBases(sourceWorld, inverseProvinceMap);
	destWorld.convertProvinceItems(sourceWorld, provinceMap, inverseProvinceMap, countryMap, HoI3AdjacencyMap);
	destWorld.consolidateProvinceItems(inverseProvinceMap);
	LOG(LogLevel::Info) << "Converting diplomacy";
	destWorld.convertDiplomacy(sourceWorld, countryMap);
	LOG(LogLevel::Info) << "Converting techs";
	destWorld.convertTechs(sourceWorld);
	LOG(LogLevel::Info) << "Adding minimal levels of airbase and port";
	destWorld.addMinimalItems(inverseProvinceMap);
	LOG(LogLevel::Info) << "Converting armies and navies";
	destWorld.convertArmies(sourceWorld, inverseProvinceMap, HoI3AdjacencyMap);
	LOG(LogLevel::Info) << "Setting up factions";
	destWorld.configureFactions(sourceWorld, countryMap);
	LOG(LogLevel::Info) << "Generating Leaders";
	destWorld.generateLeaders(leaderTraits, namesMap, portraitMap);
	LOG(LogLevel::Info) << "Converting victory points";
	destWorld.convertVictoryPoints(sourceWorld, countryMap);
	LOG(LogLevel::Info) << "Setting AI focuses";
	destWorld.setAIFocuses(focusModifiers);

	// Output results
	LOG(LogLevel::Info) << "Outputting mod";
	system("%systemroot%\\System32\\xcopy blankMod output /E /Q /Y /I");

	FILE* modFile;	// the .mod file for this mod
	if (fopen_s(&modFile, ("Output\\" + Configuration::getOutputName() + ".mod").c_str(), "w") != 0)
	{
		LOG(LogLevel::Error) << "Could not create .mod file";
		exit(-1);
	}
	fprintf(modFile, "name = \"Converted - %s\"\n", Configuration::getOutputName().c_str());
	fprintf(modFile, "path = mod/%s\"\n", Configuration::getOutputName().c_str());
	fprintf(modFile, "user_dir = \"%s_user_dir\"\n", Configuration::getOutputName().c_str());
	fprintf(modFile, "replace = \"history/countries\"\n");
	fprintf(modFile, "replace = \"history/diplomacy\"\n");
	fprintf(modFile, "replace = \"history/provinces\"\n");
	fprintf(modFile, "replace = \"script\"\n");
	fprintf(modFile, "replace_path = \"events\"\n");
	fprintf(modFile, "replace_path = \"decisions\"\n");
	fclose(modFile);
	string renameCommand = "move /Y output\\output output\\" + Configuration::getOutputName();	// the command to rename the mod correctly
	system(renameCommand.c_str());
	LOG(LogLevel::Info) << "Copying flags";
	destWorld.copyFlags(sourceWorld, countryMap);

	LOG(LogLevel::Info) << "Outputting world";
	destWorld.output();

	LOG(LogLevel::Info) << "* Conversion complete *";
	return 0;
}