// This file is part of ZetaGlest <https://github.com/ZetaGlest>
//
// Copyright (C) 2018  The ZetaGlest team
//
// ZetaGlest is a fork of MegaGlest <https://megaglest.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>

#include "faction.h"

#include <algorithm>
#include <cassert>

#include "resource_type.h"
#include "unit.h"
#include "util.h"
#include "sound_renderer.h"
#include "renderer.h"
#include "tech_tree.h"
#include "game.h"
#include "config.h"
#include "randomgen.h"
#include "leak_dumper.h"

using namespace Shared::Util;
using Shared::Util::RandomGen;

namespace Game {
	bool CommandGroupUnitSorterId::operator () (const int l, const int r) {
		const Unit *lUnit = faction->findUnit(l);
		const Unit *rUnit = faction->findUnit(r);

		if (!lUnit) {
			printf("Error lUnit == NULL for id = %d factionIndex = %d\n", l,
				faction->getIndex());

			for (unsigned int i = 0; i < (unsigned int) faction->getUnitCount();
				++i) {
				printf("%u / %d id = %d [%s]\n", i, faction->getUnitCount(),
					faction->getUnit(i)->getId(),
					faction->getUnit(i)->getType()->getName(false).c_str());
			}
		}
		if (!rUnit) {
			printf("Error rUnit == NULL for id = %d factionIndex = %d\n", r,
				faction->getIndex());

			for (unsigned int i = 0; i < (unsigned int) faction->getUnitCount();
				++i) {
				printf("%u / %d id = %d [%s]\n", i, faction->getUnitCount(),
					faction->getUnit(i)->getId(),
					faction->getUnit(i)->getType()->getName(false).c_str());
			}
		}

		CommandGroupUnitSorter sorter;
		return sorter.compare(lUnit, rUnit);
	}

	bool CommandGroupUnitSorter::operator () (const Unit * l, const Unit * r) {
		return compare(l, r);
	}

	bool CommandGroupUnitSorter::compare(const Unit * l, const Unit * r) {
		//printf("l [%p] r [%p] <>",l,r);

		if (!l) {
			printf("Error l == NULL\n");
		}
		if (!r) {
			printf("Error r == NULL\n");
		}

		assert(l && r);

		if (l == NULL || r == NULL)
			printf("Unit l [%s - %d] r [%s - %d]\n",
			(l !=
				NULL ? l->getType()->getName(false).c_str() : "null"),
				(l != NULL ? l->getId() : -1),
				(r !=
					NULL ? r->getType()->getName(false).c_str() : "null"),
					(r != NULL ? r->getId() : -1));


		bool result = false;
		// If comparer is null or dead
		if (r == NULL || r->isAlive() == false) {
			// if source is null or dead also
			if ((l == NULL || l->isAlive() == false)) {
				return false;
			}
			return true;
		} else if ((l == NULL || l->isAlive() == false)) {
			return false;
		}

		//      const Command *command= l->getCurrentCommandThreadSafe();
		//      const Command *commandPeer = r->getCurrentCommandThreadSafe();
		const Command *command = l->getCurrCommand();
		const Command *commandPeer = r->getCurrCommand();

		//Command *command= this->unit->getCurrCommand();

		// Are we moving or attacking
		if (command != NULL && command->getCommandType() != NULL &&
			(command->getCommandType()->getClass() == ccMove ||
				command->getCommandType()->getClass() == ccAttack) &&
			command->getUnitCommandGroupId() > 0) {
			int curCommandGroupId = command->getUnitCommandGroupId();

			//Command *commandPeer = j.unit->getCurrentCommandThreadSafe();
			//Command *commandPeer = j.unit->getCurrCommand();

			// is comparer a valid command
			if (commandPeer == NULL || commandPeer->getCommandType() == NULL) {
				result = true;
			}
			// is comparer command the same type?
			else if (commandPeer->getCommandType()->getClass() !=
				command->getCommandType()->getClass()) {
				result = true;
			}
			// is comparer command groupid invalid?
			else if (commandPeer->getUnitCommandGroupId() < 0) {
				result = true;
			}
			// If comparer command group id is less than current group id
			else if (curCommandGroupId != commandPeer->getUnitCommandGroupId()) {
				result = curCommandGroupId < commandPeer->getUnitCommandGroupId();
			} else {
				float unitDist = l->getCenteredPos().dist(command->getPos());
				float unitDistPeer =
					r->getCenteredPos().dist(commandPeer->getPos());

				// Closest unit in commandgroup
				result = (unitDist < unitDistPeer);
			}
		} else if (command == NULL && commandPeer != NULL) {
			result = false;
		}
		//      else if(command == NULL && j.unit->getCurrentCommandThreadSafe() == NULL) {
		//              return this->unit->getId() < j.unit->getId();
		//      }
		else {
			//Command *commandPeer = j.unit->getCurrentCommandThreadSafe();
			//if( commandPeer != NULL && commandPeer->getCommandType() != NULL &&
			//      (commandPeer->getCommandType()->getClass() != ccMove &&
			//       commandPeer->getCommandType()->getClass() != ccAttack)) {
			result = (l->getId() < r->getId());
			//}
			//else {
			//      result = (l->getId() < r->getId());
			//}
		}

		//printf("Sorting, unit [%d - %s] cmd [%s] | unit2 [%d - %s] cmd [%s] result = %d\n",this->unit->getId(),this->unit->getFullName().c_str(),(this->unit->getCurrCommand() == NULL ? "NULL" : this->unit->getCurrCommand()->toString().c_str()),j.unit->getId(),j.unit->getFullName().c_str(),(j.unit->getCurrCommand() == NULL ? "NULL" : j.unit->getCurrCommand()->toString().c_str()),result);

		return result;
	}

	void Faction::sortUnitsByCommandGroups() {
		MutexSafeWrapper safeMutex(unitsMutex,
			string(__FILE__) + "_" +
			intToStr(__LINE__));
		//printf("====== sortUnitsByCommandGroups for faction # %d [%s] unitCount = %d\n",this->getIndex(),this->getType()->getName().c_str(),units.size());
		//for(unsigned int i = 0; i < units.size(); ++i) {
		//      printf("%d / %d [%p] <>",i,units.size(),&units[i]);
	//      //      printf("i = %d [%p]\n",i,&units[i]);
	//              if(Unit::isUnitDeleted(units[i]) == true) {
	//                      printf("i = %d [%p]\n",i,&units[i]);
	//                      throw game_runtime_error("unit already deleted!");
	//              }
		//}
		//printf("\nSorting\n");

		//std::sort(units.begin(),units.end(),CommandGroupUnitSorter());

		//printf("====== Done sorting for faction # %d [%s] unitCount = %d\n",this->getIndex(),this->getType()->getName().c_str(),units.size());

		//unsigned int originalUnitSize = (unsigned int)units.size();

		std::vector < int >unitIds;
		for (unsigned int i = 0; i < units.size(); ++i) {
			int unitId = units[i]->getId();
			if (this->findUnit(unitId) == NULL) {
				printf
				("#1 Error unitId not found for id = %d [%s] factionIndex = %d\n",
					unitId, units[i]->getType()->getName(false).c_str(),
					this->getIndex());

				for (unsigned int j = 0; j < units.size(); ++j) {
					printf("%u / %d id = %d [%s]\n", j, (int) units.size(),
						units[j]->getId(),
						units[j]->getType()->getName(false).c_str());
				}
			}
			unitIds.push_back(unitId);
		}
		CommandGroupUnitSorterId sorter;
		sorter.faction = this;
		std::stable_sort(unitIds.begin(), unitIds.end(), sorter);

		units.clear();
		for (unsigned int i = 0; i < unitIds.size(); ++i) {

			int unitId = unitIds[i];
			if (this->findUnit(unitId) == NULL) {
				printf("#2 Error unitId not found for id = %d factionIndex = %d\n",
					unitId, this->getIndex());

				for (unsigned int j = 0; j < units.size(); ++j) {
					printf("%u / %d id = %d [%s]\n", j, (int) units.size(),
						units[j]->getId(),
						units[j]->getType()->getName(false).c_str());
				}
			}

			units.push_back(this->findUnit(unitId));
		}

		//assert(originalUnitSize == units.size());
	}

	// =====================================================
	//      class FactionThread
	// =====================================================

	FactionThread::FactionThread(Faction * faction) :BaseThread() {
		this->triggerIdMutex = new Mutex(CODE_AT_LINE);
		this->faction = faction;
		this->masterController = NULL;
		uniqueID = "FactionThread";
	}

	FactionThread::~FactionThread() {
		this->faction = NULL;
		this->masterController = NULL;
		delete this->triggerIdMutex;
		this->triggerIdMutex = NULL;
	}

	void FactionThread::setQuitStatus(bool value) {
		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s] Line: %d value = %d\n",
				__FILE__, __FUNCTION__, __LINE__, value);

		BaseThread::setQuitStatus(value);
		if (value == true) {
			signalPathfinder(-1);
		}

		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s] Line: %d\n", __FILE__,
				__FUNCTION__, __LINE__);
	}

	void FactionThread::signalPathfinder(int frameIndex) {
		if (frameIndex >= 0) {
			static string mutexOwnerId =
				string(__FILE__) + string("_") + intToStr(__LINE__);
			MutexSafeWrapper safeMutex(triggerIdMutex, mutexOwnerId);
			this->frameIndex.first = frameIndex;
			this->frameIndex.second = false;

			safeMutex.ReleaseLock();
		}
		semTaskSignalled.signal();
	}

	void FactionThread::setTaskCompleted(int frameIndex) {
		if (frameIndex >= 0) {
			static string mutexOwnerId =
				string(__FILE__) + string("_") + intToStr(__LINE__);
			MutexSafeWrapper safeMutex(triggerIdMutex, mutexOwnerId);
			if (this->frameIndex.first == frameIndex) {
				this->frameIndex.second = true;
			}
			safeMutex.ReleaseLock();
		}
	}

	bool FactionThread::canShutdown(bool deleteSelfIfShutdownDelayed) {
		bool ret = (getExecutingTask() == false);
		if (ret == false && deleteSelfIfShutdownDelayed == true) {
			setDeleteSelfOnExecutionDone(deleteSelfIfShutdownDelayed);
			deleteSelfIfRequired();
			signalQuit();
		}

		return ret;
	}

	bool FactionThread::isSignalPathfinderCompleted(int frameIndex) {
		if (getRunningStatus() == false) {
			return true;
		}
		static string mutexOwnerId =
			string(__FILE__) + string("_") + intToStr(__LINE__);
		MutexSafeWrapper safeMutex(triggerIdMutex, mutexOwnerId);
		//bool result = (event != NULL ? event->eventCompleted : true);
		bool result = (this->frameIndex.first == frameIndex
			&& this->frameIndex.second == true);

		//if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] worker thread this = %p, this->frameIndex.first = %d, this->frameIndex.second = %d\n",__FILE__,__FUNCTION__,__LINE__,this,this->frameIndex.first,this->frameIndex.second);

		safeMutex.ReleaseLock();
		return result;
	}

	void FactionThread::execute() {
		string codeLocation = "1";
		RunningStatusSafeWrapper runningStatus(this);
		try {
			//setRunningStatus(true);
			if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
				enabled)
				SystemFlags::OutputDebug(SystemFlags::debugSystem,
					"In [%s::%s Line: %d]\n", __FILE__,
					__FUNCTION__, __LINE__);
			if (SystemFlags::VERBOSE_MODE_ENABLED)
				printf
				("In [%s::%s Line: %d] ****************** STARTING worker thread this = %p\n",
					__FILE__, __FUNCTION__, __LINE__, this);

			bool minorDebugPerformance = false;
			Chrono chrono;

			codeLocation = "2";
			//unsigned int idx = 0;
			for (; this->faction != NULL;) {
				if (getQuitStatus() == true) {
					if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
						enabled)
						SystemFlags::OutputDebug(SystemFlags::debugSystem,
							"In [%s::%s Line: %d]\n", __FILE__,
							__FUNCTION__, __LINE__);
					break;
				}

				semTaskSignalled.waitTillSignalled();

				codeLocation = "3";
				//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
				static string masterSlaveOwnerId =
					string(__FILE__) + string("_") + intToStr(__LINE__);
				MasterSlaveThreadControllerSafeWrapper
					safeMasterController(masterController, 20000,
						masterSlaveOwnerId);
				//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);

				if (getQuitStatus() == true) {
					if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
						enabled)
						SystemFlags::OutputDebug(SystemFlags::debugSystem,
							"In [%s::%s Line: %d]\n", __FILE__,
							__FUNCTION__, __LINE__);
					break;
				}

				static string mutexOwnerId =
					string(__FILE__) + string("_") + intToStr(__LINE__);
				MutexSafeWrapper safeMutex(triggerIdMutex, mutexOwnerId);
				bool executeTask = (this->frameIndex.first >= 0);
				int currentTriggeredFrameIndex = this->frameIndex.first;

				//if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] frameIndex = %d this = %p executeTask = %d\n",__FILE__,__FUNCTION__,__LINE__,frameIndex.first, this, executeTask);

				safeMutex.ReleaseLock();

				codeLocation = "5";
				//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);

				if (executeTask == true) {
					codeLocation = "6";
					ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);

					if (this->faction == NULL) {
						throw game_runtime_error("this->faction == NULL");
					}
					World *world = this->faction->getWorld();
					if (world == NULL) {
						throw game_runtime_error("world == NULL");
					}

					codeLocation = "7";
					//Config &config= Config::getInstance();
					//bool sortedUnitsAllowed = config.getBool("AllowGroupedUnitCommands","true");
					//bool sortedUnitsAllowed = false;
					//if(sortedUnitsAllowed == true) {

					/// TODO: Why does this cause and OOS?
					//this->faction->sortUnitsByCommandGroups ();

					//}

					codeLocation = "8";
					static string mutexOwnerId2 =
						string(__FILE__) + string("_") + intToStr(__LINE__);
					MutexSafeWrapper safeMutex(faction->getUnitMutex(),
						mutexOwnerId2);

					//if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
					if (minorDebugPerformance)
						chrono.start();

					//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);

					codeLocation = "9";
					int unitCount = this->faction->getUnitCount();
					for (int j = 0; j < unitCount; ++j) {
						codeLocation = "10";
						Unit *unit = this->faction->getUnit(j);
						if (unit == NULL) {
							throw game_runtime_error("unit == NULL");
						}

						codeLocation = "11";
						int64 elapsed1 = 0;
						if (minorDebugPerformance)
							elapsed1 = chrono.getMillis();

						bool update = unit->needToUpdate();

						codeLocation = "12";
						if (minorDebugPerformance
							&& (chrono.getMillis() - elapsed1) >= 1)
							printf
							("Faction [%d - %s] #1-unit threaded updates on frame: %d for [%d] unit # %d, unitCount = %d, took [%lld] msecs\n",
								faction->getStartLocationIndex(),
								faction->getType()->getName(false).c_str(),
								currentTriggeredFrameIndex,
								faction->getUnitPathfindingListCount(), j, unitCount,
								(long long int) chrono.getMillis() - elapsed1);

						//update = true;
						if (update == true) {
							codeLocation = "13";
							if (SystemFlags::
								getSystemSettingType(SystemFlags::debugWorldSynch).
								enabled == true) {
								int64 updateProgressValue = unit->getUpdateProgress();
								int64 speed =
									unit->getCurrSkill()->getTotalSpeed(unit->
										getTotalUpgrade());
								int64 df = unit->getDiagonalFactor();
								int64 hf = unit->getHeightFactor();
								bool changedActiveCommand = unit->isChangedActiveCommand();

								char szBuf[8096] = "";
								snprintf(szBuf, 8096,
									"unit->needToUpdate() returned: %d updateProgressValue: %lld speed: %lld changedActiveCommand: %d df: %lld hf: %lld",
									update, (long long int) updateProgressValue,
									(long long int) speed, changedActiveCommand,
									(long long int) df, (long long int) hf);
								unit->logSynchDataThreaded(__FILE__, __LINE__, szBuf);
							}

							int64 elapsed2 = 0;
							if (minorDebugPerformance)
								elapsed2 = chrono.getMillis();

							if (world->getUnitUpdater() == NULL) {
								throw
									game_runtime_error
									("world->getUnitUpdater() == NULL");
							}

							world->getUnitUpdater()->updateUnitCommand(unit,
								currentTriggeredFrameIndex);

							codeLocation = "15";
							if (minorDebugPerformance
								&& (chrono.getMillis() - elapsed2) >= 1)
								printf
								("Faction [%d - %s] #2-unit threaded updates on frame: %d for [%d] unit # %d, unitCount = %d, took [%lld] msecs\n",
									faction->getStartLocationIndex(),
									faction->getType()->getName(false).c_str(),
									currentTriggeredFrameIndex,
									faction->getUnitPathfindingListCount(), j, unitCount,
									(long long int) chrono.getMillis() - elapsed2);
						} else {
							codeLocation = "16";
							if (SystemFlags::
								getSystemSettingType(SystemFlags::debugWorldSynch).
								enabled == true) {
								int64 updateProgressValue = unit->getUpdateProgress();
								int64 speed =
									unit->getCurrSkill()->getTotalSpeed(unit->
										getTotalUpgrade());
								int64 df = unit->getDiagonalFactor();
								int64 hf = unit->getHeightFactor();
								bool changedActiveCommand = unit->isChangedActiveCommand();

								char szBuf[8096] = "";
								snprintf(szBuf, 8096,
									"unit->needToUpdate() returned: %d updateProgressValue: %lld speed: %lld changedActiveCommand: %d df: %lld hf: %lld",
									update, (long long int) updateProgressValue,
									(long long int) speed, changedActiveCommand,
									(long long int) df, (long long int) hf);
								unit->logSynchDataThreaded(__FILE__, __LINE__, szBuf);
							}
						}
					}

					codeLocation = "17";
					if (minorDebugPerformance && chrono.getMillis() >= 1)
						printf
						("Faction [%d - %s] threaded updates on frame: %d for [%d] units took [%lld] msecs\n",
							faction->getStartLocationIndex(),
							faction->getType()->getName(false).c_str(),
							currentTriggeredFrameIndex,
							faction->getUnitPathfindingListCount(),
							(long long int) chrono.getMillis());

					//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);

					safeMutex.ReleaseLock();

					codeLocation = "18";
					//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);

					setTaskCompleted(currentTriggeredFrameIndex);

					//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
				}

				//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);

				codeLocation = "19";
				if (getQuitStatus() == true) {
					if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
						enabled)
						SystemFlags::OutputDebug(SystemFlags::debugSystem,
							"In [%s::%s Line: %d]\n", __FILE__,
							__FUNCTION__, __LINE__);
					break;
				}
			}

			if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
				enabled)
				SystemFlags::OutputDebug(SystemFlags::debugSystem,
					"In [%s::%s Line: %d]\n", __FILE__,
					__FUNCTION__, __LINE__);
			if (SystemFlags::VERBOSE_MODE_ENABLED)
				printf
				("In [%s::%s Line: %d] ****************** ENDING worker thread this = %p\n",
					__FILE__, __FUNCTION__, __LINE__, this);
		} catch (const exception & ex) {
			//setRunningStatus(false);

			SystemFlags::OutputDebug(SystemFlags::debugError,
				"In [%s::%s Line: %d] Loc [%s] Error [%s]\n",
				__FILE__, __FUNCTION__, __LINE__,
				codeLocation.c_str(), ex.what());
			if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
				enabled)
				SystemFlags::OutputDebug(SystemFlags::debugSystem,
					"In [%s::%s Line: %d]\n", __FILE__,
					__FUNCTION__, __LINE__);

			throw game_runtime_error(ex.what());
		} catch (...) {
			char szBuf[8096] = "";
			snprintf(szBuf, 8096, "In [%s::%s %d] UNKNOWN error Loc [%s]\n",
				__FILE__, __FUNCTION__, __LINE__, codeLocation.c_str());
			SystemFlags::OutputDebug(SystemFlags::debugError, szBuf);
			throw game_runtime_error(szBuf);
		}

		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s] Line: %d\n", __FILE__,
				__FUNCTION__, __LINE__);
	}


	// =====================================================
	//      class Faction
	// =====================================================

	Faction::Faction() {
		init();
	}

	void Faction::init() {
		unitsMutex = new Mutex(CODE_AT_LINE);
		texture = NULL;
		//lastResourceTargettListPurge = 0;
		cachingDisabled = false;
		factionDisconnectHandled = false;
		workerThread = NULL;

		world = NULL;
		scriptManager = NULL;
		factionType = NULL;
		index = 0;
		teamIndex = 0;
		startLocationIndex = 0;
		thisFaction = false;
		currentSwitchTeamVoteFactionIndex = -1;
		allowSharedTeamUnits = false;

		loadWorldNode = NULL;
		techTree = NULL;

		control = ctClosed;

		overridePersonalityType = fpt_EndCount;

		upgradeManager = UpgradeManager();
	}

	Faction::~Faction() {
		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);

		//Renderer &renderer= Renderer::getInstance();

		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);

		//renderer.endTexture(rsGame,texture);
		//texture->end();
		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);

		if (workerThread != NULL) {
			workerThread->signalQuit();
			if (workerThread->shutdownAndWait() == true) {
				delete workerThread;
			}
			workerThread = NULL;
		}

		MutexSafeWrapper safeMutex(unitsMutex,
			string(__FILE__) + "_" +
			intToStr(__LINE__));
		deleteValues(units.begin(), units.end());
		units.clear();

		safeMutex.ReleaseLock();

		//delete texture;
		texture = NULL;
		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);

		delete unitsMutex;
		unitsMutex = NULL;

		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);
	}

	void Faction::end() {
		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);

		if (workerThread != NULL) {
			workerThread->signalQuit();
			if (workerThread->shutdownAndWait() == true) {
				delete workerThread;
			}
			workerThread = NULL;
		}

		MutexSafeWrapper safeMutex(unitsMutex,
			string(__FILE__) + "_" +
			intToStr(__LINE__));
		deleteValues(units.begin(), units.end());
		units.clear();

		safeMutex.ReleaseLock();

		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);
	}

	void Faction::notifyUnitAliveStatusChange(const Unit * unit) {
		if (unit != NULL) {
			if (unit->isAlive() == true) {
				aliveUnitListCache[unit->getId()] = unit;

				if (unit->getType()->isMobile() == true) {
					mobileUnitListCache[unit->getId()] = unit;
				}
			} else {
				aliveUnitListCache.erase(unit->getId());
				mobileUnitListCache.erase(unit->getId());
				beingBuiltUnitListCache.erase(unit->getId());
			}
		}
	}

	void Faction::notifyUnitTypeChange(const Unit * unit,
		const UnitType * newType) {
		if (unit != NULL) {
			if (unit->getType()->isMobile() == true) {
				mobileUnitListCache.erase(unit->getId());
			}

			if (newType != NULL && newType->isMobile() == true) {
				mobileUnitListCache[unit->getId()] = unit;
			}
		}
	}

	void Faction::notifyUnitSkillTypeChange(const Unit * unit,
		const SkillType * newType) {
		if (unit != NULL) {
			if (unit->isBeingBuilt() == true) {
				beingBuiltUnitListCache.erase(unit->getId());
			}
			if (newType != NULL && newType->getClass() == scBeBuilt) {
				beingBuiltUnitListCache[unit->getId()] = unit;
			}
		}
	}

	bool Faction::hasAliveUnits(bool filterMobileUnits,
		bool filterBuiltUnits) const {
		bool result = false;
		if (aliveUnitListCache.empty() == false) {
			if (filterMobileUnits == true) {
				result = (mobileUnitListCache.empty() == false);
			} else {
				result = true;
			}

			if (result == true && filterBuiltUnits == true) {
				result = (beingBuiltUnitListCache.empty() == true);
			}
		}
		return result;
	}

	FactionPersonalityType Faction::getPersonalityType() const {
		if (overridePersonalityType != fpt_EndCount) {
			return overridePersonalityType;
		}
		return factionType->getPersonalityType();
	}

	int Faction::
		getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type)
		const {
		return factionType->getAIBehaviorStaticOverideValue(type);
	}

	void Faction::addUnitToMovingList(int unitId) {
		unitsMovingList[unitId] = getWorld()->getFrameCount();
	}
	void Faction::removeUnitFromMovingList(int unitId) {
		unitsMovingList.erase(unitId);
	}

	//int Faction::getUnitMovingListCount() {
	//      return (int)unitsMovingList.size();
	//}

	void Faction::addUnitToPathfindingList(int unitId) {
		//printf("ADD (1) Faction [%d - %s] threaded updates for [%d] units\n",this->getStartLocationIndex(),this->getType()->getName().c_str(),unitsPathfindingList.size());
		unitsPathfindingList[unitId] = getWorld()->getFrameCount();
		//printf("ADD (2) Faction [%d - %s] threaded updates for [%d] units\n",this->getStartLocationIndex(),this->getType()->getName().c_str(),unitsPathfindingList.size());
	}
	//void Faction::removeUnitFromPathfindingList(int unitId) {
	//      unitsPathfindingList.erase(unitId);
	//}

	int Faction::getUnitPathfindingListCount() {
		//printf("GET Faction [%d - %s] threaded updates for [%d] units\n",this->getStartLocationIndex(),this->getType()->getName().c_str(),unitsPathfindingList.size());
		return (int) unitsPathfindingList.size();
	}

	void Faction::clearUnitsPathfinding() {
		//printf("CLEAR Faction [%d - %s] threaded updates for [%d] units\n",this->getStartLocationIndex(),this->getType()->getName().c_str(),unitsPathfindingList.size());
		if (unitsPathfindingList.empty() == false) {
			unitsPathfindingList.clear();
		}
	}

	bool Faction::canUnitsPathfind() {
		bool result = true;
		if (control == ctCpuEasy || control == ctCpu ||
			control == ctCpuUltra || control == ctCpuZeta) {
			//printf("AI player for faction index: %d (%s) current pathfinding: %d\n",index,factionType->getName().c_str(),getUnitPathfindingListCount());

			const int MAX_UNITS_PATHFINDING_PER_FRAME = 10;
			result =
				(getUnitPathfindingListCount() <= MAX_UNITS_PATHFINDING_PER_FRAME);
			if (result == false) {
				//printf("WARNING limited AI player for faction index: %d (%s) current pathfinding: %d\n",index,factionType->getName().c_str(),getUnitPathfindingListCount());
			}
		}
		return result;
	}

	void Faction::setLockedUnitForFaction(const UnitType * ut, bool lock) {
		if (lock) {
			lockedUnits.insert(ut);
		} else {
			std::set < const UnitType *>::iterator it;
			it = lockedUnits.find(ut);
			if (it != lockedUnits.end()) {
				lockedUnits.erase(it);
			}
		}

	}

	void Faction::signalWorkerThread(int frameIndex) {
		if (workerThread != NULL) {
			workerThread->signalPathfinder(frameIndex);
		}
	}

	bool Faction::isWorkerThreadSignalCompleted(int frameIndex) {
		if (workerThread != NULL) {
			return workerThread->isSignalPathfinderCompleted(frameIndex);
		}
		return true;
	}


	void Faction::init(FactionType * factionType, ControlType control,
		TechTree * techTree, Game * game, int factionIndex,
		int teamIndex, int startLocationIndex,
		bool thisFaction, bool giveResources,
		const XmlNode * loadWorldNode) {
		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);

		this->techTree = techTree;
		this->loadWorldNode = loadWorldNode;
		this->control = control;
		this->factionType = factionType;
		this->startLocationIndex = startLocationIndex;
		this->index = factionIndex;
		this->teamIndex = teamIndex;
		this->thisFaction = thisFaction;
		this->world = game->getWorld();
		this->scriptManager = game->getScriptManager();
		//cachingDisabled = (Config::getInstance().getBool("DisableCaching","false") == true);
		cachingDisabled = false;

		resources.resize(techTree->getResourceTypeCount());
		store.resize(techTree->getResourceTypeCount());

		if (loadWorldNode == NULL) {
			for (int index = 0; index < techTree->getResourceTypeCount();
				++index) {
				const ResourceType *rt = techTree->getResourceType(index);
				int resourceAmount =
					giveResources ? factionType->getStartingResourceAmount(rt) : 0;
				resources[index].init(rt, resourceAmount);
				store[index].init(rt, 0);

				this->world->initTeamResource(rt, this->teamIndex, 0);
			}
		}
		//initialize cache
		for (int index = 0; index < techTree->getResourceTypeCount(); ++index) {
			const ResourceType *rt = techTree->getResourceType(index);
			this->updateUnitTypeWithResourceCostCache(rt);
		}

		texture = Renderer::getInstance().newTexture2D(rsGame);
		string data_path =
			getGameReadWritePath(GameConstants::path_data_CacheLookupKey);
		if (texture) {
			string playerTexture =
				getGameCustomCoreDataPath(data_path,
					"data/core/faction_textures/faction" +
					intToStr(startLocationIndex) + ".tga");
			texture->load(playerTexture);
		}

		if (loadWorldNode != NULL) {
			loadGame(loadWorldNode, this->index, game->getGameSettings(),
				game->getWorld());
		}

		if (game->getGameSettings()->getPathFinderType() == pfBasic) {
			if (workerThread != NULL) {
				workerThread->signalQuit();
				if (workerThread->shutdownAndWait() == true) {
					delete workerThread;
				}
				workerThread = NULL;
			}
			static string mutexOwnerId =
				string(extractFileFromDirectoryPath(__FILE__).c_str()) +
				string("_") + intToStr(__LINE__);
			this->workerThread = new FactionThread(this);
			this->workerThread->setUniqueID(mutexOwnerId);
			this->workerThread->start();
		}

		if (SystemFlags::getSystemSettingType(SystemFlags::debugSystem).
			enabled)
			SystemFlags::OutputDebug(SystemFlags::debugSystem,
				"In [%s::%s Line: %d]\n", __FILE__,
				__FUNCTION__, __LINE__);
	}

	// ================== get ==================

	bool Faction::hasUnitTypeWithResourceCostInCache(const ResourceType * rt) const {
		std::string resourceTypeName = rt->getName(false);
		std::map < std::string, bool >::const_iterator iterFind =
			resourceTypeCostCache.find(resourceTypeName);
		if (iterFind != resourceTypeCostCache.end()) {
			return iterFind->second;
		}
		return false;
	}
	void Faction::updateUnitTypeWithResourceCostCache(const ResourceType *
		rt) {
		std::string resourceTypeName = rt->getName(false);

		if (resourceTypeCostCache.find(resourceTypeName) ==
			resourceTypeCostCache.end()) {
			resourceTypeCostCache[resourceTypeName] =
				hasUnitTypeWithResouceCost(rt);
		}
	}

	bool Faction::hasUnitTypeWithResouceCost(const ResourceType * rt) {
		for (int factionUnitTypeIndex = 0;
			factionUnitTypeIndex < getType()->getUnitTypeCount();
			++factionUnitTypeIndex) {

			const UnitType *ut = getType()->getUnitType(factionUnitTypeIndex);
			if (ut->getCost(rt) != NULL) {
				return true;
			}
		}
		return false;
	}

	const Resource *Faction::getResource(const ResourceType * rt,
		bool localFactionOnly) const {

		if (localFactionOnly == false &&
			world != NULL && world->getGame() != NULL) {

			Game *game = world->getGame();
			if (game->isFlagType1BitEnabled(ft1_allow_shared_team_resources) ==
				true) {
				return world->getResourceForTeam(rt, this->getTeam());
			}
		}

		for (int index = 0; index < (int) resources.size(); ++index) {
			if (rt == resources[index].getType()) {
				return &resources[index];
			}
		}

		printf("ERROR cannot find resource type [%s] in list:\n",
			(rt != NULL ? rt->getName().c_str() : "null"));
		for (int i = 0; i < (int) resources.size(); ++i) {
			printf("Index %d [%s]", i,
				resources[i].getType()->getName().c_str());
		}

		assert(false);
		return NULL;
	}

	int Faction::getStoreAmount(const ResourceType * rt,
		bool localFactionOnly) const {

		if (localFactionOnly == false &&
			world != NULL && world->getGame() != NULL) {

			Game *game = world->getGame();
			if (game->isFlagType1BitEnabled(ft1_allow_shared_team_resources) ==
				true) {
				return world->getStoreAmountForTeam(rt, this->getTeam());
			}
		}

		for (int index = 0; index < (int) store.size(); ++index) {
			if (rt == store[index].getType()) {
				return store[index].getAmount();
			}
		}
		printf("ERROR cannot find store type [%s] in list:\n",
			(rt != NULL ? rt->getName().c_str() : "null"));
		for (int i = 0; i < (int) store.size(); ++i) {
			printf("Index %d [%s]", i, store[i].getType()->getName().c_str());
		}

		assert(false);
		return 0;
	}

	bool Faction::getCpuControl(bool enableServerControlledAI, bool isNetworkGame, NetworkRole role) const {
		return getCpuControl();
	}

	bool Faction::getCpuControl() const {
		return control == ctCpuEasy || control == ctCpu || control == ctCpuUltra
			|| control == ctCpuZeta;
	}

	// ==================== upgrade manager ====================

	void Faction::startUpgrade(const UpgradeType * ut) {
		upgradeManager.startUpgrade(ut, index);
	}

	void Faction::cancelUpgrade(const UpgradeType * ut) {
		upgradeManager.cancelUpgrade(ut);
	}

	void Faction::finishUpgrade(const UpgradeType * ut) {
		upgradeManager.finishUpgrade(ut);
		if (world->getThisFaction() != NULL
			&& this->getIndex() == world->getThisFaction()->getIndex()) {
			Console *console = world->getGame()->getConsole();
			console->addStdMessage("UpgradeFinished",
				": " + formatString(ut->getName(true)));
		}
		for (int i = 0; i < getUnitCount(); ++i) {
			getUnit(i)->applyUpgrade(ut);
		}
	}

	// ==================== reqs ====================

	//checks if all required units and upgrades are present and maxUnitCount is within limit
	bool Faction::reqsOk(const RequirableType * rt) const {
		assert(rt != NULL);
		//required units
		for (int i = 0; i < rt->getUnitReqCount(); ++i) {
			bool found = false;
			for (int j = 0; j < getUnitCount(); ++j) {
				Unit *unit = getUnit(j);
				const UnitType *ut = unit->getType();
				if (rt->getUnitReq(i) == ut && unit->isOperative()) {
					found = true;
					break;
				}
			}
			if (found == false) {
				if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).
					enabled)
					SystemFlags::OutputDebug(SystemFlags::debugLUA,
						"In [%s::%s Line: %d]\n", __FILE__,
						__FUNCTION__, __LINE__);
				return false;
			}
		}

		//required upgrades
		for (int i = 0; i < rt->getUpgradeReqCount(); ++i) {
			if (upgradeManager.isUpgraded(rt->getUpgradeReq(i)) == false) {
				if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).
					enabled)
					SystemFlags::OutputDebug(SystemFlags::debugLUA,
						"In [%s::%s Line: %d]\n", __FILE__,
						__FUNCTION__, __LINE__);
				return false;
			}
		}

		//required resources
		for (int i = 0; i < rt->getCostCount(); i++) {
			const ResourceType *resource = rt->getCost(i)->getType();
			int cost = rt->getCost(i)->getAmount();
			if (cost > 0) {
				int available = getResource(resource)->getAmount();
				if (cost > available) {
					return false;
				}
			}
		}

		if (dynamic_cast <const UnitType *>(rt) != NULL) {
			const UnitType *producedUnitType =
				dynamic_cast <const UnitType *>(rt);
			if (producedUnitType != NULL
				&& producedUnitType->getMaxUnitCount() > 0) {
				if (producedUnitType->getMaxUnitCount() <=
					getCountForMaxUnitCount(producedUnitType)) {
					if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).
						enabled)
						SystemFlags::OutputDebug(SystemFlags::debugLUA,
							"In [%s::%s Line: %d]\n", __FILE__,
							__FUNCTION__, __LINE__);
					return false;
				}
			}

			if (producedUnitType != NULL && isUnitLocked(producedUnitType)) {
				return false;
			}
		}

		return true;
	}

	int Faction::getCountForMaxUnitCount(const UnitType * unitType) const {
		int count = 0;
		//calculate current unit count
		for (int j = 0; j < getUnitCount(); ++j) {
			Unit *unit = getUnit(j);
			const UnitType *currentUt = unit->getType();
			if (unitType == currentUt && unit->isOperative()) {
				count++;
			}
			//check if there is any command active which already produces this unit
			count = count + unit->getCountOfProducedUnits(unitType);
		}
		return count;
	}


	bool Faction::reqsOk(const CommandType * ct) const {
		assert(ct != NULL);
		if (ct == NULL) {
			throw game_runtime_error("In [Faction::reqsOk] ct == NULL");
		}

		if (ct->getProduced() != NULL && reqsOk(ct->getProduced()) == false) {
			if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled)
				SystemFlags::OutputDebug(SystemFlags::debugLUA,
					"In [%s::%s Line: %d] reqsOk FAILED\n",
					__FILE__, __FUNCTION__, __LINE__);
			return false;
		}

		if (ct->getClass() == ccUpgrade) {
			const UpgradeCommandType *uct =
				static_cast <const UpgradeCommandType *>(ct);
			if (upgradeManager.isUpgradingOrUpgraded(uct->getProducedUpgrade())) {
				if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).
					enabled)
					SystemFlags::OutputDebug(SystemFlags::debugLUA,
						"In [%s::%s Line: %d] upgrade check FAILED\n",
						__FILE__, __FUNCTION__, __LINE__);
				return false;
			}
		}

		return reqsOk(static_cast <const RequirableType *>(ct));
	}

	// ================== cost application ==================

	//apply costs except static production (start building/production)
	bool Faction::applyCosts(const ProducibleType * p,
		const CommandType * ct) {
		bool ignoreResourceCosts = false;
		if (ct != NULL && ct->getClass() == ccMorph) {
			const MorphCommandType *mct =
				dynamic_cast <const MorphCommandType *>(ct);
			if (mct != NULL) {
				ignoreResourceCosts = mct->getIgnoreResourceRequirements();
			}
		}

		if (ignoreResourceCosts == false) {
			if (checkCosts(p, ct) == false) {
				return false;
			}

			assert(p != NULL);
			//for each unit cost spend it
			//pass 2, decrease resources, except negative static costs (ie: farms)
			for (int i = 0; i < p->getCostCount(); ++i) {
				const Resource *r = p->getCost(i);
				if (r == NULL) {
					char szBuf[8096] = "";
					snprintf(szBuf, 8096,
						"cannot apply costs for p [%s] %d of %d costs resource is null",
						p->getName(false).c_str(), i, p->getCostCount());
					throw game_runtime_error(szBuf);
				}

				const ResourceType *rt = r->getType();
				if (rt == NULL) {
					char szBuf[8096] = "";
					snprintf(szBuf, 8096,
						"cannot apply costs for p [%s] %d of %d costs resourcetype [%s] is null",
						p->getName(false).c_str(), i, p->getCostCount(),
						r->getDescription(false).c_str());
					throw game_runtime_error(szBuf);
				}
				int cost = r->getAmount();
				if ((cost > 0 || (rt->getClass() != rcStatic))
					&& rt->getClass() != rcConsumable) {
					incResourceAmount(rt, -(cost));
				}

			}
		}
		return true;
	}

	//apply discount (when a morph ends)
	void Faction::applyDiscount(const ProducibleType * p, int discount) {
		assert(p != NULL);
		//increase resources
		for (int i = 0; i < p->getCostCount(); ++i) {
			const ResourceType *rt = p->getCost(i)->getType();
			assert(rt != NULL);
			int cost = p->getCost(i)->getAmount();
			if ((cost > 0 || (rt->getClass() != rcStatic))
				&& rt->getClass() != rcConsumable) {
				incResourceAmount(rt, cost * discount / 100);
			}
		}
	}

	//apply static production (for starting units)
	void Faction::applyStaticCosts(const ProducibleType * p,
		const CommandType * ct) {
		assert(p != NULL);
		bool ignoreResourceCosts = false;
		if (ct != NULL && ct->getClass() == ccMorph) {
			const MorphCommandType *mct =
				dynamic_cast <const MorphCommandType *>(ct);
			if (mct != NULL) {
				ignoreResourceCosts = mct->getIgnoreResourceRequirements();
			}
		}

		if (ignoreResourceCosts == false) {
			//decrease static resources
			for (int i = 0; i < p->getCostCount(); ++i) {
				const ResourceType *rt = p->getCost(i)->getType();
				//assert(rt != NULL);
				if (rt == NULL) {
					throw game_runtime_error(string(__FUNCTION__) +
						" rt == NULL for ProducibleType ["
						+ p->getName(false) +
						"] index: " + intToStr(i));
				}
				if (rt->getClass() == rcStatic) {
					int cost = p->getCost(i)->getAmount();
					if (cost > 0) {
						incResourceAmount(rt, -cost);
					}
				}
			}
		}
	}

	//apply static production (when a mana source is done)
	void Faction::applyStaticProduction(const ProducibleType * p,
		const CommandType * ct) {
		assert(p != NULL);

		bool ignoreResourceCosts = false;
		if (ct != NULL && ct->getClass() == ccMorph) {
			const MorphCommandType *mct =
				dynamic_cast <const MorphCommandType *>(ct);
			if (mct != NULL) {
				ignoreResourceCosts = mct->getIgnoreResourceRequirements();
			}
		}

		if (ignoreResourceCosts == false) {
			//decrease static resources
			for (int i = 0; i < p->getCostCount(); ++i) {
				const ResourceType *rt = p->getCost(i)->getType();
				assert(rt != NULL);
				if (rt->getClass() == rcStatic) {
					int cost = p->getCost(i)->getAmount();
					if (cost < 0) {
						incResourceAmount(rt, -cost);
					}
				}
			}
		}
	}

	//deapply all costs except static production (usually when a building is cancelled)
	void Faction::deApplyCosts(const ProducibleType * p,
		const CommandType * ct) {
		assert(p != NULL);

		bool ignoreResourceCosts = false;
		if (ct != NULL && ct->getClass() == ccMorph) {
			const MorphCommandType *mct =
				dynamic_cast <const MorphCommandType *>(ct);
			if (mct != NULL) {
				ignoreResourceCosts = mct->getIgnoreResourceRequirements();
			}
		}

		if (ignoreResourceCosts == false) {
			//increase resources
			for (int i = 0; i < p->getCostCount(); ++i) {
				const ResourceType *rt = p->getCost(i)->getType();
				assert(rt != NULL);
				int cost = p->getCost(i)->getAmount();
				if ((cost > 0 || (rt->getClass() != rcStatic))
					&& rt->getClass() != rcConsumable) {
					incResourceAmount(rt, cost);
				}
			}
		}
	}

	//deapply static costs (usually when a unit dies)
	void Faction::deApplyStaticCosts(const ProducibleType * p,
		const CommandType * ct) {
		assert(p != NULL);

		bool ignoreResourceCosts = false;
		if (ct != NULL && ct->getClass() == ccMorph) {
			const MorphCommandType *mct =
				dynamic_cast <const MorphCommandType *>(ct);
			if (mct != NULL) {
				ignoreResourceCosts = mct->getIgnoreResourceRequirements();
			}
		}

		if (ignoreResourceCosts == false) {
			//decrease resources
			for (int i = 0; i < p->getCostCount(); ++i) {
				const ResourceType *rt = p->getCost(i)->getType();
				assert(rt != NULL);
				if (rt->getClass() == rcStatic) {
					if (rt->getRecoup_cost() == true) {
						int cost = p->getCost(i)->getAmount();
						incResourceAmount(rt, cost);
					}
				}
			}
		}
	}

	//deapply static costs, but not negative costs, for when building gets killed
	void Faction::deApplyStaticConsumption(const ProducibleType * p,
		const CommandType * ct) {
		assert(p != NULL);

		bool ignoreResourceCosts = false;
		if (ct != NULL && ct->getClass() == ccMorph) {
			const MorphCommandType *mct =
				dynamic_cast <const MorphCommandType *>(ct);
			if (mct != NULL) {
				ignoreResourceCosts = mct->getIgnoreResourceRequirements();
			}
		}

		if (ignoreResourceCosts == false) {
			//decrease resources
			for (int i = 0; i < p->getCostCount(); ++i) {
				const ResourceType *rt = p->getCost(i)->getType();
				assert(rt != NULL);
				if (rt->getClass() == rcStatic) {
					int cost = p->getCost(i)->getAmount();
					if (cost > 0) {
						incResourceAmount(rt, cost);
					}
				}
			}
		}
	}

	//apply resource on interval (cosumable resouces)
	void Faction::applyCostsOnInterval(const ResourceType * rtApply) {

		// For each Resource type we store in the int a total consumed value, then
		// a vector of units that consume the resource type
		std::map < const ResourceType *, std::pair < int,
			std::vector <Unit *> > >resourceIntervalUsage;

		// count up consumables usage for the interval
		for (int j = 0; j < getUnitCount(); ++j) {
			Unit *unit = getUnit(j);
			if (unit->isOperative() == true) {
				for (int k = 0; k < unit->getType()->getCostCount(); ++k) {
					const Resource *resource = unit->getType()->getCost(k);
					if (resource->getType() == rtApply
						&& resource->getType()->getClass() == rcConsumable
						&& resource->getAmount() != 0) {
						if (resourceIntervalUsage.find(resource->getType()) ==
							resourceIntervalUsage.end()) {
							resourceIntervalUsage[resource->getType()] =
								make_pair < int, std::vector <Unit *> >(0,
									std::vector <
									Unit * >());
						}
						// Negative cost means accumulate the resource type
						resourceIntervalUsage[resource->getType()].first +=
							-resource->getAmount();

						// If the cost > 0 then the unit is a consumer
						if (resource->getAmount() > 0) {
							resourceIntervalUsage[resource->getType()].second.
								push_back(unit);
						}
					}
				}
			}
		}

		// Apply consumable resource usage
		if (resourceIntervalUsage.empty() == false) {
			for (std::map < const ResourceType *, std::pair < int,
				std::vector < Unit * > > >::iterator iter =
				resourceIntervalUsage.begin();
				iter != resourceIntervalUsage.end(); ++iter) {
				// Apply resource type usage to faction resource store
				const ResourceType *rt = iter->first;
				int resourceTypeUsage = iter->second.first;
				incResourceAmount(rt, resourceTypeUsage);

				// Check if we have any unit consumers
				if (getResource(rt)->getAmount() < 0) {
					resetResourceAmount(rt);

					// Apply consequences to consumer units of this resource type
					std::vector < Unit * >&resourceConsumers = iter->second.second;

					for (int i = 0; i < (int) resourceConsumers.size(); ++i) {
						Unit *unit = resourceConsumers[i];

						//decrease unit hp
						if (scriptManager->getPlayerModifiers(this->index)->
							getConsumeEnabled() == true) {
							bool decHpResult =
								unit->decHp(unit->getType()->
									getTotalMaxHp(unit->getTotalUpgrade()) / 3);
							if (decHpResult) {
								unit->setCauseOfDeath(ucodStarvedResource);
								world->getStats()->die(unit->getFactionIndex(),
									unit->getType()->
									getCountUnitDeathInStats());
								scriptManager->onUnitDied(unit);
							}
							StaticSound *sound =
								static_cast <
								const DieSkillType *
								>(unit->getType()->getFirstStOfClass(scDie))->getSound();
							if (sound != NULL
								&& (thisFaction == true
									|| world->showWorldForPlayer(world->
										getThisTeamIndex()) ==
									true)) {
								SoundRenderer::getInstance().playFx(sound);
							}
						}
					}
				}
			}
		}
	}

	bool Faction::checkCosts(const ProducibleType * pt,
		const CommandType * ct) {
		assert(pt != NULL);

		bool ignoreResourceCosts = false;
		if (ct != NULL && ct->getClass() == ccMorph) {
			const MorphCommandType *mct =
				dynamic_cast <const MorphCommandType *>(ct);
			if (mct != NULL) {
				ignoreResourceCosts = mct->getIgnoreResourceRequirements();
			}
			//printf("Checking costs = %d for commandtype:\n%s\n",ignoreResourceCosts,mct->getDesc(NULL).c_str());
		}

		if (ignoreResourceCosts == false) {
			//for each unit cost check if enough resources
			for (int i = 0; i < pt->getCostCount(); ++i) {
				const ResourceType *rt = pt->getCost(i)->getType();
				int cost = pt->getCost(i)->getAmount();
				if (cost > 0) {
					int available = getResource(rt)->getAmount();
					if (cost > available) {
						return false;
					}
				}
			}
		}

		return true;
	}

	// ================== diplomacy ==================

	bool Faction::isAlly(const Faction * faction) {
		assert(faction != NULL);
		return (teamIndex == faction->getTeam() ||
			faction->getTeam() ==
			GameConstants::maxPlayers - 1 + fpt_Observer);
	}

	// ================== misc ==================

	void Faction::incResourceAmount(const ResourceType * rt, int amount) {
		if (world != NULL && world->getGame() != NULL
			&& world->getGame()->
			isFlagType1BitEnabled(ft1_allow_shared_team_resources) == true) {
			for (int i = 0; i < (int) resources.size(); ++i) {
				Resource *r = &resources[i];
				if (r->getType() == rt) {
					r->setAmount(r->getAmount() + amount);
					if (r->getType()->getClass() != rcStatic
						&& (getResource(rt, false)->getAmount() + amount) >
						getStoreAmount(rt, false)) {
						r->setAmount(getStoreAmount(rt, false) -
							(getResource(rt, false)->getAmount() -
								r->getAmount()));
					}
					return;
				}
			}
		} else {
			for (int i = 0; i < (int) resources.size(); ++i) {
				Resource *r = &resources[i];
				if (r->getType() == rt) {
					r->setAmount(r->getAmount() + amount);
					if (r->getType()->getClass() != rcStatic
						&& r->getAmount() > getStoreAmount(rt)) {
						r->setAmount(getStoreAmount(rt));
					}
					return;
				}
			}
		}
		assert(false);
	}

	void Faction::setResourceBalance(const ResourceType * rt, int balance) {
		for (int i = 0; i < (int) resources.size(); ++i) {
			Resource *r = &resources[i];
			if (r->getType() == rt) {
				r->setBalance(balance);
				return;
			}
		}
		assert(false);
	}

	Unit *Faction::findUnit(int id) const {
		UnitMap::const_iterator itFound = unitMap.find(id);
		if (itFound == unitMap.end()) {
			return NULL;
		}
		return itFound->second;
	}

	void Faction::addUnit(Unit * unit) {
		MutexSafeWrapper safeMutex(unitsMutex,
			string(__FILE__) + "_" +
			intToStr(__LINE__));
		units.push_back(unit);
		unitMap[unit->getId()] = unit;
	}

	void Faction::removeUnit(Unit * unit) {
		MutexSafeWrapper safeMutex(unitsMutex,
			string(__FILE__) + "_" +
			intToStr(__LINE__));

		assert(units.size() == unitMap.size());

		int unitId = unit->getId();
		for (int i = 0; i < (int) units.size(); ++i) {
			if (units[i]->getId() == unitId) {
				units.erase(units.begin() + i);
				unitMap.erase(unitId);
				assert(units.size() == unitMap.size());
				return;
			}
		}

		throw game_runtime_error("Could not remove unit from faction!");
		//assert(false);
	}

	void Faction::addStore(const UnitType * unitType) {
		assert(unitType != NULL);
		for (int newUnitStoredResourceIndex = 0;
			newUnitStoredResourceIndex < unitType->getStoredResourceCount();
			++newUnitStoredResourceIndex) {
			const Resource *newUnitStoredResource =
				unitType->getStoredResource(newUnitStoredResourceIndex);

			for (int currentStoredResourceIndex = 0;
				currentStoredResourceIndex < (int) store.size();
				++currentStoredResourceIndex) {
				Resource *storedResource = &store[currentStoredResourceIndex];

				if (storedResource->getType() == newUnitStoredResource->getType()) {
					storedResource->setAmount(storedResource->getAmount() +
						newUnitStoredResource->getAmount());
				}
			}
		}
	}

	void Faction::removeStore(const UnitType * unitType) {
		assert(unitType != NULL);
		for (int i = 0; i < unitType->getStoredResourceCount(); ++i) {
			const Resource *r = unitType->getStoredResource(i);
			for (int j = 0; j < (int) store.size(); ++j) {
				Resource *storedResource = &store[j];
				if (storedResource->getType() == r->getType()) {
					storedResource->setAmount(storedResource->getAmount() -
						r->getAmount());
				}
			}
		}
		limitResourcesToStore();
	}

	void Faction::limitResourcesToStore() {
		if (world != NULL && world->getGame() != NULL
			&& world->getGame()->
			isFlagType1BitEnabled(ft1_allow_shared_team_resources) == true) {
			for (int i = 0; i < (int) resources.size(); ++i) {
				Resource *r = &resources[i];
				const ResourceType *rt = r->getType();
				if (rt->getClass() != rcStatic
					&& (getResource(rt, false)->getAmount()) > getStoreAmount(rt,
						false)) {
					r->setAmount(getStoreAmount(rt, false) -
						(getResource(rt, false)->getAmount() -
							r->getAmount()));
				}
			}
		} else {
			for (int i = 0; i < (int) resources.size(); ++i) {
				Resource *r = &resources[i];
				Resource *s = &store[i];
				if (r->getType()->getClass() != rcStatic
					&& r->getAmount() > s->getAmount()) {
					r->setAmount(s->getAmount());
				}
			}
		}
	}

	void Faction::resetResourceAmount(const ResourceType * rt) {
		for (int i = 0; i < (int) resources.size(); ++i) {
			if (resources[i].getType() == rt) {
				resources[i].setAmount(0);
				return;
			}
		}
		assert(false);
	}

	bool Faction::isResourceTargetInCache(const Vec2i & pos,
		bool incrementUseCounter) {
		bool result = false;

		if (cachingDisabled == false) {
			if (cacheResourceTargetList.empty() == false) {
				std::map < Vec2i, int >::iterator iter =
					cacheResourceTargetList.find(pos);

				result = (iter != cacheResourceTargetList.end());
				if (result == true && incrementUseCounter == true) {
					iter->second++;
				}
			}
		}

		return result;
	}

	void Faction::addResourceTargetToCache(const Vec2i & pos,
		bool incrementUseCounter) {
		if (cachingDisabled == false) {

			bool duplicateEntry =
				isResourceTargetInCache(pos, incrementUseCounter);
			//bool duplicateEntry = false;

			if (duplicateEntry == false) {
				cacheResourceTargetList[pos] = 1;

				if (SystemFlags::
					getSystemSettingType(SystemFlags::debugWorldSynch).enabled ==
					true) {
					char szBuf[8096] = "";
					snprintf(szBuf, 8096,
						"[addResourceTargetToCache] pos [%s]cacheResourceTargetList.size() ["
						SIZE_T_SPECIFIER "]", pos.getString().c_str(),
						cacheResourceTargetList.size());

					//unit->logSynchData(szBuf);
					SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,
						"----------------------------------- START [%d] ------------------------------------------------\n",
						getFrameCount());
					SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,
						"[%s::%d]\n",
						extractFileFromDirectoryPath(__FILE__).
						c_str(), __LINE__);
					SystemFlags::OutputDebug(SystemFlags::debugWorldSynch, "%s\n",
						szBuf);
					SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,
						"------------------------------------ END [%d] -------------------------------------------------\n",
						getFrameCount());
				}
			}
		}
	}

	void Faction::removeResourceTargetFromCache(const Vec2i & pos) {
		if (cachingDisabled == false) {
			if (cacheResourceTargetList.empty() == false) {
				std::map < Vec2i, int >::iterator iter =
					cacheResourceTargetList.find(pos);

				if (iter != cacheResourceTargetList.end()) {
					cacheResourceTargetList.erase(pos);

					if (SystemFlags::
						getSystemSettingType(SystemFlags::debugWorldSynch).enabled ==
						true) {
						char szBuf[8096] = "";
						snprintf(szBuf, 8096,
							"[removeResourceTargetFromCache] pos [%s]cacheResourceTargetList.size() ["
							SIZE_T_SPECIFIER "]", pos.getString().c_str(),
							cacheResourceTargetList.size());

						//unit->logSynchData(szBuf);
						SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,
							"----------------------------------- START [%d] ------------------------------------------------\n",
							getFrameCount());
						SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,
							"[%s::%d]\n",
							extractFileFromDirectoryPath
							(__FILE__).c_str(), __LINE__);
						SystemFlags::OutputDebug(SystemFlags::debugWorldSynch, "%s\n",
							szBuf);
						SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,
							"------------------------------------ END [%d] -------------------------------------------------\n",
							getFrameCount());
					}
				}
			}
		}
	}

	void Faction::addCloseResourceTargetToCache(const Vec2i & pos) {
		if (cachingDisabled == false) {
			if (cachedCloseResourceTargetLookupList.find(pos) ==
				cachedCloseResourceTargetLookupList.end()) {
				const Map *map = world->getMap();
				const int harvestDistance = 5;

				for (int j = -harvestDistance; j <= harvestDistance; ++j) {
					for (int k = -harvestDistance; k <= harvestDistance; ++k) {
						Vec2i newPos = pos + Vec2i(j, k);
						if (isResourceTargetInCache(newPos) == false) {
							if (map->isInside(newPos.x, newPos.y)) {
								Resource *r =
									map->getSurfaceCell(map->toSurfCoords(newPos))->
									getResource();
								if (r != NULL) {
									addResourceTargetToCache(newPos);
									//cacheResourceTargetList[newPos] = 1;
								}
							}
						}
					}
				}

				cachedCloseResourceTargetLookupList[pos] = true;
			}
		}
	}

	Vec2i Faction::getClosestResourceTypeTargetFromCache(Unit * unit,
		const ResourceType *
		type,
		int frameIndex) {
		Vec2i result(-1);

		if (cachingDisabled == false) {
			if (cacheResourceTargetList.empty() == false) {
				if (SystemFlags::
					getSystemSettingType(SystemFlags::debugWorldSynch).enabled ==
					true) {
					char szBuf[8096] = "";
					snprintf(szBuf, 8096,
						"cacheResourceTargetList.size() [" SIZE_T_SPECIFIER
						"]", cacheResourceTargetList.size());

					if (frameIndex < 0) {
						unit->logSynchData(__FILE__, __LINE__, szBuf);
					} else {
						unit->logSynchDataThreaded(__FILE__, __LINE__, szBuf);
					}
				}


				std::vector < Vec2i > deleteList;

				const int harvestDistance = 5;
				const Map *map = world->getMap();
				Vec2i pos = unit->getPos();

				bool foundCloseResource = false;
				// First look immediately around the unit's position

				// 0 means start looking leftbottom to top right
		//                      if(Thread::isCurrentThreadMainThread() == false) {
		//                              throw game_runtime_error("#1 Invalid access to Faction random from outside main thread current id = " +
		//                                              intToStr(Thread::getCurrentThreadId()) + " main = " + intToStr(Thread::getMainThreadId()));
		//                      }
				int tryRadius = random.randRange(0, 1);
				//int tryRadius = unit->getRandom(true)->randRange(0,1);
				//int tryRadius = 0;
				if (tryRadius == 0) {
					for (int j = -harvestDistance;
						j <= harvestDistance && foundCloseResource == false; ++j) {
						for (int k = -harvestDistance;
							k <= harvestDistance && foundCloseResource == false; ++k) {
							Vec2i newPos = pos + Vec2i(j, k);
							if (map->isInside(newPos) == true
								&& isResourceTargetInCache(newPos) == false) {
								const SurfaceCell *sc =
									map->getSurfaceCell(map->toSurfCoords(newPos));
								if (sc != NULL && sc->getResource() != NULL) {
									const Resource *resource = sc->getResource();
									if (resource->getType() != NULL
										&& resource->getType() == type) {
										if (result.x < 0
											|| unit->getPos().dist(newPos) <
											unit->getPos().dist(result)) {
											if (unit->isBadHarvestPos(newPos) == false) {
												result = newPos;
												foundCloseResource = true;
												break;
											}
										}
									}
								} else {
									deleteList.push_back(newPos);
								}
							}
						}
					}
				}
				// start looking topright to leftbottom
				else {
					for (int j = harvestDistance;
						j >= -harvestDistance && foundCloseResource == false; --j) {
						for (int k = harvestDistance;
							k >= -harvestDistance && foundCloseResource == false; --k) {
							Vec2i newPos = pos + Vec2i(j, k);
							if (map->isInside(newPos) == true
								&& isResourceTargetInCache(newPos) == false) {
								const SurfaceCell *sc =
									map->getSurfaceCell(map->toSurfCoords(newPos));
								if (sc != NULL && sc->getResource() != NULL) {
									const Resource *resource = sc->getResource();
									if (resource->getType() != NULL
										&& resource->getType() == type) {
										if (result.x < 0
											|| unit->getPos().dist(newPos) <
											unit->getPos().dist(result)) {
											if (unit->isBadHarvestPos(newPos) == false) {
												result = newPos;
												foundCloseResource = true;
												break;
											}
										}
									}
								} else {
									deleteList.push_back(newPos);
								}
							}
						}
					}
				}

				if (foundCloseResource == false) {
					// Now check the whole cache
					for (std::map < Vec2i, int >::iterator iter =
						cacheResourceTargetList.begin();
						iter != cacheResourceTargetList.end()
						&& foundCloseResource == false; ++iter) {
						const Vec2i & cache = iter->first;
						if (map->isInside(cache) == true) {
							const SurfaceCell *sc =
								map->getSurfaceCell(map->toSurfCoords(cache));
							if (sc != NULL && sc->getResource() != NULL) {
								const Resource *resource = sc->getResource();
								if (resource->getType() != NULL
									&& resource->getType() == type) {
									if (result.x < 0
										|| unit->getPos().dist(cache) <
										unit->getPos().dist(result)) {
										if (unit->isBadHarvestPos(cache) == false) {
											result = cache;
											// Close enough to our position, no more looking
											if (unit->getPos().dist(result) <=
												(harvestDistance * 2)) {
												foundCloseResource = true;
												break;
											}
										}
									}
								}
							} else {
								deleteList.push_back(cache);
							}
						} else {
							deleteList.push_back(cache);
						}
					}
				}

				if (deleteList.empty() == false) {
					if (SystemFlags::
						getSystemSettingType(SystemFlags::debugWorldSynch).enabled ==
						true) {
						char szBuf[8096] = "";
						snprintf(szBuf, 8096,
							"[cleaning old resource targets] deleteList.size() ["
							SIZE_T_SPECIFIER
							"] cacheResourceTargetList.size() ["
							SIZE_T_SPECIFIER "] result [%s]",
							deleteList.size(), cacheResourceTargetList.size(),
							result.getString().c_str());

						if (frameIndex < 0) {
							unit->logSynchData(__FILE__, __LINE__, szBuf);
						} else {
							unit->logSynchDataThreaded(__FILE__, __LINE__, szBuf);
						}
					}

					cleanupResourceTypeTargetCache(&deleteList, frameIndex);
				}
			}
		}

		return result;
	}

	// CANNOT MODIFY the cache here since the AI calls this method and the AI is only controlled
	// by the server for network games and it would cause out of synch since clients do not call
	// this method so DO NOT modify the cache here!
	Vec2i Faction::getClosestResourceTypeTargetFromCache(const Vec2i & pos,
		const ResourceType *
		type) {
		Vec2i result(-1);
		if (cachingDisabled == false) {
			if (cacheResourceTargetList.empty() == false) {
				//std::vector<Vec2i> deleteList;

				const int harvestDistance = 5;
				const Map *map = world->getMap();

				bool foundCloseResource = false;

				// 0 means start looking leftbottom to top right
		//                      if(Thread::isCurrentThreadMainThread() == false) {
		//                              throw game_runtime_error("#2 Invalid access to Faction random from outside main thread current id = " +
		//                                              intToStr(Thread::getCurrentThreadId()) + " main = " + intToStr(Thread::getMainThreadId()));
		//                      }
				int tryRadius = random.randRange(0, 1);
				if (tryRadius == 0) {
					// First look immediately around the given position
					for (int j = -harvestDistance;
						j <= harvestDistance && foundCloseResource == false; ++j) {
						for (int k = -harvestDistance;
							k <= harvestDistance && foundCloseResource == false; ++k) {
							Vec2i newPos = pos + Vec2i(j, k);
							if (map->isInside(newPos) == true
								&& isResourceTargetInCache(newPos) == false) {
								const SurfaceCell *sc =
									map->getSurfaceCell(map->toSurfCoords(newPos));
								if (sc != NULL && sc->getResource() != NULL) {
									const Resource *resource = sc->getResource();
									if (resource->getType() != NULL
										&& resource->getType() == type) {
										if (result.x < 0
											|| pos.dist(newPos) < pos.dist(result)) {
											result = newPos;
											foundCloseResource = true;
											break;
										}
									}
								}
								//else {
								//      deleteList.push_back(newPos);
								//}
							}
						}
					}
				} else {
					// First look immediately around the given position
					for (int j = harvestDistance;
						j >= -harvestDistance && foundCloseResource == false; --j) {
						for (int k = harvestDistance;
							k >= -harvestDistance && foundCloseResource == false; --k) {
							Vec2i newPos = pos + Vec2i(j, k);
							if (map->isInside(newPos) == true
								&& isResourceTargetInCache(newPos) == false) {
								const SurfaceCell *sc =
									map->getSurfaceCell(map->toSurfCoords(newPos));
								if (sc != NULL && sc->getResource() != NULL) {
									const Resource *resource = sc->getResource();
									if (resource->getType() != NULL
										&& resource->getType() == type) {
										if (result.x < 0
											|| pos.dist(newPos) < pos.dist(result)) {
											result = newPos;
											foundCloseResource = true;
											break;
										}
									}
								}
								//else {
								//      deleteList.push_back(newPos);
								//}
							}
						}
					}
				}

				if (foundCloseResource == false) {
					// Now check the whole cache
					for (std::map < Vec2i, int >::iterator iter =
						cacheResourceTargetList.begin();
						iter != cacheResourceTargetList.end()
						&& foundCloseResource == false; ++iter) {
						const Vec2i & cache = iter->first;
						if (map->isInside(cache) == true) {
							const SurfaceCell *sc =
								map->getSurfaceCell(map->toSurfCoords(cache));
							if (sc != NULL && sc->getResource() != NULL) {
								const Resource *resource = sc->getResource();
								if (resource->getType() != NULL
									&& resource->getType() == type) {
									if (result.x < 0 || pos.dist(cache) < pos.dist(result)) {
										result = cache;
										// Close enough to our position, no more looking
										if (pos.dist(result) <= (harvestDistance * 2)) {
											foundCloseResource = true;
											break;
										}
									}
								}
							}
							//else {
							//      deleteList.push_back(cache);
							//}
						}
						//else {
						//      deleteList.push_back(cache);
						//}
					}
				}
			}
		}

		return result;
	}

	void Faction::cleanupResourceTypeTargetCache(std::vector < Vec2i >
		*deleteListPtr,
		int frameIndex) {
		if (cachingDisabled == false) {
			if (cacheResourceTargetList.empty() == false) {
				const int cleanupInterval = (GameConstants::updateFps * 5);
				bool needToCleanup = (getFrameCount() % cleanupInterval == 0);

				if (deleteListPtr != NULL || needToCleanup == true) {
					std::vector < Vec2i > deleteList;

					if (deleteListPtr != NULL) {
						deleteList = *deleteListPtr;
					} else {
						for (std::map < Vec2i, int >::iterator iter =
							cacheResourceTargetList.begin();
							iter != cacheResourceTargetList.end(); ++iter) {
							const Vec2i & cache = iter->first;

							if (world->getMap()->
								getSurfaceCell(world->getMap()->toSurfCoords(cache)) !=
								NULL) {
								Resource *resource =
									world->getMap()->getSurfaceCell(world->getMap()->
										toSurfCoords(cache))->
									getResource();
								if (resource == NULL) {
									deleteList.push_back(cache);
								}
							} else {
								deleteList.push_back(cache);
							}
						}
					}

					if (deleteList.empty() == false) {
						if (SystemFlags::
							getSystemSettingType(SystemFlags::debugWorldSynch).
							enabled == true) {
							char szBuf[8096] = "";
							snprintf(szBuf, 8096,
								"[cleaning old resource targets] deleteList.size() ["
								SIZE_T_SPECIFIER
								"] cacheResourceTargetList.size() ["
								SIZE_T_SPECIFIER "], needToCleanup [%d]",
								deleteList.size(), cacheResourceTargetList.size(),
								needToCleanup);
							//unit->logSynchData(szBuf);

							string logDataText = "----------------------------------- START [" + to_string(getFrameCount()) +
								"] ------------------------------------------------\n";

							logDataText += "[" + extractFileFromDirectoryPath(__FILE__) + "::" + to_string(__LINE__) + "]\n";
							logDataText += szBuf;
							logDataText += "\n";

							logDataText += "------------------------------------ END [" + to_string(getFrameCount()) + "] -------------------------------------------------\n";

							if (frameIndex < 0) {
								SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,
									"%s", logDataText.c_str());
							} else {
								addWorldSynchThreadedLogList(logDataText);
							}
						}

						for (int i = 0; i < (int) deleteList.size(); ++i) {
							Vec2i & cache = deleteList[i];
							cacheResourceTargetList.erase(cache);
						}
					}
				}
			}
		}
	}

	//std::vector<Vec2i> Faction::findCachedPath(const Vec2i &target, Unit *unit) {
	//      std::vector<Vec2i> result;
	//      if(cachingDisabled == false) {
	//              if(successfulPathFinderTargetList.find(target) == successfulPathFinderTargetList.end()) {
	//                      // Lets find the shortest and most successful path already taken by a
	//                      // similar sized unit
	//
	//                      bool foundCachedPath = false;
	//                      std::vector<FactionPathSuccessCache> &cacheList = successfulPathFinderTargetList[target];
	//                      int unitSize = unit->getType()->getSize();
	//                      for(int i = 0; i < cacheList.size(); ++i) {
	//                              FactionPathSuccessCache &cache = cacheList[i];
	//                              if(cache.unitSize <= unitSize) {
	//                                      vector<std::pair<vector<Vec2i>, int> > &pathQueue = cache.pathQueue;
	//
	//                                      for(int j = 0; j < pathQueue.size(); ++j) {
	//                                              // Now start at the end of the path and see how many nodes
	//                                              // until we reach a cell near the unit's current position
	//                                              std::pair<vector<Vec2i>, int> &path = pathQueue[j];
	//
	//                                              for(int k = path.first.size() - 1; k >= 0; --k) {
	//                                                      if(world->getMap()->canMove(unit, unit->getPos(), path.first[k]) == true) {
	//                                                              if(foundCachedPath == false) {
	//                                                                      for(int l = k; l < path.first.size(); ++l) {
	//                                                                              result.push_back(path.first[l]);
	//                                                                      }
	//                                                              }
	//                                                              else {
	//                                                                      if(result.size() > (path.first.size() - k)) {
	//                                                                              for(int l = k; l < path.first.size(); ++l) {
	//                                                                                      result.push_back(path.first[l]);
	//                                                                              }
	//                                                                      }
	//                                                              }
	//                                                              foundCachedPath = true;
	//
	//                                                              break;
	//                                                      }
	//                                              }
	//                                      }
	//                              }
	//                      }
	//              }
	//      }
	//
	//      return result;
	//}

	//void Faction::addCachedPath(const Vec2i &target, Unit *unit) {
	//      if(cachingDisabled == false) {
	//              if(successfulPathFinderTargetList.find(target) == successfulPathFinderTargetList.end()) {
	//                      FactionPathSuccessCache cache;
	//                      cache.unitSize = unit->getType()->getSize();
	//                      cache.pathQueue.push_back(make_pair<vector<Vec2i>, int>(unit->getCurrentTargetPathTaken().second,1));
	//                      successfulPathFinderTargetList[target].push_back(cache);
	//              }
	//              else {
	//                      bool finishedAdd = false;
	//                      std::pair<Vec2i,std::vector<Vec2i> > currentTargetPathTaken = unit->getCurrentTargetPathTaken();
	//                      std::vector<FactionPathSuccessCache> &cacheList = successfulPathFinderTargetList[target];
	//                      int unitSize = unit->getType()->getSize();
	//
	//                      for(int i = 0; i < cacheList.size() && finishedAdd == false; ++i) {
	//                              FactionPathSuccessCache &cache = cacheList[i];
	//                              if(cache.unitSize <= unitSize) {
	//                                      vector<std::pair<vector<Vec2i>, int> > &pathQueue = cache.pathQueue;
	//
	//                                      for(int j = 0; j < pathQueue.size() && finishedAdd == false; ++j) {
	//                                              // Now start at the end of the path and see how many nodes are the same
	//                                              std::pair<vector<Vec2i>, int> &path = pathQueue[j];
	//                                              int minPathSize = std::min(path.first.size(),currentTargetPathTaken.second.size());
	//                                              int intersectIndex = -1;
	//
	//                                              for(int k = 0; k < minPathSize; ++k) {
	//                                                      if(path.first[path.first.size() - k - 1] != currentTargetPathTaken.second[currentTargetPathTaken.second.size() - k - 1]) {
	//                                                              intersectIndex = k;
	//                                                              break;
	//                                                      }
	//                                              }
	//
	//                                              // New path is same or longer than old path so replace
	//                                              // old path with new
	//                                              if(intersectIndex + 1 == path.first.size()) {
	//                                                      path.first = currentTargetPathTaken.second;
	//                                                      path.second++;
	//                                                      finishedAdd = true;
	//                                              }
	//                                              // Old path is same or longer than new path so
	//                                              // do nothing
	//                                              else if(intersectIndex + 1 == currentTargetPathTaken.second.size()) {
	//                                                      path.second++;
	//                                                      finishedAdd = true;
	//                                              }
	//                                      }
	//
	//                                      // If new path is >= 10 cells add it
	//                                      if(finishedAdd == false && currentTargetPathTaken.second.size() >= 10) {
	//                                              pathQueue.push_back(make_pair<vector<Vec2i>, int>(currentTargetPathTaken.second,1));
	//                                      }
	//                              }
	//                      }
	//              }
	//      }
	//}

	void Faction::deletePixels() {
		if (factionType != NULL) {
			factionType->deletePixels();
		}
	}

	//Unit * Faction::findClosestUnitWithSkillClass(        const Vec2i &pos,const CommandClass &cmdClass,
	//                                                                                              const std::vector<SkillClass> &skillClassList,
	//                                                                                              const UnitType *unitType) {
	//      Unit *result = NULL;
	//
	///*
	//      std::map<CommandClass,std::map<int,int> >::iterator iterFind = cacheUnitCommandClassList.find(cmdClass);
	//      if(iterFind != cacheUnitCommandClassList.end()) {
	//              for(std::map<int,int>::iterator iter = iterFind->second.begin();
	//                              iter != iterFind->second.end(); ++iter) {
	//                      Unit *curUnit = findUnit(iter->second);
	//                      if(curUnit != NULL) {
	//
	//                              const CommandType *cmdType = curUnit->getType()->getFirstCtOfClass(cmdClass);
	//                              bool isUnitPossibleCandidate = (cmdType != NULL);
	//                              if(skillClassList.empty() == false) {
	//                                      isUnitPossibleCandidate = false;
	//
	//                                      for(int j = 0; j < skillClassList.size(); ++j) {
	//                                              SkillClass skValue = skillClassList[j];
	//                                              if(curUnit->getCurrSkill()->getClass() == skValue) {
	//                                                      isUnitPossibleCandidate = true;
	//                                                      break;
	//                                              }
	//                                      }
	//                              }
	//
	//                              if(isUnitPossibleCandidate == true) {
	//                                      if(result == NULL || curUnit->getPos().dist(pos) < result->getPos().dist(pos)) {
	//                                              result = curUnit;
	//                                      }
	//                              }
	//                      }
	//              }
	//      }
	//*/
	//
	//      //if(result == NULL) {
	//              for(int i = 0; i < getUnitCount(); ++i) {
	//                      Unit *curUnit = getUnit(i);
	//
	//                      bool isUnitPossibleCandidate = false;
	//
	//                      const CommandType *cmdType = curUnit->getType()->getFirstCtOfClass(cmdClass);
	//                      if(cmdType != NULL) {
	//                              const RepairCommandType *rct = dynamic_cast<const RepairCommandType *>(cmdType);
	//                              if(rct != NULL && rct->isRepairableUnitType(unitType)) {
	//                                      isUnitPossibleCandidate = true;
	//                              }
	//                      }
	//                      else {
	//                              isUnitPossibleCandidate = false;
	//                      }
	//
	//                      if(isUnitPossibleCandidate == true && skillClassList.empty() == false) {
	//                              isUnitPossibleCandidate = false;
	//
	//                              for(int j = 0; j < (int)skillClassList.size(); ++j) {
	//                                      SkillClass skValue = skillClassList[j];
	//                                      if(curUnit->getCurrSkill()->getClass() == skValue) {
	//                                              isUnitPossibleCandidate = true;
	//                                              break;
	//                                      }
	//                              }
	//                      }
	//
	//
	//                      if(isUnitPossibleCandidate == true) {
	//                              //cacheUnitCommandClassList[cmdClass][curUnit->getId()] = curUnit->getId();
	//
	//                              if(result == NULL || curUnit->getPos().dist(pos) < result->getPos().dist(pos)) {
	//                                      result = curUnit;
	//                              }
	//                      }
	//              }
	//      //}
	//      return result;
	//}

	int Faction::getFrameCount() {
		int frameCount = 0;
		const Game *game = Renderer::getInstance().getGame();
		if (game != NULL && game->getWorld() != NULL) {
			frameCount = game->getWorld()->getFrameCount();
		}

		return frameCount;
	}

	const SwitchTeamVote *Faction::getFirstSwitchTeamVote() const {
		const SwitchTeamVote *vote = NULL;
		if (switchTeamVotes.empty() == false) {
			for (std::map < int, SwitchTeamVote >::const_iterator iterMap =
				switchTeamVotes.begin(); iterMap != switchTeamVotes.end();
				++iterMap) {
				const SwitchTeamVote & curVote = iterMap->second;
				if (curVote.voted == false) {
					vote = &curVote;
					break;
				}
			}
		}

		return vote;
	}

	SwitchTeamVote *Faction::getSwitchTeamVote(int factionIndex) {
		SwitchTeamVote *vote = NULL;
		if (switchTeamVotes.find(factionIndex) != switchTeamVotes.end()) {
			vote = &switchTeamVotes[factionIndex];
		}

		return vote;
	}

	void Faction::setSwitchTeamVote(SwitchTeamVote & vote) {
		switchTeamVotes[vote.factionIndex] = vote;
	}

	bool Faction::canCreateUnit(const UnitType * ut, bool checkBuild,
		bool checkProduce, bool checkMorph) const {
		// Now check that at least 1 other unit can produce, build or morph this unit
		bool foundUnit = false;
		for (int l = 0; l < this->getUnitCount() && foundUnit == false; ++l) {
			const UnitType *unitType2 = this->getUnit(l)->getType();

			for (int j = 0;
				j < unitType2->getCommandTypeCount() && foundUnit == false; ++j) {
				const CommandType *cmdType = unitType2->getCommandType(j);
				if (cmdType != NULL) {
					// Check if this is a produce command
					if (checkProduce == true && cmdType->getClass() == ccProduce) {
						const ProduceCommandType *produce =
							dynamic_cast <const ProduceCommandType *>(cmdType);
						if (produce != NULL) {
							const UnitType *produceUnit = produce->getProducedUnit();

							if (produceUnit != NULL &&
								ut->getId() != unitType2->getId() &&
								ut->getName(false) == produceUnit->getName(false)) {
								foundUnit = true;
								break;
							}
						}
					}
					// Check if this is a build command
					else if (checkBuild == true && cmdType->getClass() == ccBuild) {
						const BuildCommandType *build =
							dynamic_cast <const BuildCommandType *>(cmdType);
						if (build != NULL) {
							for (int k = 0;
								k < build->getBuildingCount() && foundUnit == false;
								++k) {
								const UnitType *buildUnit = build->getBuilding(k);

								if (buildUnit != NULL &&
									ut->getId() != unitType2->getId() &&
									ut->getName(false) == buildUnit->getName(false)) {
									foundUnit = true;
									break;
								}
							}
						}
					}
					// Check if this is a morph command
					else if (checkMorph == true && cmdType->getClass() == ccMorph) {
						const MorphCommandType *morph =
							dynamic_cast <const MorphCommandType *>(cmdType);
						if (morph != NULL) {
							const UnitType *morphUnit = morph->getMorphUnit();

							if (morphUnit != NULL &&
								ut->getId() != unitType2->getId() &&
								ut->getName(false) == morphUnit->getName(false)) {
								foundUnit = true;
								break;
							}
						}
					}
				}
			}
		}

		return foundUnit;
	}

	void Faction::clearCaches() {
		cacheResourceTargetList.clear();
		cachedCloseResourceTargetLookupList.clear();

		//aliveUnitListCache.clear();
		//mobileUnitListCache.clear();
		//beingBuiltUnitListCache.clear();

		unsigned int unitCount = this->getUnitCount();
		for (unsigned int i = 0; i < unitCount; ++i) {
			Unit *unit = this->getUnit(i);
			if (unit != NULL) {
				unit->clearCaches();
			}
		}
	}

	uint64 Faction::getCacheKBytes(uint64 * cache1Size, uint64 * cache2Size,
		uint64 * cache3Size, uint64 * cache4Size,
		uint64 * cache5Size) {
		uint64 cache1Count = 0;
		uint64 cache2Count = 0;
		uint64 cache3Count = 0;
		uint64 cache4Count = 0;
		uint64 cache5Count = 0;

		for (std::map < Vec2i, int >::iterator iterMap1 =
			cacheResourceTargetList.begin();
			iterMap1 != cacheResourceTargetList.end(); ++iterMap1) {
			cache1Count++;
		}
		for (std::map < Vec2i, bool >::iterator iterMap1 =
			cachedCloseResourceTargetLookupList.begin();
			iterMap1 != cachedCloseResourceTargetLookupList.end(); ++iterMap1) {
			cache2Count++;
		}
		for (std::map < int, const Unit * >::iterator iterMap1 =
			aliveUnitListCache.begin(); iterMap1 != aliveUnitListCache.end();
			++iterMap1) {
			cache3Count++;
		}
		for (std::map < int, const Unit * >::iterator iterMap1 =
			mobileUnitListCache.begin();
			iterMap1 != mobileUnitListCache.end(); ++iterMap1) {
			cache4Count++;
		}
		for (std::map < int, const Unit * >::iterator iterMap1 =
			beingBuiltUnitListCache.begin();
			iterMap1 != beingBuiltUnitListCache.end(); ++iterMap1) {
			cache5Count++;
		}

		if (cache1Size) {
			*cache1Size = cache1Count;
		}
		if (cache2Size) {
			*cache2Size = cache2Count;
		}
		if (cache3Size) {
			*cache3Size = cache3Count;
		}
		if (cache4Size) {
			*cache4Size = cache4Count;
		}
		if (cache5Size) {
			*cache5Size = cache5Count;
		}

		uint64 totalBytes = cache1Count * sizeof(int);
		totalBytes += cache2Count * sizeof(bool);
		totalBytes += cache3Count * (sizeof(int) + sizeof(const Unit *));
		totalBytes += cache4Count * (sizeof(int) + sizeof(const Unit *));
		totalBytes += cache5Count * (sizeof(int) + sizeof(const Unit *));

		totalBytes /= 1000;

		return totalBytes;
	}

	string Faction::getCacheStats() {
		string result = "";

		int cache1Count = 0;
		int cache2Count = 0;

		for (std::map < Vec2i, int >::iterator iterMap1 =
			cacheResourceTargetList.begin();
			iterMap1 != cacheResourceTargetList.end(); ++iterMap1) {
			cache1Count++;
		}
		for (std::map < Vec2i, bool >::iterator iterMap1 =
			cachedCloseResourceTargetLookupList.begin();
			iterMap1 != cachedCloseResourceTargetLookupList.end(); ++iterMap1) {
			cache2Count++;
		}

		uint64 totalBytes = cache1Count * sizeof(int);
		totalBytes += cache2Count * sizeof(bool);

		totalBytes /= 1000;

		char szBuf[8096] = "";
		snprintf(szBuf, 8096, "cache1Count [%d] cache2Count [%d] total KB: %s",
			cache1Count, cache2Count, formatNumber(totalBytes).c_str());
		result = szBuf;
		return result;
	}

	std::string Faction::toString(bool crcMode) const {
		std::string result = "FactionIndex = " + intToStr(this->index) + "\n";
		result += "teamIndex = " + intToStr(this->teamIndex) + "\n";
		result +=
			"startLocationIndex = " + intToStr(this->startLocationIndex) + "\n";
		if (crcMode == false) {
			result += "thisFaction = " + intToStr(this->thisFaction) + "\n";
			result += "control = " + intToStr(this->control) + "\n";
		}

		if (this->factionType != NULL) {
			result += this->factionType->toString() + "\n";
		}

		result += this->upgradeManager.toString() + "\n";

		result += "ResourceCount = " + intToStr(resources.size()) + "\n";
		for (int idx = 0; idx < (int) resources.size(); idx++) {
			result +=
				"index = " + intToStr(idx) + " " + resources[idx].toString() +
				"\n";
		}

		result += "StoreCount = " + intToStr(store.size()) + "\n";
		for (int idx = 0; idx < (int) store.size(); idx++) {
			result +=
				"index = " + intToStr(idx) + " " + store[idx].toString() + "\n";
		}

		result += "Allies = " + intToStr(allies.size()) + "\n";
		for (int idx = 0; idx < (int) allies.size(); idx++) {
			result +=
				"index = " + intToStr(idx) + " name: " +
				allies[idx]->factionType->getName(false) + " factionindex = " +
				intToStr(allies[idx]->index) + "\n";
		}

		result += "Units = " + intToStr(units.size()) + "\n";
		for (int idx = 0; idx < (int) units.size(); idx++) {
			result += units[idx]->toString(crcMode) + "\n";
		}

		return result;
	}

	void Faction::saveGame(XmlNode * rootNode) {
		std::map < string, string > mapTagReplacements;
		XmlNode *factionNode = rootNode->addChild("Faction");

		upgradeManager.saveGame(factionNode);
		for (unsigned int i = 0; i < resources.size(); ++i) {
			Resource & resource = resources[i];
			resource.saveGame(factionNode);
		}
		XmlNode *storeNode = factionNode->addChild("Store");
		for (unsigned int i = 0; i < store.size(); ++i) {
			Resource & resource = store[i];
			resource.saveGame(storeNode);
		}

		for (unsigned int i = 0; i < allies.size(); ++i) {
			Faction *ally = allies[i];
			XmlNode *allyNode = factionNode->addChild("Ally");
			allyNode->addAttribute("allyFactionIndex",
				intToStr(ally->getIndex()),
				mapTagReplacements);
		}
		for (unsigned int i = 0; i < units.size(); ++i) {
			Unit *unit = units[i];
			unit->saveGame(factionNode);
		}

		factionNode->addAttribute("control", intToStr(control),
			mapTagReplacements);

		factionNode->addAttribute("overridePersonalityType",
			intToStr(overridePersonalityType),
			mapTagReplacements);
		factionNode->addAttribute("factiontype", factionType->getName(false),
			mapTagReplacements);
		factionNode->addAttribute("index", intToStr(index),
			mapTagReplacements);
		factionNode->addAttribute("teamIndex", intToStr(teamIndex),
			mapTagReplacements);
		factionNode->addAttribute("startLocationIndex",
			intToStr(startLocationIndex),
			mapTagReplacements);
		factionNode->addAttribute("thisFaction", intToStr(thisFaction),
			mapTagReplacements);

		for (std::map < Vec2i, int >::iterator iterMap =
			cacheResourceTargetList.begin();
			iterMap != cacheResourceTargetList.end(); ++iterMap) {
			XmlNode *cacheResourceTargetListNode =
				factionNode->addChild("cacheResourceTargetList");

			cacheResourceTargetListNode->addAttribute("key",
				iterMap->first.
				getString(),
				mapTagReplacements);
			cacheResourceTargetListNode->addAttribute("value",
				intToStr(iterMap->second),
				mapTagReplacements);
		}

		for (std::map < Vec2i, bool >::iterator iterMap =
			cachedCloseResourceTargetLookupList.begin();
			iterMap != cachedCloseResourceTargetLookupList.end(); ++iterMap) {
			XmlNode *cachedCloseResourceTargetLookupListNode =
				factionNode->addChild("cachedCloseResourceTargetLookupList");

			cachedCloseResourceTargetLookupListNode->addAttribute("key",
				iterMap->first.
				getString(),
				mapTagReplacements);
			cachedCloseResourceTargetLookupListNode->addAttribute("value",
				intToStr
				(iterMap->
					second),
				mapTagReplacements);
		}

		factionNode->addAttribute("random", intToStr(random.getLastNumber()),
			mapTagReplacements);
		factionNode->addAttribute("currentSwitchTeamVoteFactionIndex",
			intToStr(currentSwitchTeamVoteFactionIndex),
			mapTagReplacements);
		factionNode->addAttribute("allowSharedTeamUnits",
			intToStr(allowSharedTeamUnits),
			mapTagReplacements);

		for (std::set < const UnitType * >::iterator iterMap =
			lockedUnits.begin(); iterMap != lockedUnits.end(); ++iterMap) {
			XmlNode *lockedUnitsListNode =
				factionNode->addChild("lockedUnitList");
			const UnitType *ut = *iterMap;

			lockedUnitsListNode->addAttribute("value", ut->getName(false),
				mapTagReplacements);
		}

		for (std::map < int, int >::iterator iterMap = unitsMovingList.begin();
			iterMap != unitsMovingList.end(); ++iterMap) {
			XmlNode *unitsMovingListNode =
				factionNode->addChild("unitsMovingList");

			unitsMovingListNode->addAttribute("key", intToStr(iterMap->first),
				mapTagReplacements);
			unitsMovingListNode->addAttribute("value",
				intToStr(iterMap->second),
				mapTagReplacements);
		}

		for (std::map < int, int >::iterator iterMap =
			unitsPathfindingList.begin();
			iterMap != unitsPathfindingList.end(); ++iterMap) {
			XmlNode *unitsPathfindingListNode =
				factionNode->addChild("unitsPathfindingList");

			unitsPathfindingListNode->addAttribute("key",
				intToStr(iterMap->first),
				mapTagReplacements);
			unitsPathfindingListNode->addAttribute("value",
				intToStr(iterMap->second),
				mapTagReplacements);
		}
	}

	void Faction::loadGame(const XmlNode * rootNode, int factionIndex,
		GameSettings * settings, World * world) {
		XmlNode *factionNode = NULL;
		vector < XmlNode * >factionNodeList =
			rootNode->getChildList("Faction");
		for (unsigned int i = 0; i < factionNodeList.size(); ++i) {
			XmlNode *node = factionNodeList[i];
			if (node->getAttribute("index")->getIntValue() == factionIndex) {
				factionNode = node;
				break;
			}
		}

		if (factionNode != NULL) {

			allies.clear();
			vector < XmlNode * >allyNodeList = factionNode->getChildList("Ally");
			for (unsigned int i = 0; i < allyNodeList.size(); ++i) {
				XmlNode *allyNode = allyNodeList[i];

				int allyFactionIndex =
					allyNode->getAttribute("allyFactionIndex")->getIntValue();
				allies.push_back(world->getFaction(allyFactionIndex));
			}

			vector < XmlNode * >unitNodeList = factionNode->getChildList("Unit");
			for (unsigned int i = 0; i < unitNodeList.size(); ++i) {
				XmlNode *unitNode = unitNodeList[i];
				Unit *unit = Unit::loadGame(unitNode, settings, this, world);
				this->addUnit(unit);
			}

			for (unsigned int i = 0; i < resources.size(); ++i) {
				Resource & resource = resources[i];
				resource.loadGame(factionNode, i, techTree);
			}
			XmlNode *storeNode = factionNode->getChild("Store");
			for (unsigned int i = 0; i < store.size(); ++i) {
				Resource & resource = store[i];
				resource.loadGame(storeNode, i, techTree);
			}

			upgradeManager.loadGame(factionNode, this);

			control =
				static_cast <ControlType>
				(factionNode->getAttribute("control")->getIntValue());

			if (factionNode->hasAttribute("overridePersonalityType") == true) {
				overridePersonalityType =
					static_cast <FactionPersonalityType>
					(factionNode->getAttribute("overridePersonalityType")->
						getIntValue());
			}

			teamIndex = factionNode->getAttribute("teamIndex")->getIntValue();

			startLocationIndex =
				factionNode->getAttribute("startLocationIndex")->getIntValue();

			thisFaction =
				factionNode->getAttribute("thisFaction")->getIntValue() != 0;

			if (factionNode->hasAttribute("allowSharedTeamUnits") == true) {
				allowSharedTeamUnits =
					factionNode->getAttribute("allowSharedTeamUnits")->
					getIntValue() != 0;
			}

			vector < XmlNode * >cacheResourceTargetListNodeList =
				factionNode->getChildList("cacheResourceTargetList");
			for (unsigned int i = 0; i < cacheResourceTargetListNodeList.size();
				++i) {
				XmlNode *cacheResourceTargetListNode =
					cacheResourceTargetListNodeList[i];

				Vec2i vec =
					Vec2i::strToVec2(cacheResourceTargetListNode->
						getAttribute("key")->getValue());
				cacheResourceTargetList[vec] =
					cacheResourceTargetListNode->getAttribute("value")->
					getIntValue();
			}
			vector < XmlNode * >cachedCloseResourceTargetLookupListNodeList =
				factionNode->getChildList("cachedCloseResourceTargetLookupList");
			for (unsigned int i = 0;
				i < cachedCloseResourceTargetLookupListNodeList.size(); ++i) {
				XmlNode *cachedCloseResourceTargetLookupListNode =
					cachedCloseResourceTargetLookupListNodeList[i];

				Vec2i vec =
					Vec2i::strToVec2(cachedCloseResourceTargetLookupListNode->
						getAttribute("key")->getValue());
				cachedCloseResourceTargetLookupList[vec] =
					cachedCloseResourceTargetLookupListNode->getAttribute("value")->
					getIntValue() != 0;
			}

			random.setLastNumber(factionNode->getAttribute("random")->
				getIntValue());

			vector < XmlNode * >lockedUnitsListNodeList =
				factionNode->getChildList("lockedUnitList");
			for (unsigned int i = 0; i < lockedUnitsListNodeList.size(); ++i) {
				XmlNode *lockedUnitsListNode = lockedUnitsListNodeList[i];

				string unitName =
					lockedUnitsListNode->getAttribute("value")->getValue();
				lockedUnits.insert(getType()->getUnitType(unitName));
			}

			vector < XmlNode * >unitsMovingListNodeList =
				factionNode->getChildList("unitsMovingList");
			for (unsigned int i = 0; i < unitsMovingListNodeList.size(); ++i) {
				XmlNode *unitsMovingListNode = unitsMovingListNodeList[i];

				int unitId =
					unitsMovingListNode->getAttribute("key")->getIntValue();
				unitsMovingList[unitId] =
					unitsMovingListNode->getAttribute("value")->getIntValue();
			}
			vector < XmlNode * >unitsPathfindingListNodeList =
				factionNode->getChildList("unitsPathfindingList");
			for (unsigned int i = 0; i < unitsPathfindingListNodeList.size();
				++i) {
				XmlNode *unitsPathfindingListNode = unitsPathfindingListNodeList[i];

				int unitId =
					unitsPathfindingListNode->getAttribute("key")->getIntValue();
				unitsPathfindingList[unitId] =
					unitsPathfindingListNode->getAttribute("value")->getIntValue();
			}
		}
	}

	Checksum Faction::getCRC() {
		const bool consoleDebug = false;

		Checksum crcForFaction;

		// UpgradeManager upgradeManager;

		for (unsigned int i = 0; i < resources.size(); ++i) {
			Resource & resource = resources[i];
			//crcForFaction.addSum(resource.getCRC().getSum());
			uint32 crc = resource.getCRC().getSum();
			crcForFaction.addBytes(&crc, sizeof(uint32));
		}

		if (consoleDebug) {
			if (getWorld()->getFrameCount() % 40 == 0) {
				printf("#1 Frame #: %d Faction: %d CRC: %u\n",
					getWorld()->getFrameCount(), index,
					crcForFaction.getSum());
			}
		}

		for (unsigned int i = 0; i < store.size(); ++i) {
			Resource & resource = store[i];
			//crcForFaction.addSum(resource.getCRC().getSum());
			uint32 crc = resource.getCRC().getSum();
			crcForFaction.addBytes(&crc, sizeof(uint32));
		}

		if (consoleDebug) {
			if (getWorld()->getFrameCount() % 40 == 0) {
				printf("#2 Frame #: %d Faction: %d CRC: %u\n",
					getWorld()->getFrameCount(), index,
					crcForFaction.getSum());
			}
		}

		for (unsigned int i = 0; i < units.size(); ++i) {
			Unit *unit = units[i];
			//crcForFaction.addSum(unit->getCRC().getSum());
			uint32 crc = unit->getCRC().getSum();
			crcForFaction.addBytes(&crc, sizeof(uint32));
		}

		if (consoleDebug) {
			if (getWorld()->getFrameCount() % 40 == 0) {
				printf("#3 Frame #: %d Faction: %d CRC: %u\n",
					getWorld()->getFrameCount(), index,
					crcForFaction.getSum());
			}
		}

		return crcForFaction;
	}

	void Faction::addCRC_DetailsForWorldFrame(int worldFrameCount,
		bool isNetworkServer) {
		unsigned int MAX_FRAME_CACHE = 250;
		if (isNetworkServer == true) {
			MAX_FRAME_CACHE += 250;
		}
		crcWorldFrameDetails[worldFrameCount] = this->toString(true);
		//if(worldFrameCount <= 0) printf("Adding world frame: %d log entries: %lld\n",worldFrameCount,(long long int)crcWorldFrameDetails.size());

		for (unsigned int i = 0; i < units.size(); ++i) {
			Unit *unit = units[i];

			unit->getRandom()->clearLastCaller();
			unit->clearNetworkCRCDecHpList();
			unit->clearParticleInfo();
		}

		if ((unsigned int) crcWorldFrameDetails.size() > MAX_FRAME_CACHE) {
			//printf("===> Removing older world frame log entries: %lld\n",(long long int)crcWorldFrameDetails.size());

			for (;
				(unsigned int) crcWorldFrameDetails.size() - MAX_FRAME_CACHE >
				0;) {
				crcWorldFrameDetails.erase(crcWorldFrameDetails.begin());
			}
		}
	}

	string Faction::getCRC_DetailsForWorldFrame(int worldFrameCount) {
		if (crcWorldFrameDetails.empty()) {
			return "";
		}
		return crcWorldFrameDetails[worldFrameCount];
	}

	std::pair < int,
		string >
		Faction::getCRC_DetailsForWorldFrameIndex(int worldFrameIndex) const {
		if (crcWorldFrameDetails.empty()) {
			return make_pair < int, string >(0, "");
		}
		std::map < int, string >::const_iterator iterMap =
			crcWorldFrameDetails.begin();
		std::advance(iterMap, worldFrameIndex);
		if (iterMap == crcWorldFrameDetails.end()) {
			return make_pair < int, string >(0, "");
		}
		return std::pair < int, string >(iterMap->first, iterMap->second);
	}

	string Faction::getCRC_DetailsForWorldFrames() const {
		string result = "";
		for (std::map < int, string >::const_iterator iterMap =
			crcWorldFrameDetails.begin();
			iterMap != crcWorldFrameDetails.end(); ++iterMap) {
			result +=
				string
				("============================================================================\n");
			result +=
				string("** world frame: ") + intToStr(iterMap->first) +
				string(" detail: ") + iterMap->second;
		}
		return result;
	}

	uint64 Faction::getCRC_DetailsForWorldFrameCount() const {
		return crcWorldFrameDetails.size();
	}

} //end namespace
