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

#include "server_interface.h"

#include <stdexcept>

#include "window.h"
#include "logger.h"

#include "platform_util.h"
#include "conversion.h"
#include "config.h"
#include "lang.h"
#include "util.h"
#include "game_util.h"
#include "miniftpserver.h"
#include "map_preview.h"
#include "stats.h"
#include <time.h>
#include <set>
#include <iostream>
#include <iterator>

#include "leak_dumper.h"

using namespace std;
using namespace Shared::Platform;
using namespace Shared::Util;
using namespace Shared::Map;

namespace Glest { namespace Game {

double maxFrameCountLagAllowed 								= 30;
double maxClientLagTimeAllowed 								= 25;
double maxFrameCountLagAllowedEver 							= 30;
double maxClientLagTimeAllowedEver							= 25;

double warnFrameCountLagPercent 							= 0.50;
double LAG_CHECK_GRACE_PERIOD 								= 15;
double LAG_CHECK_INTERVAL_PERIOD 							= 4;

const int MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS	= 15000;
const int MAX_CLIENT_PAUSE_FOR_LAG_COUNT					= 3;
const int MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS			= 1500;
const int MASTERSERVER_HEARTBEAT_GAME_STATUS_SECONDS 		= 30;

const int MAX_EMPTY_NETWORK_COMMAND_LIST_BROADCAST_INTERVAL_MILLISECONDS = 4000;

ServerInterface::ServerInterface(bool publishEnabled, ClientLagCallbackInterface *clientLagCallbackInterface) : GameNetworkInterface() {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	this->clientLagCallbackInterface	= clientLagCallbackInterface;
	this->clientsAutoPausedDueToLag     = false;

	allowInGameConnections 				= false;
	gameLaunched 						= false;

	serverSynchAccessor 				= new Mutex(CODE_AT_LINE);
	switchSetupRequestsSynchAccessor 	= new Mutex(CODE_AT_LINE);

	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
		slotAccessorMutexes[index] 		= new Mutex(CODE_AT_LINE);
	}
	masterServerThreadAccessor 			= new Mutex(CODE_AT_LINE);
	textMessageQueueThreadAccessor 		= new Mutex(CODE_AT_LINE);
	broadcastMessageQueueThreadAccessor = new Mutex(CODE_AT_LINE);
	inBroadcastMessageThreadAccessor 	= new Mutex(CODE_AT_LINE);

	serverSocketAdmin				= NULL;
	nextEventId 					= 1;
	gameHasBeenInitiated 			= false;
	exitServer 						= false;
	gameSettingsUpdateCount 		= 0;
	currentFrameCount 				= 0;
	gameStartTime 					= 0;
	resumeGameStartTime				= 0;
	publishToMasterserverThread 	= NULL;
	lastMasterserverHeartbeatTime 	= 0;
	needToRepublishToMasterserver 	= false;
	ftpServer 						= NULL;
	inBroadcastMessage				= false;
	lastGlobalLagCheckTime			= 0;
	masterserverAdminRequestLaunch	= false;
	lastListenerSlotCheckTime		= 0;

	// This is an admin port listening only on the localhost intended to
	// give current connection status info
#ifndef __APPLE__
	try {
		serverSocketAdmin			= new ServerSocket(true);
		serverSocketAdmin->setBlock(false);
		serverSocketAdmin->setBindPort(Config::getInstance().getInt("ServerAdminPort", intToStr(GameConstants::serverAdminPort).c_str()));
		serverSocketAdmin->setBindSpecificAddress(Config::getInstance().getString("ServerAdminBindAddress", "127.0.0.1"));
		serverSocketAdmin->listen(5);
	}
	catch(const std::exception &ex) {
		char szBuf[8096]="";
		snprintf(szBuf,8096,"In [%s::%s Line: %d] Warning Server admin port bind/listen error:\n%s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);

		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s",szBuf);
	}
#endif

	maxFrameCountLagAllowed 				= Config::getInstance().getInt("MaxFrameCountLagAllowed", intToStr(maxFrameCountLagAllowed).c_str());
	maxFrameCountLagAllowedEver 			= Config::getInstance().getInt("MaxFrameCountLagAllowedEver", intToStr(maxFrameCountLagAllowedEver).c_str());
	maxClientLagTimeAllowedEver				= Config::getInstance().getInt("MaxClientLagTimeAllowedEver", intToStr(maxClientLagTimeAllowedEver).c_str());
	maxClientLagTimeAllowed 				= Config::getInstance().getInt("MaxClientLagTimeAllowed", intToStr(maxClientLagTimeAllowed).c_str());
	warnFrameCountLagPercent 				= Config::getInstance().getFloat("WarnFrameCountLagPercent", doubleToStr(warnFrameCountLagPercent).c_str());

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] maxFrameCountLagAllowed = %f, maxFrameCountLagAllowedEver = %f, maxClientLagTimeAllowed = %f, maxClientLagTimeAllowedEver = %f\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,maxFrameCountLagAllowed,maxFrameCountLagAllowedEver,maxClientLagTimeAllowed,maxClientLagTimeAllowedEver);

	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
		slots[index]				= NULL;
		switchSetupRequests[index]	= NULL;
	}

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

	serverSocket.setBlock(false);
	serverSocket.setBindPort(Config::getInstance().getInt("PortServer", intToStr(GameConstants::serverPort).c_str()));

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

	gameStatsThreadAccessor 	= new Mutex(CODE_AT_LINE);
	gameStats 					= NULL;

	Config &config 			= Config::getInstance();
  	string scenarioDir 		= "";
  	vector<string> pathList = config.getPathListForType(ptMaps,scenarioDir);
  	vector<string> invalidMapList;
  	vector<string> allMaps = MapPreview::findAllValidMaps(pathList,scenarioDir,false,true,&invalidMapList);
	if (allMaps.empty()) {
        //throw megaglest_runtime_error("No maps were found!");
		printf("No maps were found (srv)!\n");
	}
	std::sort(allMaps.begin(),allMaps.end(),compareNonCaseSensitive);
	vector<string> results;
	copy(allMaps.begin(), allMaps.end(), std::back_inserter(results));
	mapFiles = results;

	//player Sorted maps
	////////////////////
	for(unsigned int i = 0; i < GameConstants::maxPlayers+1; ++i) {
		playerSortedMaps[i].clear();
	}

	// at index=0 fill in the whole list
	copy(mapFiles.begin(), mapFiles.end(), std::back_inserter(playerSortedMaps[0]));

	MapInfo mapInfo;
	// fill playerSortedMaps according to map player count
	for(int i= 0; i < (int)mapFiles.size(); i++){// fetch info and put map in right list
		//printf("mapFiles.at(i) %s allMaps.at[i] %s\n",mapFiles[i].c_str(),allMaps.at(i).c_str());
		MapPreview::loadMapInfo(Config::getMapPath(mapFiles.at(i)), &mapInfo, "MaxPlayers","Size",true) ;
		playerSortedMaps[mapInfo.players].push_back(mapFiles.at(i));
	}
	///////////////////

	results.clear();
    findDirs(config.getPathListForType(ptTilesets), results);
	if (results.empty()) {
        //throw megaglest_runtime_error("No tile-sets were found!");
		printf("No tile-sets were found (srv)!");
	}
    tilesetFiles = results;

    results.clear();
    findDirs(config.getPathListForType(ptTechs), results);
	if(results.empty()) {
        //throw megaglest_runtime_error("No tech-trees were found!");
		printf("No tech-trees were found (srv)!\n");
	}
    techTreeFiles = results;

	if(Config::getInstance().getBool("EnableFTPServer","true") == true) {
		std::pair<string,string> mapsPath;
		vector<string> pathList = Config::getInstance().getPathListForType(ptMaps);
		if(pathList.empty() == false) {
			mapsPath.first = pathList[0];
			if(pathList.size() > 1) {
				mapsPath.second = pathList[1];
			}
		}

		std::pair<string,string> tilesetsPath;
		vector<string> tilesetsList = Config::getInstance().getPathListForType(ptTilesets);
		if(tilesetsList.empty() == false) {
			tilesetsPath.first = tilesetsList[0];
			if(tilesetsList.size() > 1) {
				tilesetsPath.second = tilesetsList[1];
			}
		}

		std::pair<string,string> techtreesPath;
		vector<string> techtreesList = Config::getInstance().getPathListForType(ptTechs);
		if(techtreesList.empty() == false) {
			techtreesPath.first = techtreesList[0];
			if(techtreesList.size() > 1) {
				techtreesPath.second = techtreesList[1];
			}
		}

		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
		int portNumber   = Config::getInstance().getInt("FTPServerPort",intToStr(ServerSocket::getFTPServerPort()).c_str());
		ServerSocket::setFTPServerPort(portNumber);
		//printf("In [%s::%s] portNumber = %d ServerSocket::getFTPServerPort() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,portNumber,ServerSocket::getFTPServerPort());

		bool allowInternetTilesetFileTransfers = Config::getInstance().getBool("EnableFTPServerInternetTilesetXfer","true");
		bool allowInternetTechtreeFileTransfers = Config::getInstance().getBool("EnableFTPServerInternetTechtreeXfer","true");

		// Get path to temp files
		string tempFilePath = "temp/";
		if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
			tempFilePath = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + tempFilePath;
		}
		else {
	        string userData = config.getString("UserData_Root","");
	        if(userData != "") {
	        	endPathWithSlash(userData);
	        }
	        tempFilePath = userData + tempFilePath;
		}
		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Temp files path [%s]\n",tempFilePath.c_str());

		ftpServer = new FTPServerThread(mapsPath,tilesetsPath,techtreesPath,
				publishEnabled,allowInternetTilesetFileTransfers,
				allowInternetTechtreeFileTransfers,portNumber,GameConstants::maxPlayers,
				this,tempFilePath);
		ftpServer->start();
	}

	if(publishToMasterserverThread == NULL) {
		if(needToRepublishToMasterserver == true || GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
			static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
			publishToMasterserverThread = new SimpleTaskThread(this,0,125);
			publishToMasterserverThread->setUniqueID(mutexOwnerId);
			publishToMasterserverThread->start();

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

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

void ServerInterface::setPublishEnabled(bool value) {
	if(ftpServer != NULL) {
		ftpServer->setInternetEnabled(value);
	}
}

void ServerInterface::shutdownMasterserverPublishThread() {
	MutexSafeWrapper safeMutex(masterServerThreadAccessor,CODE_AT_LINE);

	if(publishToMasterserverThread != NULL) {
		time_t elapsed = time(NULL);
		publishToMasterserverThread->signalQuit();
		for(;publishToMasterserverThread->canShutdown(false) == false &&
			difftime((long int)time(NULL),elapsed) <= 15;) {
			//sleep(150);
		}
		if(publishToMasterserverThread->canShutdown(true)) {
			delete publishToMasterserverThread;
			publishToMasterserverThread = NULL;
		}
	}
}

ServerInterface::~ServerInterface() {
	//printf("===> Destructor for ServerInterface\n");
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	masterController.clearSlaves(true);
	exitServer = true;
	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
		if(slots[index] != NULL) {
			MutexSafeWrapper safeMutex(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
			delete slots[index];
			slots[index] = NULL;
		}

		if(switchSetupRequests[index] != NULL) {
			delete switchSetupRequests[index];
			switchSetupRequests[index] = NULL;
		}
	}

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
	close();
	shutdownFTPServer();
	shutdownMasterserverPublishThread();

	lastMasterserverHeartbeatTime = 0;
	if(needToRepublishToMasterserver == true) {
		simpleTask(NULL,NULL);
	}

	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
		delete slotAccessorMutexes[index];
		slotAccessorMutexes[index] = NULL;
	}

	delete textMessageQueueThreadAccessor;
	textMessageQueueThreadAccessor = NULL;

	delete broadcastMessageQueueThreadAccessor;
	broadcastMessageQueueThreadAccessor = NULL;

	delete inBroadcastMessageThreadAccessor;
	inBroadcastMessageThreadAccessor = NULL;

	delete serverSynchAccessor;
	serverSynchAccessor = NULL;

	delete masterServerThreadAccessor;
	masterServerThreadAccessor = NULL;

	delete serverSocketAdmin;
	serverSocketAdmin = NULL;

	for(int index = 0; index < (int)broadcastMessageQueue.size(); ++index) {
		pair<NetworkMessage *,int> &item = broadcastMessageQueue[index];
		if(item.first != NULL) {
			delete item.first;
		}
		item.first = NULL;
	}
	broadcastMessageQueue.clear();

	delete switchSetupRequestsSynchAccessor;
	switchSetupRequestsSynchAccessor = NULL;

	delete gameStatsThreadAccessor;
	gameStatsThreadAccessor = NULL;

	delete gameStats;
	gameStats = NULL;

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

SwitchSetupRequest ** ServerInterface::getSwitchSetupRequests() {
	MutexSafeWrapper safeMutex(switchSetupRequestsSynchAccessor,CODE_AT_LINE);
    return &switchSetupRequests[0];
}

SwitchSetupRequest * ServerInterface::getSwitchSetupRequests(int index) {
	MutexSafeWrapper safeMutex(switchSetupRequestsSynchAccessor,CODE_AT_LINE);
    return switchSetupRequests[index];
}

void ServerInterface::setSwitchSetupRequests(int index,SwitchSetupRequest *ptr) {
	MutexSafeWrapper safeMutex(switchSetupRequestsSynchAccessor,CODE_AT_LINE);
    switchSetupRequests[index] = ptr;
}

int ServerInterface::isValidClientType(uint32 clientIp) {
	int result = 0;
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
		MutexSafeWrapper safeMutex(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		if(slots[index] != NULL) {
			Socket *socket = slots[index]->getSocket();
			if(socket != NULL) {
				uint32 slotIp = socket->getConnectedIPAddress(socket->getIpAddress());
				if(slotIp == clientIp) {
					result = 1;
					break;
				}
			}
		}
	}
	return result;
}

int ServerInterface::isClientAllowedToGetFile(uint32 clientIp, const char *username, const char *filename) {
	int result = 1;

	if(	username != NULL &&
			strlen(username) > 0 &&
		filename != NULL &&
			strlen(filename) > 0) {
		string user = username;
		string file = filename;

		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d username [%s] file [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,username,filename);

		if(StartsWith(user,"tilesets") == true && EndsWith(file,"7z") == false) {
			if(Config::getInstance().getBool("DisableFTPServerXferUncompressedTilesets","false") == true) {
				result = 0;
			}
			else {
				char szIP[100] = "";
				Ip::Inet_NtoA(clientIp,szIP);
				string clientIP = szIP;
				std::vector<std::string> serverList = Socket::getLocalIPAddressList();

				result = 0;
				for(unsigned int index = 0; index < serverList.size(); ++index) {
					string serverIP = serverList[index];

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d clientIP [%s] serverIP [%s] %d / %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientIP.c_str(),serverIP.c_str(),index,serverList.size());

					vector<string> clientTokens;
					Tokenize(clientIP,clientTokens,".");

					vector<string> serverTokens;
					Tokenize(serverIP,serverTokens,".");

					if(clientTokens.size() == 4 && serverTokens.size() == 4) {
						if( clientTokens[0] == serverTokens[0] ||
							clientTokens[1] == serverTokens[1] ||
							clientTokens[2] == serverTokens[2]) {
							result = 1;

							if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d clientIP [%s] IS NOT BLOCKED\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientIP.c_str());

							break;
						}
					}
				}
			}
		}
	}
	return result;
}

void ServerInterface::addClientToServerIPAddress(uint32 clientIp, uint32 ServerIp) {
	FTPServerThread::addClientToServerIPAddress(clientIp, ServerIp);
}

void ServerInterface::addSlot(int playerIndex) {
	//printf("Adding slot for playerIndex = %d, serverSocket.isPortBound() = %d\n",playerIndex,serverSocket.isPortBound());
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
		char szBuf[8096]="";
		snprintf(szBuf,8096,"In [%s::%s %d] playerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,playerIndex);
		throw megaglest_runtime_error(szBuf);
	}
	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
	if(serverSocketAdmin != NULL && serverSocketAdmin->isSocketValid() == false) {
		serverSocketAdmin->listen(5);
	}
	if(serverSocket.isPortBound() == false) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
		serverSocket.bind(serverSocket.getBindPort());
	}

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

	MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[playerIndex],CODE_AT_LINE_X(playerIndex));

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

	ConnectionSlot *slot = slots[playerIndex];
	if(slot != NULL) {
		slots[playerIndex] = NULL;
	}
	slots[playerIndex] = new ConnectionSlot(this, playerIndex);

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

	safeMutexSlot.ReleaseLock();
	delete slot;

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

	safeMutex.ReleaseLock();

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

	updateListen();

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

void ServerInterface::removeSlot(int playerIndex, int lockedSlotIndex) {
	//printf("Removing slot for playerIndex = %d, serverSocket.isPortBound() = %d\n",playerIndex,serverSocket.isPortBound());

	if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
		char szBuf[8096]="";
		snprintf(szBuf,8096,"In [%s::%s %d] playerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,playerIndex);
		throw megaglest_runtime_error(szBuf);
	}

	Lang &lang= Lang::getInstance();
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);

	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
	MutexSafeWrapper safeMutexSlot(NULL,CODE_AT_LINE_X(playerIndex));
	if(playerIndex != lockedSlotIndex) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
		safeMutexSlot.setMutex(slotAccessorMutexes[playerIndex],CODE_AT_LINE_X(playerIndex));
	}

	vector<string> msgList;
	ConnectionSlot *slot 				= slots[playerIndex];
	bool notifyDisconnect 				= false;
	const vector<string> languageList 	= this->gameSettings.getUniqueNetworkPlayerLanguages();
	if(slot != NULL) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);

		if(slot->getLastReceiveCommandListTime() > 0) {
			char szBuf[4096] = "";

			for(unsigned int index = 0; index < languageList.size(); ++index) {
				string msgTemplate = "Player %s, disconnected from the game.";
				if(lang.hasString("PlayerDisconnected",languageList[index]) == true) {
					msgTemplate = lang.getString("PlayerDisconnected",languageList[index]);
				}
#ifdef WIN32
				_snprintf(szBuf,4095,msgTemplate.c_str(),slot->getName().c_str());
#else
				snprintf(szBuf,4095,msgTemplate.c_str(),slot->getName().c_str());
#endif
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,szBuf);

				msgList.push_back(szBuf);
			}

			notifyDisconnect = true;
		}
	}
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);

	slots[playerIndex]= NULL;
	safeMutexSlot.ReleaseLock();
	safeMutex.ReleaseLock();

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);

	if(slot != NULL) slot->close();
	delete slot;

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);

	updateListen();

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);

	if(notifyDisconnect == true) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);

		for(unsigned int index = 0; index < languageList.size(); ++index) {
			bool localEcho = lang.isLanguageLocal(languageList[index]);
			queueTextMessage(msgList[index],-1, localEcho, languageList[index]);
		}
	}
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
}

bool ServerInterface::switchSlot(int fromPlayerIndex, int toPlayerIndex) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
	bool result = false;

	//printf("#1 Server is switching slots\n");

	if(fromPlayerIndex < 0 || fromPlayerIndex >= GameConstants::maxPlayers) {
		char szBuf[8096]="";
		snprintf(szBuf,8096,"In [%s::%s %d] fromPlayerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,fromPlayerIndex);
		throw megaglest_runtime_error(szBuf);
	}

	if(toPlayerIndex < 0 || toPlayerIndex >= GameConstants::maxPlayers) {
		char szBuf[8096]="";
		snprintf(szBuf,8096,"In [%s::%s %d] toPlayerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,toPlayerIndex);
		throw megaglest_runtime_error(szBuf);
	}

	if(fromPlayerIndex == toPlayerIndex) {
		return false;
	}

	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
	MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[fromPlayerIndex],CODE_AT_LINE_X(fromPlayerIndex));
	MutexSafeWrapper safeMutexSlot2(slotAccessorMutexes[toPlayerIndex],CODE_AT_LINE_X(toPlayerIndex));

	//printf("#1a Server is switching slots\n");

	if(slots[toPlayerIndex] != NULL &&
	   slots[toPlayerIndex]->hasValidSocketId() == false) {

		//printf("#2 Server is switching slots\n");

		slots[fromPlayerIndex]->setPlayerIndex(toPlayerIndex);
		slots[toPlayerIndex]->setPlayerIndex(fromPlayerIndex);
		ConnectionSlot *tmp 	= slots[toPlayerIndex];
		slots[toPlayerIndex] 	= slots[fromPlayerIndex];
		slots[fromPlayerIndex] 	= tmp;

		safeMutex.ReleaseLock();

		PlayerIndexMessage playerIndexMessage(toPlayerIndex);
		slots[toPlayerIndex]->sendMessage(&playerIndexMessage);

		//slots[fromPlayerIndex]->resetJoinGameInProgressFlags();
		//slots[toPlayerIndex]->setJoinGameInProgressFlags();

		safeMutexSlot.ReleaseLock();
		safeMutexSlot2.ReleaseLock();
		result = true;
		updateListen();
	}
	else {
		//printf("#3 Server is switching slots aborted, is slot already connected?\n");

		safeMutexSlot.ReleaseLock();
		safeMutexSlot2.ReleaseLock();
		safeMutex.ReleaseLock();
	}
	//printf("#4 Server is switching slots\n");

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

Mutex *ServerInterface::getSlotMutex(int playerIndex) {
	return slotAccessorMutexes[playerIndex];
}

ConnectionSlot *ServerInterface::getSlot(int playerIndex, bool lockMutex) {
	if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
		char szBuf[8096]="";
		snprintf(szBuf,8096,"In [%s::%s %d] playerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,playerIndex);
		throw megaglest_runtime_error(szBuf);
	}

	MutexSafeWrapper safeMutexSlot((lockMutex == true ? slotAccessorMutexes[playerIndex] : NULL),CODE_AT_LINE_X(playerIndex));
	ConnectionSlot *result = slots[playerIndex];
	return result;
}

bool ServerInterface::isClientConnected(int playerIndex) {
	if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
		char szBuf[8096]="";
		snprintf(szBuf,8096,"In [%s::%s %d] playerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,playerIndex);
		throw megaglest_runtime_error(szBuf);
	}

	bool result = false;
	MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[playerIndex],CODE_AT_LINE_X(playerIndex));
	if(slots[playerIndex] != NULL && slots[playerIndex]->isConnected() == true) {
		result = true;
	}
	return result;
}

bool ServerInterface::hasClientConnection() {
	bool result = false;
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
		if(isClientConnected(index) == true) {
			result = true;
			break;
		}
	}
	return result;
}

int ServerInterface::getSlotCount() {
	int slotCount = 0;
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		if(slots[index] != NULL) {
			++slotCount;
		}
	}
	return slotCount;
}

int ServerInterface::getConnectedSlotCount(bool authenticated) {
	int connectedSlotCount = 0;
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		if(slots[index] != NULL && slots[index]->isConnected() == true) {
			if(authenticated == false ||
				(authenticated == true && slots[index]->getConnectHasHandshaked() == true)) {
				++connectedSlotCount;
			}
		}
	}
	return connectedSlotCount;
}

int64 ServerInterface::getNextEventId() {
	nextEventId++;
	if(nextEventId > INT_MAX) {
		nextEventId = 1;
	}
	return nextEventId;
}

std::pair<bool,bool> ServerInterface::clientLagCheck(ConnectionSlot *connectionSlot, bool skipNetworkBroadCast) {
	std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false, false);
	static bool alreadyInLagCheck = false;

	if(alreadyInLagCheck == true ||
		(connectionSlot != NULL && (connectionSlot->getSkipLagCheck() == true ||
		 connectionSlot->getConnectHasHandshaked() == false))) {
		return clientLagExceededOrWarned;
	}

	try {
		alreadyInLagCheck = true;

		if((gameStartTime > 0 &&
				difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD) &&
			(resumeGameStartTime == 0 ||
			  (resumeGameStartTime > 0 &&
					  difftime((long int)time(NULL),resumeGameStartTime) >= LAG_CHECK_GRACE_PERIOD))) {
			if(connectionSlot != NULL && connectionSlot->isConnected() == true) {

				double clientLag 		= this->getCurrentFrameCount() - connectionSlot->getCurrentFrameCount();
				double clientLagCount 	= (gameSettings.getNetworkFramePeriod() > 0 ? (clientLag / gameSettings.getNetworkFramePeriod()) : 0);
				connectionSlot->setCurrentLagCount(clientLagCount);

				double clientLagTime 	= difftime((long int)time(NULL),connectionSlot->getLastReceiveCommandListTime());

				if(this->getCurrentFrameCount() > 0) {
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, clientLag = %f, clientLagCount = %f, this->getCurrentFrameCount() = %d, connectionSlot->getCurrentFrameCount() = %d, clientLagTime = %f\n",
																		 extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,
																		 connectionSlot->getPlayerIndex(),
																		 clientLag,clientLagCount,
																		 this->getCurrentFrameCount(),
																		 connectionSlot->getCurrentFrameCount(),
																		 clientLagTime);
				}

				// TEST LAG Error and warnings!!!
				//clientLagCount = maxFrameCountLagAllowed + 1;
				//clientLagTime = maxClientLagTimeAllowed + 1;
				/*
				if(difftime(time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD + 5) {
					clientLagTime = maxClientLagTimeAllowed + 1;
				}
				else if(difftime(time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD) {
					clientLagTime = (maxClientLagTimeAllowed * warnFrameCountLagPercent) + 1;
				}
				*/
				// END test


				//printf("skipNetworkBroadCast [%d] clientLagCount [%f][%f][%f] clientLagTime [%f][%f][%f]\n",skipNetworkBroadCast,clientLagCount,(maxFrameCountLagAllowed * warnFrameCountLagPercent),maxFrameCountLagAllowed,clientLagTime,(maxClientLagTimeAllowed * warnFrameCountLagPercent),maxClientLagTimeAllowed);

				// New lag check
				if((maxFrameCountLagAllowed > 0 && clientLagCount > maxFrameCountLagAllowed) ||
					(maxClientLagTimeAllowed > 0 && clientLagTime > maxClientLagTimeAllowed) ||
					(maxFrameCountLagAllowedEver > 0 && clientLagCount > maxFrameCountLagAllowedEver) ||
					( maxClientLagTimeAllowedEver > 0 && clientLagTime > maxClientLagTimeAllowedEver)) {

					clientLagExceededOrWarned.first = true;
					//printf("#1 Client Warned\n");

			    	Lang &lang= Lang::getInstance();
			    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
			    	for(unsigned int index = 0; index < languageList.size(); ++index) {
						char szBuf[4096]="";

						string msgTemplate = "DROPPING %s, exceeded max allowed LAG count of %f [time = %f], clientLag = %f [%f], disconnecting client.";
						if(lang.hasString("ClientLagDropping") == true) {
							msgTemplate = lang.getString("ClientLagDropping",languageList[index]);
						}
						if(gameSettings.getNetworkPauseGameForLaggedClients() == true &&
							((maxFrameCountLagAllowedEver <= 0 || clientLagCount <= maxFrameCountLagAllowedEver) &&
							 (maxClientLagTimeAllowedEver <= 0 || clientLagTime <= maxClientLagTimeAllowedEver))) {
							msgTemplate = "PAUSING GAME TEMPORARILY for %s, exceeded max allowed LAG count of %f [time = %f], clientLag = %f [%f], waiting for client to catch up...";
							if(lang.hasString("ClientLagPausing") == true) {
								msgTemplate = lang.getString("ClientLagPausing",languageList[index]);
							}
						}
#ifdef WIN32
						_snprintf(szBuf,4095,msgTemplate.c_str(),connectionSlot->getName().c_str() ,maxFrameCountLagAllowed,maxClientLagTimeAllowed,clientLagCount,clientLagTime);
#else
						snprintf(szBuf,4095,msgTemplate.c_str(),connectionSlot->getName().c_str(),maxFrameCountLagAllowed,maxClientLagTimeAllowed,clientLagCount,clientLagTime);
#endif
						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,szBuf);

						if(skipNetworkBroadCast == false) {
							string sMsg = szBuf;
							bool echoLocal = lang.isLanguageLocal(languageList[index]);
							sendTextMessage(sMsg,-1, echoLocal, languageList[index], connectionSlot->getPlayerIndex());
						}
			    	}

					if(gameSettings.getNetworkPauseGameForLaggedClients() == false ||
						(maxFrameCountLagAllowedEver > 0 && clientLagCount > maxFrameCountLagAllowedEver) ||
						(maxClientLagTimeAllowedEver > 0 && clientLagTime > maxClientLagTimeAllowedEver)) {

						//printf("Closing connection slot lagged out!\n");
						connectionSlot->close();
					}

				}
				// New lag check warning
				else if((maxFrameCountLagAllowed > 0 && warnFrameCountLagPercent > 0 &&
						 clientLagCount > (maxFrameCountLagAllowed * warnFrameCountLagPercent)) ||
						(maxClientLagTimeAllowed > 0 && warnFrameCountLagPercent > 0 &&
						 clientLagTime > (maxClientLagTimeAllowed * warnFrameCountLagPercent)) ) {

					clientLagExceededOrWarned.second = true;
					//printf("#2 Client Warned\n");

					if(connectionSlot->getLagCountWarning() == false) {
						connectionSlot->setLagCountWarning(true);

				    	Lang &lang= Lang::getInstance();
				    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
				    	for(unsigned int index = 0; index < languageList.size(); ++index) {
				    		char szBuf[4096]="";

				    		string msgTemplate = "LAG WARNING for %s, may exceed max allowed LAG count of %f [time = %f], clientLag = %f [%f], WARNING...";
							if(lang.hasString("ClientLagWarning") == true) {
								msgTemplate = lang.getString("ClientLagWarning",languageList[index]);
							}

		#ifdef WIN32
				    		_snprintf(szBuf,4095,msgTemplate.c_str(),connectionSlot->getName().c_str(),maxFrameCountLagAllowed,maxClientLagTimeAllowed,clientLagCount,clientLagTime);
		#else
				    		snprintf(szBuf,4095,msgTemplate.c_str(),connectionSlot->getName().c_str(),maxFrameCountLagAllowed,maxClientLagTimeAllowed,clientLagCount,clientLagTime);
		#endif
				    		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,szBuf);

							if(skipNetworkBroadCast == false) {
								string sMsg = szBuf;
								bool echoLocal = lang.isLanguageLocal(languageList[index]);
								sendTextMessage(sMsg,-1, echoLocal, languageList[index], connectionSlot->getPlayerIndex());
							}
				    	}
					}
				}
				else if(connectionSlot->getLagCountWarning() == true) {
					connectionSlot->setLagCountWarning(false);
				}
			}
		}
	}
	catch(const exception &ex) {
		alreadyInLagCheck = false;

		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ERROR [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		throw megaglest_runtime_error(ex.what());
	}

	alreadyInLagCheck = false;
	return clientLagExceededOrWarned;
}

void ServerInterface::updateSocketTriggeredList(std::map<PLATFORM_SOCKET,bool> & socketTriggeredList) {
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		ConnectionSlot *connectionSlot = slots[index];
		if(connectionSlot != NULL) {
			PLATFORM_SOCKET clientSocket = connectionSlot->getSocketId();
			if(Socket::isSocketValid(&clientSocket) == true) {
				socketTriggeredList[clientSocket] = false;
			}
		}
	}
}

void ServerInterface::validateConnectedClients() {
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		ConnectionSlot* connectionSlot = slots[index];
		if(connectionSlot != NULL) {
			connectionSlot->validateConnection();
		}
	}
}

bool ServerInterface::signalClientReceiveCommands(ConnectionSlot *connectionSlot,
		int slotIndex, bool socketTriggered, ConnectionSlotEvent & event) {
	bool slotSignalled 		= false;

	event.eventType 		= eReceiveSocketData;
	event.networkMessage 	= NULL;
	event.connectionSlot 	= connectionSlot;
	event.socketTriggered 	= socketTriggered;
	event.triggerId 		= slotIndex;
	event.eventId 			= getNextEventId();

	if(connectionSlot != NULL) {
		if(socketTriggered == true || connectionSlot->isConnected() == false) {
			connectionSlot->signalUpdate(&event);
			slotSignalled = true;
		}
	}
	return slotSignalled;
}

void ServerInterface::signalClientsToRecieveData(std::map<PLATFORM_SOCKET,bool> &socketTriggeredList,
												 std::map<int,ConnectionSlotEvent> &eventList,
												 std::map<int,bool> & mapSlotSignalledList) {
	//printf("====================================In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	//printf("Signal clients get new data\n");
	const bool newThreadManager = Config::getInstance().getBool("EnableNewThreadManager","false");
	if(newThreadManager == true) {
		masterController.clearSlaves(true);
		std::vector<SlaveThreadControllerInterface *> slaveThreadList;
		for(int i= 0; exitServer == false && i < GameConstants::maxPlayers; ++i) {
			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[i],CODE_AT_LINE_X(i));
			ConnectionSlot* connectionSlot = slots[i];

			bool socketTriggered = false;

			if(connectionSlot != NULL) {
				PLATFORM_SOCKET clientSocket = connectionSlot->getSocketId();
				if(Socket::isSocketValid(&clientSocket)) {
					socketTriggered = socketTriggeredList[clientSocket];
				}
				else if(this->getGameHasBeenInitiated() == true &&
						this->getAllowInGameConnections() == true) {
					socketTriggeredList[clientSocket] = true;
					socketTriggered = socketTriggeredList[clientSocket];
				}
			}
			ConnectionSlotEvent &event = eventList[i];
			event.eventType 		= eReceiveSocketData;
			event.networkMessage 	= NULL;
			event.connectionSlot 	= connectionSlot;
			event.socketTriggered 	= socketTriggered;
			event.triggerId 		= i;
			event.eventId 			= getNextEventId();

			if(connectionSlot != NULL) {
				if(socketTriggered == true || connectionSlot->isConnected() == false) {
					if(connectionSlot->getWorkerThread() != NULL) {
						slaveThreadList.push_back(connectionSlot->getWorkerThread());
						mapSlotSignalledList[i] = true;
					}
				}
			}
		}
		masterController.setSlaves(slaveThreadList);
		masterController.signalSlaves(&eventList);
	}
	else {
		for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
			ConnectionSlot *connectionSlot = slots[index];

			if(connectionSlot != NULL) {
				bool socketTriggered = false;
				PLATFORM_SOCKET clientSocket = connectionSlot->getSocketId();
				if(Socket::isSocketValid(&clientSocket)) {
					socketTriggered = socketTriggeredList[clientSocket];
				}

				ConnectionSlotEvent &event = eventList[index];
				bool socketSignalled = signalClientReceiveCommands(connectionSlot,index,socketTriggered,event);
				if(connectionSlot != NULL && socketTriggered == true) {
					mapSlotSignalledList[index] = socketSignalled;
				}
			}
		}
	}
}

void ServerInterface::checkForCompletedClientsUsingThreadManager(
		std::map<int, bool> &mapSlotSignalledList, std::vector<string>& errorMsgList) {

	masterController.waitTillSlavesTrigger(MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS);
	masterController.clearSlaves(true);

	for (int i = 0; exitServer == false && i < GameConstants::maxPlayers; ++i) {
		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[i],CODE_AT_LINE_X(i));

		ConnectionSlot* connectionSlot = slots[i];
		if (connectionSlot != NULL && mapSlotSignalledList[i] == true) {

			try {
				std::vector<std::string> errorList =
						connectionSlot->getThreadErrorList();
				// Collect any collected errors from threads
				if (errorList.empty() == false) {
					for (int iErrIdx = 0; iErrIdx < (int) errorList.size();++iErrIdx) {
						string &sErr = errorList[iErrIdx];

						if (sErr != "") {
							errorMsgList.push_back(sErr);
						}
					}
					connectionSlot->clearThreadErrorList();
				}
			} catch (const exception &ex) {
				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());

				errorMsgList.push_back(ex.what());
			}
		}
	}
}

void ServerInterface::checkForCompletedClientsUsingLoop(
		std::map<int, bool>& mapSlotSignalledList, std::vector<string> &errorMsgList,
		std::map<int, ConnectionSlotEvent> &eventList) {

	//time_t waitForThreadElapsed = time(NULL);
	Chrono waitForThreadElapsed(true);

	std::map<int, bool> slotsCompleted;
	for (bool threadsDone = false; exitServer == false && threadsDone == false &&
		 waitForThreadElapsed.getMillis() <= MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS;) {

		threadsDone = true;
		// Examine all threads for completion of delegation
		for (int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));

			ConnectionSlot *connectionSlot = slots[index];
			if (connectionSlot != NULL && connectionSlot->isConnected() == true &&
				  mapSlotSignalledList[index] == true &&
					connectionSlot->getJoinGameInProgress() == false &&
				 	  slotsCompleted.find(index) == slotsCompleted.end()) {

				try {
					std::vector<std::string> errorList = connectionSlot->getThreadErrorList();
					// Collect any collected errors from threads
					if (errorList.empty() == false) {

						for (int iErrIdx = 0; iErrIdx < (int) errorList.size();++iErrIdx) {

							string &sErr = errorList[iErrIdx];
							if (sErr != "") {
								errorMsgList.push_back(sErr);
							}
						}
						connectionSlot->clearThreadErrorList();
					}

					// Not done waiting for data yet
					bool updateFinished = (connectionSlot != NULL ? connectionSlot->updateCompleted(&eventList[index]) : true);
					if (updateFinished == false) {
						threadsDone = false;
						break;
					}
					else {
						slotsCompleted[index] = true;
					}
				}
				catch (const exception &ex) {
					SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());

					errorMsgList.push_back(ex.what());
				}
			}
		}
	}
}

std::string ServerInterface::getIpAddress(bool mutexLock) {
	string result = serverSocket.getIpAddress();
	return result;
}

void ServerInterface::setClientLagCallbackInterface(ClientLagCallbackInterface *intf) {
	this->clientLagCallbackInterface = intf;
}

bool ServerInterface::getClientsAutoPausedDueToLag() {
	return this->clientsAutoPausedDueToLag;
}

void ServerInterface::checkForCompletedClients(std::map<int,bool> & mapSlotSignalledList,
											   std::vector <string> &errorMsgList,
											   std::map<int,ConnectionSlotEvent> &eventList) {

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

	const bool newThreadManager = Config::getInstance().getBool("EnableNewThreadManager","false");
	if(newThreadManager == true) {
		checkForCompletedClientsUsingThreadManager(mapSlotSignalledList, errorMsgList);
	}
	else {
		checkForCompletedClientsUsingLoop(mapSlotSignalledList, errorMsgList, eventList);
	}
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}

void ServerInterface::checkForAutoPauseForLaggingClient(int index,ConnectionSlot* connectionSlot) {

	if (gameSettings.getNetworkPauseGameForLaggedClients() == true &&
			this->clientsAutoPausedDueToLag == false) {
		if (connectionSlot != NULL && connectionSlot->isConnected() == true) {
			if (connectionSlot->getAutoPauseGameCountForLag() < MAX_CLIENT_PAUSE_FOR_LAG_COUNT) {
				if (this->clientLagCallbackInterface != NULL) {

					if (this->clientsAutoPausedDueToLagTimer.isStarted() == false ||
						this->clientsAutoPausedDueToLagTimer.getMillis() >= MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS) {

						connectionSlot->incrementAutoPauseGameCountForLag();

						this->clientsAutoPausedDueToLag = true;
						if (this->clientLagCallbackInterface->clientLagHandler(index, true) == false) {
							connectionSlot->close();
						}
						else {
							if (this->clientsAutoPausedDueToLagTimer.isStarted()== true) {

								this->clientsAutoPausedDueToLagTimer.reset();
								this->clientsAutoPausedDueToLagTimer.stop();
							}
							this->clientsAutoPausedDueToLagTimer.start();
						}
					}
				}
			}
		}
	}
}

void ServerInterface::checkForLaggingClients(std::map<int,bool> &mapSlotSignalledList,
											std::map<int,ConnectionSlotEvent> &eventList,
											std::map<PLATFORM_SOCKET,bool> &socketTriggeredList,
											std::vector <string> &errorMsgList) {
	bool lastGlobalLagCheckTimeUpdate = false;
	if(gameHasBeenInitiated == true) {

		//time_t waitForClientsElapsed = time(NULL);
		Chrono waitForClientsElapsed(true);
		//time_t waitForThreadElapsed = time(NULL);
		Chrono waitForThreadElapsed(true);
		std::map<int,bool> slotsCompleted;
		std::map<int,bool> slotsWarnedList;

		for(bool threadsDone = false;
			exitServer == false && threadsDone == false &&
			waitForThreadElapsed.getMillis() <= MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS;) {

			threadsDone = true;
			// Examine all threads for completion of delegation
			for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
				//printf("#1 Check lag for i: %d\n",i);

				MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
				ConnectionSlot* connectionSlot = slots[index];

				if(connectionSlot != NULL && connectionSlot->isConnected() == true &&
					connectionSlot->getSkipLagCheck() == false &&
					mapSlotSignalledList[index] == true &&
				    slotsCompleted.find(index) == slotsCompleted.end()) {

					//printf("#2 Check lag for i: %d playerindex: %d name [%s] socket: %d\n",i,connectionSlot->getPlayerIndex(),connectionSlot->getName().c_str(),connectionSlot->getSocketId());
					try {
						std::vector<std::string> errorList = connectionSlot->getThreadErrorList();
						// Show any collected errors from threads
						if(errorList.empty() == false) {
							for(int iErrIdx = 0; iErrIdx < (int)errorList.size(); ++iErrIdx) {
								string &sErr = errorList[iErrIdx];
								if(sErr != "") {
									errorMsgList.push_back(sErr);
								}
							}
							connectionSlot->clearThreadErrorList();
						}

						// Not done waiting for data yet
						bool updateFinished = (connectionSlot != NULL ? connectionSlot->updateCompleted(&eventList[index]) : true);
						if(updateFinished == false) {
							//printf("#2a Check lag for i: %d\n",i);
							threadsDone = false;
							break;
						}
						else {
							// New lag check
							std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false,false);
							if( gameHasBeenInitiated == true && connectionSlot != NULL &&
								connectionSlot->isConnected() == true) {
								clientLagExceededOrWarned = clientLagCheck(connectionSlot,slotsWarnedList[index]);

								if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, gameSettings.getNetworkPauseGameForLaggedClients() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,gameSettings.getNetworkPauseGameForLaggedClients());

								if(clientLagExceededOrWarned.first == true) {
									slotsWarnedList[index] = true;
								}
							}
							// If the client has exceeded lag and the server wants
							// to pause while they catch up, re-trigger the
							// client reader thread
							if((clientLagExceededOrWarned.second == true &&
								gameSettings.getNetworkPauseGameForLaggedClients() == true)) {

								if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, waitForClientsElapsed.getMillis() = %d, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,(int)waitForClientsElapsed.getMillis(),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS);

								checkForAutoPauseForLaggingClient(index, connectionSlot);

								slotsCompleted[index] = true;
							}
							else {
								slotsCompleted[index] = true;
							}
						}
					}
					catch(const exception &ex) {
						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
						errorMsgList.push_back(ex.what());
					}
				}

				//printf("#3 Check lag for i: %d\n",i);
				if(connectionSlot != NULL &&
					connectionSlot->isConnected() == true &&
					connectionSlot->getSkipLagCheck() == false) {
					//printf("#4 Check lag for i: %d\n",i);

					try {
						if(gameHasBeenInitiated == true &&
							difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
							difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {

							//printf("\n\n\n^^^^^^^^^^^^^^ PART A\n\n\n");

							// New lag check
							std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false,false);
							if( connectionSlot != NULL && connectionSlot->isConnected() == true) {
								//printf("\n\n\n^^^^^^^^^^^^^^ PART B\n\n\n");

								lastGlobalLagCheckTimeUpdate = true;
								clientLagExceededOrWarned = clientLagCheck(connectionSlot,slotsWarnedList[index]);

								if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, gameSettings.getNetworkPauseGameForLaggedClients() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,gameSettings.getNetworkPauseGameForLaggedClients());

								if(clientLagExceededOrWarned.first == true) {
									slotsWarnedList[index] = true;
								}

								// If the client has exceeded lag and the server wants
								// to pause while they catch up, re-trigger the
								// client reader thread
								if((clientLagExceededOrWarned.second == true &&
									gameSettings.getNetworkPauseGameForLaggedClients() == true)) {

									if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, waitForClientsElapsed.getMillis() = %d, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,(int)waitForClientsElapsed.getMillis(),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS);

									checkForAutoPauseForLaggingClient(index, connectionSlot);
								}
							}
						}
					}
					catch(const exception &ex) {
						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
						errorMsgList.push_back(ex.what());
					}
				}

				//printf("#5 Check lag for i: %d\n",i);
			}
		}
	}
	if(lastGlobalLagCheckTimeUpdate == true) {
		lastGlobalLagCheckTime = time(NULL);
	}
}

void ServerInterface::executeNetworkCommandsFromClients() {
	if(gameHasBeenInitiated == true) {
		for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
			ConnectionSlot* connectionSlot= slots[index];
			if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
				vector<NetworkCommand> pendingList = connectionSlot->getPendingNetworkCommandList(true);
				if(pendingList.empty() == false) {
					for(int idx = 0; exitServer == false && idx < (int)pendingList.size(); ++idx) {
						NetworkCommand &cmd = pendingList[idx];
						this->requestCommand(&cmd);
					}
					//printf("Executed: %d commands from slot: %d\n",pendingList.size(),index);
				}
			}
		}
	}
}

void ServerInterface::dispatchPendingChatMessages(std::vector <string> &errorMsgList) {
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {

		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		ConnectionSlot *connectionSlot = slots[index];

		if(connectionSlot != NULL &&
		   connectionSlot->getChatTextList(false).empty() == false) {
			try {
				std::vector<ChatMsgInfo> chatText = connectionSlot->getChatTextList(true);
				for(int chatIdx = 0;
					exitServer == false && slots[index] != NULL &&
					chatIdx < (int)chatText.size(); chatIdx++) {

					connectionSlot = slots[index];
					if(connectionSlot != NULL) {
						ChatMsgInfo msg(chatText[chatIdx]);
						this->addChatInfo(msg);

						string newChatText     = msg.chatText.c_str();
						int newChatTeamIndex   = msg.chatTeamIndex;
						int newChatPlayerIndex = msg.chatPlayerIndex;
						string newChatLanguage = msg.targetLanguage;

						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 about to broadcast nmtText chatText [%s] chatTeamIndex = %d, newChatPlayerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex,newChatPlayerIndex);

						if(newChatLanguage == "" ||
							newChatLanguage == connectionSlot->getNetworkPlayerLanguage()) {

							NetworkMessageText networkMessageText(newChatText.c_str(),newChatTeamIndex,newChatPlayerIndex,newChatLanguage);
							broadcastMessage(&networkMessageText, connectionSlot->getPlayerIndex(),index);
						}

						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
					}
				}

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] index = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,index);
				// Its possible that the slot is disconnected here
				// so check the original pointer again
				if(slots[index] != NULL) {
					slots[index]->clearChatInfo();
				}
			}
			catch(const exception &ex) {
				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				errorMsgList.push_back(ex.what());
			}
		}
	}
}

void ServerInterface::dispatchPendingMarkCellMessages(std::vector <string> &errorMsgList) {
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {

		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		ConnectionSlot* connectionSlot= slots[index];

		if(connectionSlot != NULL &&
		   connectionSlot->getMarkedCellList(false).empty() == false) {

			try {
				std::vector<MarkedCell> chatText = connectionSlot->getMarkedCellList(true);
				for(int chatIdx = 0;
					exitServer == false && slots[index] != NULL &&
					chatIdx < (int)chatText.size(); chatIdx++) {

					connectionSlot= slots[index];
					if(connectionSlot != NULL) {
						MarkedCell msg(chatText[chatIdx]);
						this->addMarkedCell(msg);

						NetworkMessageMarkCell networkMessageMarkCell(msg.getTargetPos(),msg.getFactionIndex(),msg.getNote(),msg.getPlayerIndex());
						broadcastMessage(&networkMessageMarkCell, connectionSlot->getPlayerIndex(),index);
						//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
					}
				}

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] i = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,index);
				// Its possible that the slot is disconnected here
				// so check the original pointer again
				if(slots[index] != NULL) {
					slots[index]->clearMarkedCellList();
				}
			}
			catch(const exception &ex) {
				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				errorMsgList.push_back(ex.what());
			}
		}
	}
}
void ServerInterface::dispatchPendingHighlightCellMessages(std::vector <string> &errorMsgList) {
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {

		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		ConnectionSlot* connectionSlot= slots[index];
		if(connectionSlot != NULL &&
		   connectionSlot->getHighlightedCellList(false).empty() == false) {

			try {
				std::vector<MarkedCell> highlightedCells = connectionSlot->getHighlightedCellList(true);
				for(int chatIdx = 0;
					exitServer == false && slots[index] != NULL &&
					chatIdx < (int)highlightedCells.size(); chatIdx++) {

					connectionSlot= slots[index];
					if(connectionSlot != NULL) {
						MarkedCell msg(highlightedCells[chatIdx]);
						this->setHighlightedCell(msg);

						NetworkMessageHighlightCell networkMessageHighlightCell(msg.getTargetPos(),msg.getFactionIndex());
						broadcastMessage(&networkMessageHighlightCell, connectionSlot->getPlayerIndex(),index);
					}
				}

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] index = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,index);
				// Its possible that the slot is disconnected here
				// so check the original pointer again
				if(slots[index] != NULL) {
					slots[index]->clearHighlightedCellList();
				}
			}
			catch(const exception &ex) {
				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				errorMsgList.push_back(ex.what());
			}
		}
	}
}

void ServerInterface::dispatchPendingUnMarkCellMessages(std::vector <string> &errorMsgList) {
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {

		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		ConnectionSlot* connectionSlot= slots[index];
		if(connectionSlot != NULL &&
		   connectionSlot->getUnMarkedCellList(false).empty() == false) {

			try {
				std::vector<UnMarkedCell> chatText = connectionSlot->getUnMarkedCellList(true);
				for(int chatIdx = 0;
					exitServer == false && slots[index] != NULL &&
					chatIdx < (int)chatText.size(); chatIdx++) {

					connectionSlot = slots[index];
					if(connectionSlot != NULL) {
						UnMarkedCell msg(chatText[chatIdx]);
						this->addUnMarkedCell(msg);

						NetworkMessageUnMarkCell networkMessageMarkCell(msg.getTargetPos(),msg.getFactionIndex());
						broadcastMessage(&networkMessageMarkCell, connectionSlot->getPlayerIndex(),index);
						//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
					}
				}

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] i = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,index);
				// Its possible that the slot is disconnected here
				// so check the original pointer again
				if(slots[index] != NULL) {
					slots[index]->clearUnMarkedCellList();
				}
			}
			catch(const exception &ex) {
				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
				errorMsgList.push_back(ex.what());
			}
		}
	}
}

void ServerInterface::checkForAutoResumeForLaggingClients() {
	if (gameSettings.getNetworkPauseGameForLaggedClients() == true &&
		this->clientsAutoPausedDueToLag == true &&
		this->clientsAutoPausedDueToLagTimer.getMillis() >= MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS) {

		//printf("this->clientsAutoPausedDueToLag: %d [%lld]\n",this->clientsAutoPausedDueToLag,(long long)this->clientsAutoPausedDueToLagTimer.getMillis());
		if (this->clientLagCallbackInterface != NULL) {

			this->clientsAutoPausedDueToLag = false;
			this->clientLagCallbackInterface->clientLagHandler(-1, false);

			this->clientsAutoPausedDueToLagTimer.reset();
			this->clientsAutoPausedDueToLagTimer.stop();
			this->clientsAutoPausedDueToLagTimer.start();
		}
	}
}

void ServerInterface::update() {
	//printf("\nServerInterface::update -- A\n");

	std::vector <string> errorMsgList;
	try {
		// The first thing we will do is check all clients to ensure they have
		// properly identified themselves within the alloted time period
		validateConnectedClients();

		//printf("\nServerInterface::update -- B\n");

		processTextMessageQueue();
		processBroadCastMessageQueue();

		checkForAutoResumeForLaggingClients();

		//printf("\nServerInterface::update -- C\n");

		std::map<PLATFORM_SOCKET,bool> socketTriggeredList;
		//update all slots
		updateSocketTriggeredList(socketTriggeredList);

		//printf("\nServerInterface::update -- D\n");

		if(gameHasBeenInitiated == false ||
			socketTriggeredList.empty() == false) {
			//printf("\nServerInterface::update -- E\n");

			std::map<int,ConnectionSlotEvent> eventList;

			bool hasData = false;
			if(gameHasBeenInitiated == false) {
				hasData = Socket::hasDataToRead(socketTriggeredList);
			}
			else {
				hasData = true;
			}

			if(hasData && SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] hasData == true\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

			if(gameHasBeenInitiated == false || hasData == true) {
				//printf("START Server update #2\n");
				std::map<int,bool> mapSlotSignalledList;

				// Step #1 tell all connection slot worker threads to receive socket data
				if(gameHasBeenInitiated == false) {
					signalClientsToRecieveData(socketTriggeredList, eventList, mapSlotSignalledList);
				}
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #2\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

				//printf("START Server update #2\n");
				if(gameHasBeenInitiated == false || hasData == true) {
					//printf("START Server update #3\n");

					// Step #2 check all connection slot worker threads for completed status
					if(gameHasBeenInitiated == false) {
						checkForCompletedClients(mapSlotSignalledList,errorMsgList, eventList);
					}
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #3\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					//printf("START Server update #4\n");
					//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					// Step #3 check clients for any lagging scenarios and try to deal with them
					if(gameHasBeenInitiated == false) {
						checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
					}
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #4\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					//printf("START Server update #5\n");
					//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
					// Step #4 dispatch network commands to the pending list so that they are done in proper order
					executeNetworkCommandsFromClients();
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #5\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					//printf("START Server update #6\n");
					//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
					// Step #5 dispatch pending chat messages
					dispatchPendingChatMessages(errorMsgList);
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					dispatchPendingMarkCellMessages(errorMsgList);
					dispatchPendingUnMarkCellMessages(errorMsgList);

					dispatchPendingHighlightCellMessages(errorMsgList);

					if(gameHasBeenInitiated == true &&
						difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
						difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {

						std::map<int,bool> mapSlotSignalledList;
						checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
					}
					//printf("START Server update #7\n");
				}
				else if(gameHasBeenInitiated == true &&
						difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
						difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {

					//printf("Skip network data process because hasData == false\n");
					//printf("START Server update #8\n");

					std::map<int,bool> mapSlotSignalledList;
					checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
				}
				//printf("START Server update #9\n");
			}
			else if(gameHasBeenInitiated == true &&
					difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
					difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {

				//printf("\nServerInterface::update -- E1\n");
				//printf("START Server update #10\n");

				std::map<int,bool> mapSlotSignalledList;
				checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
			}
			//printf("START Server update #11\n");
		}
		else if(gameHasBeenInitiated == true &&
				difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
				difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {

			//printf("\nServerInterface::update -- F\n");
			//printf("START Server update #12\n");

			std::map<int,ConnectionSlotEvent> eventList;
			std::map<int,bool> mapSlotSignalledList;

			checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
		}
		//printf("START Server update #13\n");

		// Check if we need to switch masterserver admin to a new player because original admin disconnected
		if(gameHasBeenInitiated == true &&
			this->gameSettings.getMasterserver_admin() > 0) {

			bool foundAdminSlot 	= false;
			int iFirstConnectedSlot = -1;
			for(int index = 0; index < GameConstants::maxPlayers; ++index) {
				MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
				if(slots[index] != NULL && slots[index]->isConnected() == true) {
					if(iFirstConnectedSlot < 0) {
						iFirstConnectedSlot = index;
					}
					if(this->gameSettings.getMasterserver_admin() == slots[index]->getSessionKey()) {
						foundAdminSlot = true;
						break;
					}
				}
			}

			if(foundAdminSlot == false && iFirstConnectedSlot >= 0) {
				printf("Switching masterserver admin to slot#%d...\n",iFirstConnectedSlot);

				MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[iFirstConnectedSlot],CODE_AT_LINE_X(iFirstConnectedSlot));
				if(slots[iFirstConnectedSlot] != NULL) {
					string sMsg = "Switching player to admin mode: " + slots[iFirstConnectedSlot]->getName();
					sendTextMessage(sMsg,-1, true,"");

					this->gameSettings.setMasterserver_admin(slots[iFirstConnectedSlot]->getSessionKey());
					this->gameSettings.setMasterserver_admin_faction_index(slots[iFirstConnectedSlot]->getPlayerIndex());

					safeMutexSlot.ReleaseLock();
					this->broadcastGameSetup(&this->gameSettings);
				}
			}
		}
		//printf("\nServerInterface::update -- G\n");
		//printf("START Server update #14\n");

		checkListenerSlots();

		//printf("START Server update #15\n");
	}
	catch(const exception &ex) {
		//printf("\nServerInterface::update -- H\n");

		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		errorMsgList.push_back(ex.what());
	}

	if(errorMsgList.empty() == false){
		for(int iErrIdx = 0; iErrIdx < (int)errorMsgList.size(); ++iErrIdx) {
			string &sErr = errorMsgList[iErrIdx];
			if(sErr != "") {
				DisplayErrorMessage(sErr);
			}
		}
	}
}

void ServerInterface::updateKeyframe(int frameCount) {
	currentFrameCount = frameCount;
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] currentFrameCount = %d, requestedCommands.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,currentFrameCount,requestedCommands.size());

	NetworkMessageCommandList networkMessageCommandList(frameCount);
	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
		networkMessageCommandList.setNetworkPlayerFactionCRC(index,this->getNetworkPlayerFactionCRC(index));
	}

	while(requestedCommands.empty() == false) {
		// First add the command to the broadcast list (for all clients)
		if(networkMessageCommandList.addCommand(&requestedCommands.back())) {
			// Add the command to the local server command list
			pendingCommands.push_back(requestedCommands.back());
			requestedCommands.pop_back();
		}
		else {
			break;
		}
	}

	try {
		// Possible cause of out of synch since we have more commands that need
		// to be sent in this frame
		if(requestedCommands.empty() == false) {
			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] WARNING / ERROR, requestedCommands.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,requestedCommands.size());
			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] WARNING / ERROR, requestedCommands.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,requestedCommands.size());

			string sMsg = "may go out of synch: server requestedCommands.size() = " + intToStr(requestedCommands.size());
			sendTextMessage(sMsg,-1, true,"");
		}

		// broadcast commands
		// If we have more than 0 commands to send, automatically broadcast them
		bool sendBroadcastMessage = (networkMessageCommandList.getCommandCount() > 0);
		if(sendBroadcastMessage == false) {

			// Is auto pause due to lag NOT enabled
			if(this->getClientsAutoPausedDueToLag() == false) {

				// ****NOTE:
				// We always need to broadcast when not pause as clients
				// look for broadcasts every network frame.
				sendBroadcastMessage = true;
			}
			// Auto pause is enabled due to client lagging, only send empty command
			// broadcasts every MAX_EMPTY_NETWORK_COMMAND_LIST_BROADCAST_INTERVAL_MILLISECONDS
			else if(this->getClientsAutoPausedDueToLag() == true &&
					(lastBroadcastCommandsTimer.isStarted() == false ||
					 lastBroadcastCommandsTimer.getMillis() >= MAX_EMPTY_NETWORK_COMMAND_LIST_BROADCAST_INTERVAL_MILLISECONDS)) {

				sendBroadcastMessage = true;
			}
		}

		if(sendBroadcastMessage == true) {

			if(lastBroadcastCommandsTimer.isStarted() == false) {
				lastBroadcastCommandsTimer.start();
			}
			else {
				lastBroadcastCommandsTimer.stop();
				lastBroadcastCommandsTimer.reset();
				lastBroadcastCommandsTimer.start();
			}
			broadcastMessage(&networkMessageCommandList);
		}
	}
	catch(const exception &ex) {
		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		DisplayErrorMessage(ex.what());
	}
}

bool ServerInterface::shouldDiscardNetworkMessage(NetworkMessageType networkMessageType,
												ConnectionSlot *connectionSlot) {
	bool discard = false;
	if(connectionSlot != NULL) {
		switch(networkMessageType) {
			case nmtIntro:
				{
				discard = true;
				NetworkMessageIntro msg = NetworkMessageIntro();
				connectionSlot->receiveMessage(&msg);
				}
				break;
			case nmtPing:
				{
				discard = true;
				NetworkMessagePing msg = NetworkMessagePing();
				connectionSlot->receiveMessage(&msg);
				lastPingInfo = msg;
				}
				break;

			case nmtLaunch:
				{
				discard = true;
				NetworkMessageLaunch msg = NetworkMessageLaunch();
				connectionSlot->receiveMessage(&msg);
				}
				break;
			case nmtText:
				{
				discard = true;
				NetworkMessageText netMsg = NetworkMessageText();
				connectionSlot->receiveMessage(&netMsg);

				ChatMsgInfo msg(netMsg.getText().c_str(),netMsg.getTeamIndex(),netMsg.getPlayerIndex(),netMsg.getTargetLanguage());
				this->addChatInfo(msg);

				string newChatText     = msg.chatText.c_str();
				//string newChatSender   = msg.chatSender.c_str();
				int newChatTeamIndex   = msg.chatTeamIndex;
				int newChatPlayerIndex = msg.chatPlayerIndex;
				string newChatLanguage = msg.targetLanguage.c_str();

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 about to broadcast nmtText chatText [%s] chatTeamIndex = %d, newChatPlayerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex,newChatPlayerIndex);

				NetworkMessageText networkMessageText(newChatText.c_str(),newChatTeamIndex,newChatPlayerIndex,newChatLanguage);
				broadcastMessage(&networkMessageText, connectionSlot->getPlayerIndex());

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);

				}
				break;

			case nmtMarkCell:
				{
				discard = true;
				NetworkMessageMarkCell networkMessageMarkCell;
				connectionSlot->receiveMessage(&networkMessageMarkCell);

            	MarkedCell msg(networkMessageMarkCell.getTarget(),
            			       networkMessageMarkCell.getFactionIndex(),
            			       networkMessageMarkCell.getText().c_str(),
            			       networkMessageMarkCell.getPlayerIndex());

            	this->addMarkedCell(msg);

            	NetworkMessageMarkCell networkMessageMarkCellBroadcast(
            			networkMessageMarkCell.getTarget(),
     			        networkMessageMarkCell.getFactionIndex(),
     			        networkMessageMarkCell.getText().c_str(),
     			        networkMessageMarkCell.getPlayerIndex());
				broadcastMessage(&networkMessageMarkCellBroadcast, connectionSlot->getPlayerIndex());

				//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtMarkCell chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);

				}
				break;

			case nmtUnMarkCell:
				{
				discard = true;
				NetworkMessageUnMarkCell networkMessageMarkCell;
				connectionSlot->receiveMessage(&networkMessageMarkCell);

            	UnMarkedCell msg(networkMessageMarkCell.getTarget(),
            			       networkMessageMarkCell.getFactionIndex());

            	this->addUnMarkedCell(msg);

            	NetworkMessageUnMarkCell networkMessageMarkCellBroadcast(
            			networkMessageMarkCell.getTarget(),
     			        networkMessageMarkCell.getFactionIndex());
				broadcastMessage(&networkMessageMarkCellBroadcast, connectionSlot->getPlayerIndex());

				//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtMarkCell chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);

				}
				break;
			case nmtHighlightCell:
				{
				discard = true;
				NetworkMessageHighlightCell networkMessageHighlightCell;
				connectionSlot->receiveMessage(&networkMessageHighlightCell);

            	MarkedCell msg(networkMessageHighlightCell.getTarget(),
            			networkMessageHighlightCell.getFactionIndex(),
            			"none",-1);

            	this->setHighlightedCell(msg);

            	NetworkMessageHighlightCell networkMessageHighlightCellBroadcast(
            			networkMessageHighlightCell.getTarget(),
            			networkMessageHighlightCell.getFactionIndex());
				broadcastMessage(&networkMessageHighlightCellBroadcast, connectionSlot->getPlayerIndex());

				//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtMarkCell  chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatTeamIndex);

				}
				break;

			case nmtSynchNetworkGameData:
				{
				discard = true;
				NetworkMessageSynchNetworkGameData msg = NetworkMessageSynchNetworkGameData();
				connectionSlot->receiveMessage(&msg);
				}
				break;
			case nmtSynchNetworkGameDataStatus:
				{
				discard = true;
				NetworkMessageSynchNetworkGameDataStatus msg = NetworkMessageSynchNetworkGameDataStatus();
				connectionSlot->receiveMessage(&msg);
				}
				break;
			case nmtSynchNetworkGameDataFileCRCCheck:
				{
				discard = true;
				NetworkMessageSynchNetworkGameDataFileCRCCheck msg = NetworkMessageSynchNetworkGameDataFileCRCCheck();
				connectionSlot->receiveMessage(&msg);
				}
				break;
			case nmtSynchNetworkGameDataFileGet:
				{
				discard = true;
				NetworkMessageSynchNetworkGameDataFileGet msg = NetworkMessageSynchNetworkGameDataFileGet();
				connectionSlot->receiveMessage(&msg);
				}
				break;
			case nmtSwitchSetupRequest:
				{
				discard = true;
				SwitchSetupRequest msg = SwitchSetupRequest();
				connectionSlot->receiveMessage(&msg);
				}
				break;
			case nmtPlayerIndexMessage:
				{
				discard = true;
				PlayerIndexMessage msg = PlayerIndexMessage(0);
				connectionSlot->receiveMessage(&msg);
				}
				break;
		}
	}
	return discard;
}

void ServerInterface::waitUntilReady(Checksum *checksum) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] START\n",__FUNCTION__);
	Logger & logger = Logger::getInstance();
	gameHasBeenInitiated = true;
	Chrono chrono;
	chrono.start();

	bool allReady = false;

	if(Config::getInstance().getBool("EnableGameServerLoadCancel","false") == true) {
		logger.setCancelLoadingEnabled(true);
	}

	Lang &lang							= Lang::getInstance();
	uint64 waitLoopIterationCount 		= 0;
	uint64 MAX_LOOP_COUNT_BEFORE_SLEEP 	= 10;
	MAX_LOOP_COUNT_BEFORE_SLEEP 		= Config::getInstance().getInt("NetworkServerLoopGameLoadingCap",intToStr(MAX_LOOP_COUNT_BEFORE_SLEEP).c_str());
	if(MAX_LOOP_COUNT_BEFORE_SLEEP == 0) {
		MAX_LOOP_COUNT_BEFORE_SLEEP = 1;
	}
	int sleepMillis 		= Config::getInstance().getInt("NetworkServerLoopGameLoadingCapSleepMillis","10");
	int64 lastStatusUpdate 	= 0;

	while(exitServer == false &&
			allReady == false &&
			logger.getCancelLoading() == false) {

		waitLoopIterationCount++;
		if(waitLoopIterationCount > 0 &&
			waitLoopIterationCount % MAX_LOOP_COUNT_BEFORE_SLEEP == 0) {

			sleep(sleepMillis);
			waitLoopIterationCount = 0;
		}
		vector<string> waitingForHosts;
		allReady= true;
		for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index)	{

			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
			ConnectionSlot* connectionSlot= slots[index];
			if(connectionSlot != NULL && connectionSlot->isConnected() == true)	{
				if(connectionSlot->isReady() == false) {

					NetworkMessageType networkMessageType= connectionSlot->getNextMessageType();

					// consume old messages from the lobby
					bool discarded = shouldDiscardNetworkMessage(networkMessageType,connectionSlot);
					if(discarded == false) {

						NetworkMessageReady networkMessageReady;
						if(networkMessageType == nmtReady &&
						   connectionSlot->receiveMessage(&networkMessageReady)) {

							if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] networkMessageType==nmtReady\n",__FUNCTION__);

							connectionSlot->setReady();
							connectionSlot->setGameStarted(true);
						}
						else if(networkMessageType != nmtInvalid) {
							string sErr = "Unexpected network message: " + intToStr(networkMessageType);
							sendTextMessage(sErr,-1, true,"",index);
							DisplayErrorMessage(sErr);
							logger.setCancelLoading(false);
							return;
						}
					}
					waitingForHosts.push_back(connectionSlot->getName());
					allReady= false;
				}
			}
		}

		//check for timeout
		if(allReady == false) {
			if(chrono.getMillis() > readyWaitTimeout) {
		    	Lang &lang= Lang::getInstance();
		    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
		    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {
					string sErr = "Timeout waiting for clients.";
					if(lang.hasString("TimeoutWaitingForClients") == true) {
						sErr = lang.getString("TimeoutWaitingForClients",languageList[langIndex]);
					}
					bool localEcho = lang.isLanguageLocal(languageList[langIndex]);
					sendTextMessage(sErr,-1, localEcho, languageList[langIndex]);
					if(localEcho == true) {
						DisplayErrorMessage(sErr);
					}
		    	}
				logger.setCancelLoading(false);
				return;
			}
			else {
				if(chrono.getMillis() - lastStatusUpdate > 200) {
					lastStatusUpdate = chrono.getMillis();

					string waitForHosts = "";
					for(int hostIndex = 0; hostIndex < (int)waitingForHosts.size(); hostIndex++) {
						if(waitForHosts != "") {
							waitForHosts += ", ";
						}
						waitForHosts += waitingForHosts[hostIndex];
					}

					char szBuf[8096]="";
					string updateTextFormat = lang.getString("NetworkGameServerLoadStatus");
					if(updateTextFormat == "" ||
						updateTextFormat[0] == '?') {

						updateTextFormat =  "Waiting for network: %lld seconds elapsed (maximum wait time: %d seconds)";
					}
					snprintf(szBuf,8096,updateTextFormat.c_str(),(long long int)(chrono.getMillis() / 1000),int(readyWaitTimeout / 1000));

					char szBuf1[8096]="";
					string statusTextFormat = lang.getString("NetworkGameStatusWaiting");
					if(statusTextFormat == "" ||
						statusTextFormat[0] == '?') {

						statusTextFormat =  "Waiting for players: %s";
					}
					snprintf(szBuf1,8096,statusTextFormat.c_str(),waitForHosts.c_str());

					logger.add(szBuf, true, szBuf1);

					uint32 loadingStatus = nmls_NONE;
					//send ready message after, so clients start delayed
					for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
						MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
						ConnectionSlot *connectionSlot= slots[slotIndex];
						if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
							switch(slotIndex) {
								case 0:
									loadingStatus |= nmls_PLAYER1_CONNECTED;
									if(connectionSlot->isReady()) {
										loadingStatus |= nmls_PLAYER1_READY;
									}
									break;
								case 1:
									loadingStatus |= nmls_PLAYER2_CONNECTED;
									if(connectionSlot->isReady()) {
										loadingStatus |= nmls_PLAYER2_READY;
									}
									break;
								case 2:
									loadingStatus |= nmls_PLAYER3_CONNECTED;
									if(connectionSlot->isReady()) {
										loadingStatus |= nmls_PLAYER3_READY;
									}
									break;
								case 3:
									loadingStatus |= nmls_PLAYER4_CONNECTED;
									if(connectionSlot->isReady()) {
										loadingStatus |= nmls_PLAYER4_READY;
									}
									break;
								case 4:
									loadingStatus |= nmls_PLAYER5_CONNECTED;
									if(connectionSlot->isReady()) {
										loadingStatus |= nmls_PLAYER5_READY;
									}
									break;
								case 5:
									loadingStatus |= nmls_PLAYER6_CONNECTED;
									if(connectionSlot->isReady()) {
										loadingStatus |= nmls_PLAYER6_READY;
									}
									break;
								case 6:
									loadingStatus |= nmls_PLAYER7_CONNECTED;
									if(connectionSlot->isReady()) {
										loadingStatus |= nmls_PLAYER7_READY;
									}
									break;
								case 7:
									loadingStatus |= nmls_PLAYER8_CONNECTED;
									if(connectionSlot->isReady()) {
										loadingStatus |= nmls_PLAYER8_READY;
									}
									break;
							}
						}
					}

					// send loading status message
					for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
						MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
						ConnectionSlot* connectionSlot= slots[slotIndex];
						if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
							NetworkMessageLoadingStatus networkMessageLoadingStatus(loadingStatus);
							connectionSlot->sendMessage(&networkMessageLoadingStatus);
						}
					}

					sleep(0);
				}
			}
		}

		Shared::Platform::Window::handleEvent();
	}

	if(logger.getCancelLoading() == true) {
    	Lang &lang= Lang::getInstance();
    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {

			string sErr = lang.getString("GameCancelledByUser",languageList[langIndex]);
			bool localEcho = lang.isLanguageLocal(languageList[langIndex]);
			sendTextMessage(sErr,-1, localEcho,languageList[langIndex]);

			if(localEcho == true) {
				DisplayErrorMessage(sErr);
			}
    	}
		quitGame(true);
		logger.setCancelLoading(false);
		return;
	}

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] PART B (telling client we are ready!\n",__FUNCTION__);
	try {
		//send ready message after, so clients start delayed
		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {

			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
			ConnectionSlot* connectionSlot= slots[slotIndex];
			if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
				NetworkMessageReady networkMessageReady(checksum->getSum());
				connectionSlot->sendMessage(&networkMessageReady);
				connectionSlot->setGameStarted(true);
			}
		}

		gameStartTime = time(NULL);
	}
	catch(const exception &ex) {
		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		DisplayErrorMessage(ex.what());
	}
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] END\n",__FUNCTION__);
}

void ServerInterface::processBroadCastMessageQueue() {
	MutexSafeWrapper safeMutexSlot(broadcastMessageQueueThreadAccessor,CODE_AT_LINE);
	if(broadcastMessageQueue.empty() == false) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] broadcastMessageQueue.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,broadcastMessageQueue.size());
		for(int index = 0; index < (int)broadcastMessageQueue.size(); ++index) {
			pair<NetworkMessage *,int> &item = broadcastMessageQueue[index];
			if(item.first != NULL) {
				this->broadcastMessage(item.first,item.second);
				delete item.first;
			}
			item.first = NULL;
		}
		broadcastMessageQueue.clear();
	}
}

void ServerInterface::queueBroadcastMessage(NetworkMessage *networkMessage, int excludeSlot) {
	MutexSafeWrapper safeMutexSlot(broadcastMessageQueueThreadAccessor,CODE_AT_LINE);
	pair<NetworkMessage*,int> item;
	item.first 	= networkMessage;
	item.second = excludeSlot;
	broadcastMessageQueue.push_back(item);
}

void ServerInterface::processTextMessageQueue() {
	MutexSafeWrapper safeMutexSlot(textMessageQueueThreadAccessor,CODE_AT_LINE);
	if(textMessageQueue.empty() == false) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] textMessageQueue.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,textMessageQueue.size());
		for(int index = 0; index < (int)textMessageQueue.size(); ++index) {
			TextMessageQueue &item = textMessageQueue[index];
			sendTextMessage(item.text, item.teamIndex, item.echoLocal, item.targetLanguage);
		}
		textMessageQueue.clear();
	}
}

void ServerInterface::queueTextMessage(const string & text, int teamIndex,
		bool echoLocal, string targetLanguage) {
	//printf("Line: %d text [%s]\n",__LINE__,text.c_str());

	MutexSafeWrapper safeMutexSlot(textMessageQueueThreadAccessor,CODE_AT_LINE);
	TextMessageQueue item;
	item.text 			= text;
	item.teamIndex 		= teamIndex;
	item.echoLocal 		= echoLocal;
	item.targetLanguage = targetLanguage;
	textMessageQueue.push_back(item);
}

void ServerInterface::sendTextMessage(const string & text, int teamIndex,
		bool echoLocal,string targetLanguage) {
	sendTextMessage(text, teamIndex, echoLocal, targetLanguage, -1);
}

void ServerInterface::sendTextMessage(const string& text, int teamIndex, bool echoLocal,
		string targetLanguage, int lockedSlotIndex) {
	//printf("Line: %d text [%s] echoLocal = %d\n",__LINE__,text.c_str(),echoLocal);

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] text [%s] teamIndex = %d, echoLocal = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,text.c_str(),teamIndex,echoLocal,lockedSlotIndex);

	NetworkMessageText networkMessageText(text, teamIndex, getHumanPlayerIndex(), targetLanguage);
	broadcastMessage(&networkMessageText, -1, lockedSlotIndex);

	if(echoLocal == true) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

		ChatMsgInfo msg(text.c_str(),teamIndex,networkMessageText.getPlayerIndex(), targetLanguage);
		this->addChatInfo(msg);
	}
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

void ServerInterface::sendMarkCellMessage(Vec2i targetPos, int factionIndex, string note,int playerIndex) {
	sendMarkCellMessage(targetPos, factionIndex, note, playerIndex, -1);
}

void ServerInterface::sendMarkCellMessage(Vec2i targetPos, int factionIndex, string note, int playerIndex, int lockedSlotIndex) {
	NetworkMessageMarkCell networkMessageMarkCell(targetPos,factionIndex, note, playerIndex);
	broadcastMessage(&networkMessageMarkCell, -1, lockedSlotIndex);

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

void ServerInterface::sendHighlightCellMessage(Vec2i targetPos, int factionIndex) {
	sendHighlightCellMessage(targetPos, factionIndex, -1);
}

void ServerInterface::sendHighlightCellMessage(Vec2i targetPos, int factionIndex, int lockedSlotIndex) {
	NetworkMessageHighlightCell networkMessageHighlightCell(targetPos,factionIndex);
	broadcastMessage(&networkMessageHighlightCell, -1, lockedSlotIndex);

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

void ServerInterface::sendUnMarkCellMessage(Vec2i targetPos, int factionIndex) {
	sendUnMarkCellMessage(targetPos, factionIndex, -1);
}

void ServerInterface::sendUnMarkCellMessage(Vec2i targetPos, int factionIndex, int lockedSlotIndex) {
	NetworkMessageUnMarkCell networkMessageMarkCell(targetPos,factionIndex);
	broadcastMessage(&networkMessageMarkCell, -1, lockedSlotIndex);

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

void ServerInterface::quitGame(bool userManuallyQuit) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	NetworkMessageQuit networkMessageQuit;
	broadcastMessage(&networkMessageQuit);

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

string ServerInterface::getNetworkStatus() {
	Lang &lang = Lang::getInstance();
	string str = "";
	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		ConnectionSlot *connectionSlot= slots[index];

		str += intToStr(index)+ ": ";

		if(connectionSlot!= NULL) {
			if(connectionSlot->isConnected()) {
				int clientLagCount 					= connectionSlot->getCurrentLagCount();
				double lastClientCommandListTimeLag = difftime((long int)time(NULL),connectionSlot->getLastReceiveCommandListTime());
				//float pingTime = connectionSlot->getThreadedPingMS(connectionSlot->getIpAddress().c_str());
				char szBuf[8096]="";
				snprintf(szBuf,8096,", lag = %d [%.2f]",clientLagCount,lastClientCommandListTimeLag);
				str += connectionSlot->getName() + " [" + connectionSlot->getUUID() + "] " + string(szBuf);
			}
		}
		else {
			str += lang.getString("NotConnected");
		}

		str += '\n';
	}
	return str;
}

bool ServerInterface::launchGame(const GameSettings *gameSettings) {
	bool bOkToStart = true;

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

	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {

		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
		ConnectionSlot *connectionSlot= slots[index];
		if(connectionSlot != NULL &&
		   (connectionSlot->getAllowDownloadDataSynch() == true || connectionSlot->getAllowGameDataSynchCheck() == true) &&
		   connectionSlot->isConnected()) {

			if(connectionSlot->getNetworkGameDataSynchCheckOk() == false) {

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] map [%d] tile [%d] techtree [%d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,connectionSlot->getNetworkGameDataSynchCheckOkMap(),connectionSlot->getNetworkGameDataSynchCheckOkTile(),connectionSlot->getNetworkGameDataSynchCheckOkTech());
				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] map [%d] tile [%d] techtree [%d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,connectionSlot->getNetworkGameDataSynchCheckOkMap(),connectionSlot->getNetworkGameDataSynchCheckOkTile(),connectionSlot->getNetworkGameDataSynchCheckOkTech());

				bOkToStart = false;
				break;
			}
		}
	}
	if(bOkToStart == true) {

		bool useInGameBlockingClientSockets = Config::getInstance().getBool("EnableInGameBlockingSockets","true");
		if(useInGameBlockingClientSockets == true) {

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

			for(int index = 0; index < GameConstants::maxPlayers; ++index) {

				MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
				ConnectionSlot *connectionSlot= slots[index];
				if(connectionSlot != NULL && connectionSlot->isConnected()) {
					connectionSlot->getSocket()->setBlock(true);
				}
			}
		}

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

		bool requiresUPNPTrigger = false;
		for(int startIndex = 0; startIndex < GameConstants::maxPlayers; ++startIndex) {

			int factionIndex = gameSettings->getFactionIndexForStartLocation(startIndex);
			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[startIndex],CODE_AT_LINE_X(startIndex));
			ConnectionSlot *connectionSlot= slots[startIndex];
			if((connectionSlot == NULL || connectionSlot->isConnected() == false) &&
				this->getAllowInGameConnections() == true) {

				// Open slots for joining in progress game
				if(gameSettings->getFactionControl(factionIndex) != ctClosed &&
					gameSettings->getFactionControl(factionIndex) != ctHuman) {

					//printf("Opening slot for in game connections for slot: %d, faction: %d\n",i,factionIndex);
					if(connectionSlot == NULL) {
						addSlot(startIndex);
						connectionSlot 		= slots[startIndex];
						requiresUPNPTrigger = true;
					}
					connectionSlot->setCanAcceptConnections(true);
				}
			}
		}

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

		if(this->getAllowInGameConnections() == false) {
			serverSocket.stopBroadCastThread();
		}

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

		this->gameSettings = *gameSettings;
		//printf("#1 Data synch: lmap %u ltile: %d ltech: %u\n",gameSettings->getMapCRC(),gameSettings->getTilesetCRC(),gameSettings->getTechCRC());

		NetworkMessageLaunch networkMessageLaunch(gameSettings,nmtLaunch);
		broadcastMessage(&networkMessageLaunch);

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

		shutdownMasterserverPublishThread();
		MutexSafeWrapper safeMutex(masterServerThreadAccessor,CODE_AT_LINE);
		lastMasterserverHeartbeatTime = 0;

		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ftpServer = %p\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ftpServer);

		if(this->getAllowInGameConnections() == false) {
			shutdownFTPServer();
		}

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

		if(publishToMasterserverThread == NULL) {
			if(needToRepublishToMasterserver == true ||
				GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {

				static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
				publishToMasterserverThread = new SimpleTaskThread(this,0,125);
				publishToMasterserverThread->setUniqueID(mutexOwnerId);
				publishToMasterserverThread->start();

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

		if(this->getAllowInGameConnections() == false) {
			shutdownFTPServer();
		}

		if((needToRepublishToMasterserver == true ||
			GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) &&
		   requiresUPNPTrigger == true) {

            this->getServerSocket()->NETdiscoverUPnPDevices();
        }

		gameLaunched = true;
	}
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	return bOkToStart;
}

void ServerInterface::shutdownFTPServer() {
	if(ftpServer != NULL) {
		ftpServer->shutdownAndWait();
		delete ftpServer;
		ftpServer = NULL;
	}
}

void ServerInterface::checkListenerSlots() {
	if(gameLaunched == true &&
		this->getAllowInGameConnections() == true) {

		if(difftime((long int)time(NULL),lastListenerSlotCheckTime) >= 7) {

			lastListenerSlotCheckTime 			= time(NULL);
			bool useInGameBlockingClientSockets = Config::getInstance().getBool("EnableInGameBlockingSockets","true");

			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
			for(int startIndex = 0; startIndex < GameConstants::maxPlayers; ++startIndex) {

				int factionIndex = gameSettings.getFactionIndexForStartLocation(startIndex);
				if(gameSettings.getFactionControl(factionIndex) != ctClosed &&
					gameSettings.getFactionControl(factionIndex) != ctHuman) {

					MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[startIndex],CODE_AT_LINE_X(startIndex));
					ConnectionSlot *connectionSlot= slots[startIndex];
					// Open slots for joining in progress game
					if(connectionSlot == NULL) {
						printf("Opening slot for in game connections, slot: %d, factionindex: %d name: %s\n",startIndex,factionIndex,gameSettings.getFactionTypeName(factionIndex).c_str());

						addSlot(startIndex);
						connectionSlot = slots[startIndex];
						if(useInGameBlockingClientSockets == true) {
							connectionSlot->getSocket()->setBlock(true);
						}
						connectionSlot->setCanAcceptConnections(true);
					}
					else if(connectionSlot != NULL &&
							connectionSlot->getCanAcceptConnections() == false &&
							connectionSlot->isConnected() == false) {
						printf("Removing slot for in game connections, slot: %d, factionindex: %d name: %s\n",startIndex,factionIndex,gameSettings.getFactionTypeName(factionIndex).c_str());

						this->removeSlot(startIndex);
					}
				}
			}
		}
	}
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] needToRepublishToMasterserver = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,needToRepublishToMasterserver);
}

void ServerInterface::broadcastGameSetup(GameSettings *gameSettingsBuffer, bool setGameSettingsBuffer) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	if(gameSettingsBuffer == NULL) {
		throw megaglest_runtime_error("gameSettingsBuffer == NULL");
	}
	for(unsigned int factionIndex = 0; factionIndex < (unsigned int)gameSettingsBuffer->getFactionCount(); ++factionIndex) {

		int slotIndex = gameSettingsBuffer->getStartLocationIndex(factionIndex);
		if(gameSettingsBuffer->getFactionControl(factionIndex) == ctNetwork &&
			isClientConnected(slotIndex) == false) {

			gameSettingsBuffer->setNetworkPlayerName(factionIndex,GameConstants::NETWORK_SLOT_UNCONNECTED_SLOTNAME);
		}
	}
	if(setGameSettingsBuffer == true) {
		validateGameSettings(gameSettingsBuffer);
	}

	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
	if(setGameSettingsBuffer == true) {
		gameSettings = *gameSettingsBuffer;
		gameSettingsUpdateCount++;
	}

	NetworkMessageLaunch networkMessageLaunch(gameSettingsBuffer, nmtBroadCastSetup);
	broadcastMessage(&networkMessageLaunch);

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

void ServerInterface::broadcastMessage(NetworkMessage *networkMessage, int excludeSlot, int lockedSlotIndex) {
	try {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	    MutexSafeWrapper safeMutexSlotBroadCastAccessor(inBroadcastMessageThreadAccessor,CODE_AT_LINE);
	    if(inBroadcastMessage == true &&
	    	dynamic_cast<NetworkMessageText *>(networkMessage) != NULL) {

	    	safeMutexSlotBroadCastAccessor.ReleaseLock();
	    	NetworkMessageText *txtMsg = dynamic_cast<NetworkMessageText *>(networkMessage);
	    	if(txtMsg != NULL) {
	    		NetworkMessageText *msgCopy = txtMsg->getCopy();
	    		queueBroadcastMessage(msgCopy, excludeSlot);
	    	}
	    	return;
	    }
	    else {
			inBroadcastMessage = true;
			safeMutexSlotBroadCastAccessor.ReleaseLock(true);
	    }

		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
			MutexSafeWrapper safeMutexSlot(NULL,CODE_AT_LINE_X(slotIndex));
			if(slotIndex != lockedSlotIndex) {
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] i = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex,lockedSlotIndex);
				safeMutexSlot.setMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
			}

			ConnectionSlot* connectionSlot= slots[slotIndex];

			if(slotIndex != excludeSlot && connectionSlot != NULL) {
				if(connectionSlot->isConnected()) {
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] before sendMessage\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					connectionSlot->sendMessage(networkMessage);

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after sendMessage\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
				}
				if(gameHasBeenInitiated == true && connectionSlot->isConnected() == false) {
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 before removeSlot for slot# %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex);

					if(this->getAllowInGameConnections() == false) {
						removeSlot(slotIndex,slotIndex);
					}
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 after removeSlot for slot# %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex);
				}
			}
			else if(slotIndex == excludeSlot && gameHasBeenInitiated == true &&
					connectionSlot != NULL && connectionSlot->isConnected() == false) {

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #2 before removeSlot for slot# %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex);

				if(this->getAllowInGameConnections() == false) {
					removeSlot(slotIndex,slotIndex);
				}
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #2 after removeSlot for slot# %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex);
			}
		}

		safeMutexSlotBroadCastAccessor.Lock();

	    inBroadcastMessage = false;

	    safeMutexSlotBroadCastAccessor.ReleaseLock();
	}
	catch(const exception &ex) {
		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ERROR [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());

		MutexSafeWrapper safeMutexSlotBroadCastAccessor(inBroadcastMessageThreadAccessor,CODE_AT_LINE);
	    inBroadcastMessage = false;
	    safeMutexSlotBroadCastAccessor.ReleaseLock();

		string sMsg = ex.what();
		sendTextMessage(sMsg,-1, true, "", lockedSlotIndex);
	}
}

void ServerInterface::broadcastMessageToConnectedClients(NetworkMessage *networkMessage, int excludeSlot) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
	try {
		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
			ConnectionSlot *connectionSlot= slots[slotIndex];

			if(slotIndex != excludeSlot && connectionSlot != NULL) {
				if(connectionSlot->isConnected()) {
					connectionSlot->sendMessage(networkMessage);
				}
			}
		}
	}
	catch(const exception &ex) {
		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ERROR [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		DisplayErrorMessage(ex.what());
	}
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

void ServerInterface::updateListen() {
	if(gameHasBeenInitiated == true &&
		this->getAllowInGameConnections() == false) {
		return;
	}

	int openSlotCount = 0;
	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex)	{

		bool isSlotOpen = (slots[slotIndex] != NULL && slots[slotIndex]->isConnected() == false);
		if(isSlotOpen == true) {
			++openSlotCount;
		}
	}

	serverSocket.listen(openSlotCount);
}

int ServerInterface::getOpenSlotCount() {
	int openSlotCount = 0;
	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex)	{

		bool isSlotOpen = (slots[slotIndex] != NULL && slots[slotIndex]->isConnected() == false);
		if(isSlotOpen == true) {
			++openSlotCount;
		}
	}
	return openSlotCount;
}

int ServerInterface::getGameSettingsUpdateCount() {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START gameSettingsUpdateCount = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,gameSettingsUpdateCount);

	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
	int result = gameSettingsUpdateCount;
	safeMutex.ReleaseLock();
	return result;
}

void ServerInterface::validateGameSettings(GameSettings *serverGameSettings) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
	string mapFile = serverGameSettings->getMap();
	//printf("Trying to set map to [%s]. Current map is [%s]\n",serverGameSettings->getMap().c_str(),gameSettings.getMap().c_str());
	if(gameSettings.getMapFilter()!=serverGameSettings->getMapFilter()){
		if( playerSortedMaps[serverGameSettings->getMapFilter()].size()==0){
			serverGameSettings->setMapFilter(0);
		}
	}
	int playerIndex=serverGameSettings->getMapFilter();
	if(find(playerSortedMaps[playerIndex].begin(),playerSortedMaps[playerIndex].end(),mapFile) == playerSortedMaps[playerIndex].end()) {
		// switch to closest map
		string foundMap = "";
		for (int i = 0 ;i < (int)playerSortedMaps[playerIndex].size(); ++i) {
			foundMap=playerSortedMaps[playerIndex][i];
			if(toLower(foundMap)>toLower(serverGameSettings->getMap())){
				break;
			}
		}
		printf("map %s not found on this server. Switching to map %s\n",serverGameSettings->getMap().c_str(),foundMap.c_str());
		serverGameSettings->setMap(foundMap);
	}
	Checksum checksum;
	string file = Config::getMapPath(serverGameSettings->getMap(),"",false);
	checksum.addFile(file);
	serverGameSettings->setMapCRC(checksum.getSum());

	string tilesetFile = serverGameSettings->getTileset();
	if(find(tilesetFiles.begin(),tilesetFiles.end(),tilesetFile) == tilesetFiles.end()) {
		printf("Reverting tileset from [%s] to [%s]\n",serverGameSettings->getTileset().c_str(),gameSettings.getTileset().c_str());

		serverGameSettings->setTileset(gameSettings.getTileset());
		serverGameSettings->setTilesetCRC(gameSettings.getTilesetCRC());
	}

	string techtreeFile = serverGameSettings->getTech();
	if(find(techTreeFiles.begin(),techTreeFiles.end(),techtreeFile) == techTreeFiles.end()) {
		printf("Reverting tech from [%s] to [%s]\n",serverGameSettings->getTech().c_str(),gameSettings.getTech().c_str());

		serverGameSettings->setTech(gameSettings.getTech());
		serverGameSettings->setTechCRC(gameSettings.getTechCRC());
	}
}

void ServerInterface::setGameSettings(GameSettings *serverGameSettings, bool waitForClientAck) {
	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START gameSettingsUpdateCount = %d, waitForClientAck = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,gameSettingsUpdateCount,waitForClientAck);

	if(serverGameSettings->getScenario() == "") {
		string mapFile = serverGameSettings->getMap();
		if(find(mapFiles.begin(),mapFiles.end(),mapFile) == mapFiles.end()) {
			printf("Reverting map from [%s] to [%s]\n",serverGameSettings->getMap().c_str(),gameSettings.getMap().c_str());
	
			serverGameSettings->setMapFilter(gameSettings.getMapFilter());
			serverGameSettings->setMap(gameSettings.getMap());
			serverGameSettings->setMapCRC(gameSettings.getMapCRC());
		}
	
		string tilesetFile = serverGameSettings->getTileset();
		if(find(tilesetFiles.begin(),tilesetFiles.end(),tilesetFile) == tilesetFiles.end()) {
			printf("Reverting tileset from [%s] to [%s]\n",serverGameSettings->getTileset().c_str(),gameSettings.getTileset().c_str());
	
			serverGameSettings->setTileset(gameSettings.getTileset());
			serverGameSettings->setTilesetCRC(gameSettings.getTilesetCRC());
		}
	
		string techtreeFile = serverGameSettings->getTech();
		if(find(techTreeFiles.begin(),techTreeFiles.end(),techtreeFile) == techTreeFiles.end()) {
			printf("Reverting tech from [%s] to [%s]\n",serverGameSettings->getTech().c_str(),gameSettings.getTech().c_str());
	
			serverGameSettings->setTech(gameSettings.getTech());
			serverGameSettings->setTechCRC(gameSettings.getTechCRC());
		}
	}

	gameSettings = *serverGameSettings;

	if(getAllowGameDataSynchCheck() == true) {
		if(waitForClientAck == true && gameSettingsUpdateCount > 0) {
			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Waiting for client acks #1\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

			time_t tStart = time(NULL);
			bool gotAckFromAllClients = false;
			while(gotAckFromAllClients == false && difftime((long int)time(NULL),tStart) <= 5) {
				gotAckFromAllClients = true;
				for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
					//printf("===> START slot %d - About to setGameSettings #1\n",i);

					MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
					ConnectionSlot *connectionSlot = slots[slotIndex];
					if(connectionSlot != NULL && connectionSlot->isConnected()) {
						if(connectionSlot->getReceivedNetworkGameStatus() == false) {
							gotAckFromAllClients = false;
						}

						connectionSlot->update(true,slotIndex);
					}
					//printf("===> END slot %d - About to setGameSettings #1\n",i);
				}
			}
		}

		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
			ConnectionSlot *connectionSlot = slots[slotIndex];
			if(connectionSlot != NULL && connectionSlot->isConnected()) {
				connectionSlot->setReceivedNetworkGameStatus(false);
			}
		}

		NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData(getGameSettings());
		broadcastMessageToConnectedClients(&networkMessageSynchNetworkGameData);

		if(waitForClientAck == true) {
			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Waiting for client acks #2\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

			time_t tStart = time(NULL);
			bool gotAckFromAllClients = false;
			while(gotAckFromAllClients == false && difftime((long int)time(NULL),tStart) <= 5) {
				gotAckFromAllClients = true;
				for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
					//printf("===> START slot %d - About to setGameSettings 2\n",slotIndex);

					MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
					ConnectionSlot *connectionSlot = slots[slotIndex];
					if(connectionSlot != NULL && connectionSlot->isConnected()) {
						if(connectionSlot->getReceivedNetworkGameStatus() == false) {
							gotAckFromAllClients = false;
						}

						connectionSlot->update(true,slotIndex);
					}
					//printf("===> END slot %d - About to setGameSettings 2\n",slotIndex);
				}
			}
		}

	}
	gameSettingsUpdateCount++;
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
}

void ServerInterface::close() {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
}

string ServerInterface::getHumanPlayerName(int index) {
	string result = Config::getInstance().getString("NetPlayerName", Socket::getHostName().c_str());
	if(index >= 0 || gameSettings.getThisFactionIndex() >= 0) {
		if(index < 0) {
			index = gameSettings.getThisFactionIndex();
		}
		if(gameSettings.getNetworkPlayerName(index) != "") {
			result = gameSettings.getNetworkPlayerName(index);
		}
	}

	return result;
}

int ServerInterface::getHumanPlayerIndex() const {
	return gameSettings.getStartLocationIndex(gameSettings.getThisFactionIndex());
}

std::map<string,string> ServerInterface::publishToMasterserver() {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
	int slotCountUsed = 1;
	int slotCountHumans = 1;
	int slotCountConnectedPlayers = 1;

	if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
		slotCountUsed = 0;
		slotCountHumans = 0;
		slotCountConnectedPlayers = 0;
	}

	Config & config = Config::getInstance();
	std::map < string, string > publishToServerInfo;
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
		if(slots[slotIndex] != NULL) {
			slotCountUsed++;
			slotCountHumans++;
			ConnectionSlot* connectionSlot= slots[slotIndex];
			if((connectionSlot!=NULL) && (connectionSlot->isConnected())) {
				slotCountConnectedPlayers++;
			}
		}
	}
	publishToServerInfo["uuid"] 				= Config::getInstance().getString("PlayerId","");
	publishToServerInfo["glestVersion"] 		= glestVersionString;
	publishToServerInfo["platform"] 			= getPlatformNameString() + "-" + getGITRevisionString();
	publishToServerInfo["binaryCompileDate"] 	= getCompileDateTime();
	publishToServerInfo["serverTitle"] 			= this->getGameSettings()->getGameName();
	publishToServerInfo["tech"] 				= this->getGameSettings()->getTech();
	publishToServerInfo["map"] 					= this->getGameSettings()->getMap();
	publishToServerInfo["tileset"] 				= this->getGameSettings()->getTileset();

	bool updateSlots = true;
	MutexSafeWrapper safeMutex2(gameStatsThreadAccessor,CODE_AT_LINE);
	if(gameStats != NULL) {
		for(int factionIndex = 0; factionIndex < gameStats->getFactionCount(); ++factionIndex) {
			if(gameStats->getVictory(factionIndex) == true) {
				updateSlots = false;
				break;
			}
		}
	}
	safeMutex2.ReleaseLock();

	if(updateSlots == true) {
		publishToServerInfo["activeSlots"] 		= intToStr(slotCountUsed);
		publishToServerInfo["networkSlots"] 	= intToStr(slotCountHumans);
		publishToServerInfo["connectedClients"] = intToStr(slotCountConnectedPlayers);
	}

	string serverPort							= config.getString("PortServer", intToStr(GameConstants::serverPort).c_str());
	string externalPort							= config.getString("PortExternal", serverPort.c_str());
	publishToServerInfo["externalconnectport"] 	= externalPort;
	publishToServerInfo["privacyPlease"] 		= intToStr(config.getBool("PrivacyPlease","false"));
	publishToServerInfo["gameStatus"] 			= intToStr(game_status_in_progress);

	if(publishToMasterserverThread == NULL) {
		publishToServerInfo["gameCmd"]		= "gameOver";
		publishToServerInfo["gameStatus"] 	= intToStr(game_status_finished);
	}

	//printf("Host game id = %s\n",this->getGameSettings()->getGameUUID().c_str());
	publishToServerInfo["gameUUID"] = this->getGameSettings()->getGameUUID();

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

std::map<string,string> ServerInterface::publishToMasterserverStats() {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	MutexSafeWrapper safeMutex(gameStatsThreadAccessor,CODE_AT_LINE);
	std::map < string, string > publishToServerInfo;
	if(gameStats != NULL) {
		publishToServerInfo["gameUUID"] 						= this->getGameSettings()->getGameUUID();
		publishToServerInfo["tech"] 							= this->getGameSettings()->getTech();
		publishToServerInfo["factionCount"] 					= intToStr(gameStats->getFactionCount());
		publishToServerInfo["framesPlayed"] 					= intToStr(gameStats->getFramesPlayed());
		publishToServerInfo["framesToCalculatePlaytime"] 		= intToStr(gameStats->getFramesToCalculatePlaytime());
		publishToServerInfo["maxConcurrentUnitCount"] 			= intToStr(gameStats->getMaxConcurrentUnitCount());
		publishToServerInfo["totalEndGameConcurrentUnitCount"] 	= intToStr(gameStats->getTotalEndGameConcurrentUnitCount());
		publishToServerInfo["isHeadlessServer"] 				= intToStr(gameStats->getIsMasterserverMode());

		for(int factionIndex = 0; factionIndex < gameStats->getFactionCount(); ++factionIndex) {
			publishToServerInfo["factionIndex_" + intToStr(factionIndex)] 		= intToStr(factionIndex);
			publishToServerInfo["controlType_" + intToStr(factionIndex)] 		= intToStr(gameStats->getControl(factionIndex));
			publishToServerInfo["resourceMultiplier_" + intToStr(factionIndex)] = floatToStr(gameStats->getResourceMultiplier(factionIndex));
			publishToServerInfo["factionTypeName_" + intToStr(factionIndex)] 	= gameStats->getFactionTypeName(factionIndex);
			publishToServerInfo["personalityType_" + intToStr(factionIndex)] 	= intToStr(gameStats->getPersonalityType(factionIndex));
			publishToServerInfo["teamIndex_" + intToStr(factionIndex)] 			= intToStr(gameStats->getTeam(factionIndex));
			publishToServerInfo["wonGame_" + intToStr(factionIndex)] 			= intToStr(gameStats->getVictory(factionIndex));
			publishToServerInfo["killCount_" + intToStr(factionIndex)] 			= intToStr(gameStats->getKills(factionIndex));
			publishToServerInfo["enemyKillCount_" + intToStr(factionIndex)] 	= intToStr(gameStats->getEnemyKills(factionIndex));
			publishToServerInfo["deathCount_" + intToStr(factionIndex)] 		= intToStr(gameStats->getDeaths(factionIndex));
			publishToServerInfo["unitsProducedCount_" + intToStr(factionIndex)] = intToStr(gameStats->getUnitsProduced(factionIndex));
			publishToServerInfo["resourceHarvestedCount_" + intToStr(factionIndex)] = intToStr(gameStats->getResourcesHarvested(factionIndex));
			publishToServerInfo["playerName_" + intToStr(factionIndex)] 		= gameStats->getPlayerName(factionIndex);
			publishToServerInfo["quitBeforeGameEnd_" + intToStr(factionIndex)] 	= intToStr(gameStats->getPlayerLeftBeforeEnd(factionIndex));
			publishToServerInfo["quitTime_" + intToStr(factionIndex)] 			= intToStr(gameStats->getTimePlayerLeft(factionIndex));
			publishToServerInfo["playerUUID_" + intToStr(factionIndex)] 	    = this->getGameSettings()->getNetworkPlayerUUID(factionIndex);
			publishToServerInfo["platform_" + intToStr(factionIndex)] 	    = this->getGameSettings()->getNetworkPlayerPlatform(factionIndex);
		}
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
	}
	return publishToServerInfo;
}

void ServerInterface::setGameStats(Stats *stats) {
	if(stats == NULL) {
		return;
	}
	MutexSafeWrapper safeMutex(gameStatsThreadAccessor,CODE_AT_LINE);
	if(gameStats == NULL) {
		gameStats = new Stats();
	}
	*gameStats = *stats;
}

void ServerInterface::simpleTask(BaseThread *callingThread,void *userdata) {
	MutexSafeWrapper safeMutex(masterServerThreadAccessor,CODE_AT_LINE);

	if(difftime((long int)time(NULL),lastMasterserverHeartbeatTime) >= MASTERSERVER_HEARTBEAT_GAME_STATUS_SECONDS) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Checking to see masterserver needs an update of the game status [%d] callingThread [%p] publishToMasterserverThread [%p]\n",needToRepublishToMasterserver,callingThread,publishToMasterserverThread);

		lastMasterserverHeartbeatTime = time(NULL);
		if(needToRepublishToMasterserver == true) {
			try {
				if(Config::getInstance().getString("Masterserver","") != "") {
					string request = Config::getInstance().getString("Masterserver");
					if(request != "") {
						endPathWithSlash(request,false);
					}
					request += "addServerInfo.php?";

					std::map<string,string> newPublishToServerInfo = publishToMasterserver();

					CURL *handle = SystemFlags::initHTTP();
					for(std::map<string,string>::const_iterator iterMap = newPublishToServerInfo.begin();
						iterMap != newPublishToServerInfo.end(); ++iterMap) {

						request += iterMap->first;
						request += "=";
						request += SystemFlags::escapeURL(iterMap->second,handle);
						request += "&";
					}

					//printf("The Host request is:\n%s\n",request.c_str());
					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("The Host request is:\n%s\n",request.c_str());

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] the request is:\n%s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,request.c_str());

					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Calling masterserver [%s]...\n",request.c_str());

					std::string serverInfo = SystemFlags::getHTTP(request,handle);
					//printf("Result:\n%s\n",serverInfo .c_str());

					string requestStats = Config::getInstance().getString("Masterserver");
					if(requestStats != "") {
						endPathWithSlash(requestStats,false);
					}
					requestStats += "addGameStats.php?";

					std::map<string,string> newPublishToServerInfoStats = publishToMasterserverStats();
					if(newPublishToServerInfoStats.empty() == false) {
						for(std::map<string,string>::const_iterator iterMap = newPublishToServerInfoStats.begin();
							iterMap != newPublishToServerInfoStats.end(); ++iterMap) {

							requestStats += iterMap->first;
							requestStats += "=";
							requestStats += SystemFlags::escapeURL(iterMap->second,handle);
							requestStats += "&";
						}

						//printf("The Host stats request is:\n%s\n",requestStats.c_str());
						if(SystemFlags::VERBOSE_MODE_ENABLED) printf("The Host request is:\n%s\n",requestStats.c_str());
						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] the request is:\n%s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,requestStats.c_str());
						if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Calling masterserver [%s]...\n",requestStats.c_str());

						std::string serverInfoStats = SystemFlags::getHTTP(requestStats,handle);
						//printf("Result:\n%s\n",serverInfoStats .c_str());

						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] the result is:\n'%s'\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,serverInfoStats.c_str());
					}

					SystemFlags::cleanupHTTP(&handle);

					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Done Calling masterserver\n");

					//printf("the result is:\n'%s'\n",serverInfo.c_str());
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] the result is:\n'%s'\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,serverInfo.c_str());
				}
				else {
					SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line %d] error, no masterserver defined!\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
				}
			}
			catch(const exception &ex) {
				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line %d] error during game status update: [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
			}
		}
		if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
			DumpStatsToLog(false);
		}
	}
	if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
		//printf("Attempt Accept\n");
		if(serverSocketAdmin != NULL) {
			Socket *cli = serverSocketAdmin->accept(false);
			if(cli != NULL) {
				printf("Got status request connection, dumping info...\n");

				string data = DumpStatsToLog(true);
				cli->send(data.c_str(),(int)data.length());
				cli->disconnectSocket();
			}
		}
	}
}

std::string ServerInterface::DumpStatsToLog(bool dumpToStringOnly) const {
	string headlessLogFile = Config::getInstance().getString("HeadlessLogFile","headless.log");
	if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
		headlessLogFile  = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + headlessLogFile ;
	}
	else {
        string userData = Config::getInstance().getString("UserData_Root","");
        if(userData != "") {
        	endPathWithSlash(userData);
        }
        headlessLogFile  = userData + headlessLogFile ;
	}

	ostringstream out;
	out << "========================================="  << std::endl;
	out << "Headless Server Current Game information:"  << std::endl;
	out << "========================================="  << std::endl;

	int connectedSlotCount = 0;
	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {

		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
		ConnectionSlot *slot = slots[slotIndex];
		if(slot != NULL) {

			connectedSlotCount++;
			out << "Network connection for index: " << slotIndex << std::endl;
			out << "------------------------------" << std::endl;
			out << "Connected: " << boolToStr(slot->isConnected()) << std::endl;
			out << "Handshake received: " << boolToStr(slot->getConnectHasHandshaked()) << std::endl;
			if(slot->isConnected() == true) {

				time_t connectTime 	= slot->getConnectedTime();
				//struct tm *loctime 	= localtime (&connectTime);
				struct tm loctime = threadsafe_localtime(connectTime);
				char szBuf[8096]	= "";
				strftime(szBuf,100,"%Y-%m-%d %H:%M:%S",&loctime);

				const int HOURS_IN_DAY 		= 24;
				const int MINUTES_IN_HOUR 	= 60;
				const int SECONDS_IN_MINUTE = 60;
				int InSeconds 				= difftime((long int)time(NULL),slot->getConnectedTime());
				// compute seconds
				int seconds = InSeconds % SECONDS_IN_MINUTE ;
				// throw away seconds used in previous statement and convert to minutes
				int InMinutes = InSeconds / SECONDS_IN_MINUTE ;
				// compute  minutes
				int minutes = InMinutes % MINUTES_IN_HOUR ;

				// throw away minutes used in previous statement and convert to hours
				int InHours = InMinutes / MINUTES_IN_HOUR ;
				// compute hours
				int hours = InHours % HOURS_IN_DAY ;

				out << "Connected at: " 		<< szBuf 					<< std::endl;
				out << "Connection duration: " 	<< hours << " hours " << minutes << " minutes " << seconds << " seconds." << std::endl;
				out << "Player Index: " 		<< slot->getPlayerIndex() 	<< std::endl;
				out << "IP Address: " 			<< slot->getIpAddress() 	<< std::endl;
				out << "Player name: " 			<< slot->getName() 			<< std::endl;
				out << "Player uuid: " 			<< slot->getUUID() 			<< std::endl;
				out << "Language: " 			<< slot->getNetworkPlayerLanguage() << std::endl;
				out << "Game Version: " 		<< slot->getVersionString() << std::endl;
				out << "Session id: " 			<< slot->getSessionKey() 	<< std::endl;
				out << "Socket id: " 			<< slot->getSocketId() 		<< std::endl;
			}
		}
	}
	out << "Total Slot Count: " << connectedSlotCount 	<< std::endl;
	out << "========================================="  << std::endl;

	std::string result = out.str();

	if(dumpToStringOnly == false) {

#if defined(WIN32) && !defined(__MINGW32__)
		FILE *fp = _wfopen(utf8_decode(headlessLogFile ).c_str(), L"w");
		std::ofstream logFile(fp);
#else
		std::ofstream logFile;
		logFile.open(headlessLogFile .c_str(), ios_base::out | ios_base::trunc);
#endif
		logFile << result;
		logFile.close();
#if defined(WIN32) && !defined(__MINGW32__)
		if(fp) {
			fclose(fp);
		}
#endif
	}

    return result;
}

void ServerInterface::notifyBadClientConnectAttempt(string ipAddress) {
	//printf("In [%s::%s Line: %d] ipAddress [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ipAddress.c_str());

	if(badClientConnectIPList.find(ipAddress) == badClientConnectIPList.end()) {
		badClientConnectIPList[ipAddress] = make_pair(0,(long int)time(NULL));
	}

	pair<uint64,time_t> &lastBadConnectionAttempt = badClientConnectIPList[ipAddress];

	const uint64 BLOCK_BAD_CLIENT_CONNECT_MAX_SECONDS 	= Config::getInstance().getInt("BlockBadClientConnectMaxSeconds", "60");
	const uint64 BLOCK_BAD_CLIENT_CONNECT_MAX_ATTEMPTS 	= Config::getInstance().getInt("BlockBadClientConnectMaxAttempts", "6");
	bool addToBlockedClientsList 						= false;

	if(difftime((long int)time(NULL),lastBadConnectionAttempt.second) <= BLOCK_BAD_CLIENT_CONNECT_MAX_SECONDS) {

		if(lastBadConnectionAttempt.first+1 > BLOCK_BAD_CLIENT_CONNECT_MAX_ATTEMPTS) {
			addToBlockedClientsList = true;
		}
	}
	else {
		// Reset after x seconds
		lastBadConnectionAttempt.first = 0;
	}

	if(this->getAllowInGameConnections() == true) {
		printf("notifyBadClientConnectAttempt() #1: %s!\n",ipAddress.c_str());
	}

	if(addToBlockedClientsList == true) {
		serverSocket.addIPAddressToBlockedList(ipAddress);
	}

	lastBadConnectionAttempt.first++;
	lastBadConnectionAttempt.second = time(NULL);
}

bool ServerInterface::getStartInGameConnectionLaunch() {
	bool result = false;
	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
		MutexSafeWrapper safeMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
		if(slots[slotIndex] != NULL) {

			ConnectionSlot *slot = slots[slotIndex];
			if(slot->getStartInGameConnectionLaunch() == true) {
				result = true;
				break;
			}
		}
	}
	return result;
}

bool ServerInterface::getPauseForInGameConnection() {
	bool result = false;
	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
		MutexSafeWrapper safeMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
		if(slots[slotIndex] != NULL) {

			ConnectionSlot *slot = slots[slotIndex];
			if(slot->getPauseForInGameConnection() == true) {
				result = true;
				break;
			}
		}
	}
	return result;
}

bool ServerInterface::getUnPauseForInGameConnection() {
	bool result = false;
	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
		MutexSafeWrapper safeMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
		if(slots[slotIndex] != NULL) {

			ConnectionSlot *slot = slots[slotIndex];
			if(slot->isConnected() == true) {
				if(slot->isReady() == true) {
					result = true;
					if(slot->getUnPauseForInGameConnection() == false) {
						result = false;
						break;
					}
				}
				else {
					result = false;
					break;
				}
			}
		}
	}
	if(result == true) {
		resumeGameStartTime = time(NULL);
	}
	return result;
}

ConnectionSlot * ServerInterface::findSlotForUUID(string uuid, bool unConnectedOnly) {
	ConnectionSlot *result = NULL;
	if(uuid != "") {
		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {

			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
			ConnectionSlot *connectionSlot= slots[slotIndex];

			if(connectionSlot != NULL) {
				if(connectionSlot->getUUID() == uuid) {
					if(unConnectedOnly == false ||
						(unConnectedOnly == true && connectionSlot->isConnected() == false)) {

						if(result == NULL ||
							(result->getConnectedTime() > connectionSlot->getConnectedTime()))

						result = connectionSlot;
					}
				}
			}
		}
	}
	return result;
}

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

	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
		MutexSafeWrapper safeMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
		if(slots[slotIndex] != NULL) {

			XmlNode *slotNode = serverInterfaceNode->addChild("Slot");

			ConnectionSlot *slot = slots[slotIndex];
			if(slot != NULL) {
				slotNode->addAttribute("isconnected",intToStr(slot->isConnected()), mapTagReplacements);
				slotNode->addAttribute("sessionkey",intToStr(slot->getSessionKey()), mapTagReplacements);
				slotNode->addAttribute("ipaddress",slot->getSocket(false)->getIpAddress(), mapTagReplacements);
				slotNode->addAttribute("name",slot->getName(), mapTagReplacements);
				slotNode->addAttribute("uuid",slot->getUUID(), mapTagReplacements);
			}
			else {
				slotNode->addAttribute("isconnected",intToStr(false), mapTagReplacements);
			}
		}
	}
}

}}//end namespace
