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

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

#include "connection_slot.h"

#include "conversion.h"
#include "game_util.h"
#include "config.h"
#include "server_interface.h"
#include "network_message.h"
#include "platform_util.h"
#include <stdexcept>
#include "shared_const.h"

#include "leak_dumper.h"

using namespace std;
using namespace Shared;
using namespace Shared::Util;

namespace Game {
	// =====================================================
	//	class ConnectionSlotThread
	// =====================================================

	ConnectionSlotThread::ConnectionSlotThread(int slotIndex) : BaseThread() {
		this->masterController = NULL;
		this->triggerIdMutex = new Mutex(CODE_AT_LINE);
		this->slotIndex = slotIndex;
		this->slotInterface = NULL;
		uniqueID = "ConnectionSlotThread";
		eventList.clear();
		eventList.reserve(1000);

		triggerGameStarted = new Mutex(CODE_AT_LINE);
		gameStarted = false;
	}

	ConnectionSlotThread::ConnectionSlotThread(ConnectionSlotCallbackInterface *slotInterface, int slotIndex) : BaseThread() {
		this->masterController = NULL;
		this->triggerIdMutex = new Mutex(CODE_AT_LINE);
		this->slotIndex = slotIndex;
		this->slotInterface = slotInterface;
		uniqueID = "ConnectionSlotThread";
		eventList.clear();

		triggerGameStarted = new Mutex(CODE_AT_LINE);
		gameStarted = false;
	}

	ConnectionSlotThread::~ConnectionSlotThread() {
		delete triggerIdMutex;
		triggerIdMutex = NULL;

		delete triggerGameStarted;
		triggerGameStarted = NULL;
	}

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

		BaseThread::setQuitStatus(value);
		if (value == true) {
			signalUpdate(NULL);
		}

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

	void ConnectionSlotThread::signalUpdate(ConnectionSlotEvent *event) {
		if (event != NULL) {
			MutexSafeWrapper safeMutex(triggerIdMutex, CODE_AT_LINE);
			eventList.push_back(*event);
		}
		if (getGameStarted() == true && getQuitStatus() == true) {
			return;
		}
		semTaskSignalled.signal();
	}

	void ConnectionSlotThread::setTaskCompleted(int eventId) {
		if (eventId > 0) {
			MutexSafeWrapper safeMutex(triggerIdMutex, CODE_AT_LINE);
			for (int index = 0; index < (int) eventList.size(); ++index) {
				ConnectionSlotEvent &slotEvent = eventList[index];
				if (slotEvent.eventId == eventId) {
					slotEvent.eventCompleted = true;
					break;
				}
			}
		}
	}

	//void ConnectionSlotThread::purgeAllEvents() {
	//    MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE);
	//    eventList.clear();
	//}

	void ConnectionSlotThread::setAllEventsCompleted() {
		MutexSafeWrapper safeMutex(triggerIdMutex, CODE_AT_LINE);
		for (int index = 0; index < (int) eventList.size(); ++index) {
			ConnectionSlotEvent &slotEvent = eventList[index];
			if (slotEvent.eventCompleted == false) {
				slotEvent.eventCompleted = true;
			}
		}
	}

	void ConnectionSlotThread::purgeCompletedEvents() {
		MutexSafeWrapper safeMutex(triggerIdMutex, CODE_AT_LINE);
		for (int index = (int) eventList.size() - 1; index >= 0; index--) {
			ConnectionSlotEvent &slotEvent = eventList[index];
			if (slotEvent.eventCompleted == true) {
				eventList.erase(eventList.begin() + index);
			}
		}
	}

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

		return ret;
	}

	bool ConnectionSlotThread::isSignalCompleted(ConnectionSlotEvent *event) {
		bool result = false;
		if (event != NULL) {
			MutexSafeWrapper safeMutex(triggerIdMutex, CODE_AT_LINE);
			for (int index = 0; index < (int) eventList.size(); ++index) {
				ConnectionSlotEvent &slotEvent = eventList[index];
				if (slotEvent.eventId == event->eventId) {
					result = slotEvent.eventCompleted;
					break;
				}
			}
		}
		return result;
	}

	void ConnectionSlotThread::slotUpdateTask(ConnectionSlotEvent *event) {
		if (event != NULL && event->connectionSlot != NULL) {
			if (event->eventType == eSendSocketData) {
				event->connectionSlot->sendMessage(event->networkMessage);
			} else if (event->eventType == eReceiveSocketData) {
				event->connectionSlot->updateSlot(event);
			}
		}
	}

	void ConnectionSlotThread::signalSlave(void *userdata) {
		std::map<int, ConnectionSlotEvent> *eventList = (std::map<int, ConnectionSlotEvent> *)userdata;
		ConnectionSlotEvent &event = (*eventList)[slotIndex];
		signalUpdate(&event);
	}

	bool ConnectionSlotThread::getGameStarted() {
		MutexSafeWrapper safeMutexGameStarted(triggerGameStarted, CODE_AT_LINE);
		return gameStarted;
	}
	void ConnectionSlotThread::setGameStarted(bool value) {
		MutexSafeWrapper safeMutexGameStarted(triggerGameStarted, CODE_AT_LINE);
		if (gameStarted != value) {
			gameStarted = value;

			if (gameStarted == true) {
				semTaskSignalled.signal();
			}
		}
	}

	void ConnectionSlotThread::execute() {
		RunningStatusSafeWrapper runningStatus(this);
		try {
			if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
			//printf("Starting client SLOT thread: %d\n",slotIndex);

			for (; this->slotInterface != NULL;) {
				if (getQuitStatus() == true) {
					SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
					break;
				}

				// Does this game allow joining in progress play and is this slot
				// not already connected to a client?
				if (this->slotInterface->getAllowInGameConnections() == true &&
					this->slotInterface->isClientConnected(slotIndex) == false) {
					//printf("#1 Non connected slot: %d waiting for client connection..\n",slotIndex);
					sleep(100);

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

					//printf("Slot thread slotIndex: %d eventCount: %d\n",slotIndex,eventCount);

					ConnectionSlotEvent eventCopy;
					eventCopy.eventType = eReceiveSocketData;
					eventCopy.connectionSlot = this->slotInterface->getSlot(slotIndex, true);

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

					ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);
					this->slotUpdateTask(&eventCopy);
				} else {
					// If the game already started?
					if (getGameStarted() == true) {
						//printf("#A Checking action for slot: %d\n",slotIndex);

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

						ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);

						// If the slot or socket are NULL the connection was lost
						// so exit the thread
						MutexSafeWrapper safeMutex(this->slotInterface->getSlotMutex(slotIndex), CODE_AT_LINE);
						ConnectionSlot *slot = this->slotInterface->getSlot(slotIndex, false);
						if (slot == NULL) {
							break;
						}
						Socket *socket = slot->getSocket(true);
						if (socket == NULL) {
							break;
						}

						PLATFORM_SOCKET socketId = socket->getSocketId();
						safeMutex.ReleaseLock();

						// Avoid mutex locking
						//bool socketHasReadData = Socket::hasDataToRead(socket->getSocketId());
						bool socketHasReadData = Socket::hasDataToReadWithWait(socketId, 150000);

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

						ConnectionSlotEvent eventCopy;
						eventCopy.eventType = eReceiveSocketData;
						eventCopy.connectionSlot = this->slotInterface->getSlot(slotIndex, true);
						eventCopy.eventId = slotIndex;
						eventCopy.socketTriggered = socketHasReadData;

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

						this->slotUpdateTask(&eventCopy);
					}
					// Game has not yet started
					else {
						//printf("#1 Checking action for slot: %d\n",slotIndex);

						if (getGameStarted() == true) {
							continue;
						}
						//printf("#2 Checking action for slot: %d\n",slotIndex);

						semTaskSignalled.waitTillSignalled();
						//printf("#3 Checking action for slot: %d\n",slotIndex);

						if (getGameStarted() == true) {
							continue;
						}
						//printf("#4 Checking action for slot: %d\n",slotIndex);

						static string masterSlaveOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
						MasterSlaveThreadControllerSafeWrapper safeMasterController(masterController, 20000, masterSlaveOwnerId);
						if (getQuitStatus() == true) {
							if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
							break;
						}

						MutexSafeWrapper safeMutex(triggerIdMutex, CODE_AT_LINE);
						int eventCount = (int) eventList.size();

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

						if (eventCount > 0) {
							ConnectionSlotEvent eventCopy;
							for (int i = 0; i < (int) eventList.size(); ++i) {
								ConnectionSlotEvent &slotEvent = eventList[i];
								if (slotEvent.eventCompleted == false) {
									eventCopy = slotEvent;
									break;
								}
							}
							safeMutex.ReleaseLock();

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

							if (eventCopy.eventId > 0) {
								ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);

								if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] Slot thread slotIndex: %d eventCount: %d eventCopy.eventId: %d\n", __FILE__, __FUNCTION__, __LINE__, slotIndex, eventCount, (int) eventCopy.eventId);
								//printf("#1 Slot thread slotIndex: %d eventCount: %d eventCopy.eventId: %d\n",slotIndex,eventCount,(int)eventCopy.eventId);

								this->slotUpdateTask(&eventCopy);
								setTaskCompleted(eventCopy.eventId);

								//printf("#2 Slot thread slotIndex: %d eventCount: %d eventCopy.eventId: %d\n",slotIndex,eventCount,(int)eventCopy.eventId);
							}
						}
					}
				}

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

			//printf("Ending client SLOT thread: %d\n",slotIndex);

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

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

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

	// =====================================================
	//	class ConnectionSlot
	// =====================================================

	ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex) {
		if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s] Line: %d\n", __FILE__, __FUNCTION__, __LINE__);

		this->mutexSocket = new Mutex(CODE_AT_LINE);
		this->socket = NULL;
		this->mutexCloseConnection = new Mutex(CODE_AT_LINE);
		this->mutexPendingNetworkCommandList = new Mutex(CODE_AT_LINE);
		this->socketSynchAccessor = new Mutex(CODE_AT_LINE);
		this->connectedRemoteIPAddress = 0;
		this->sessionKey = 0;
		this->serverInterface = serverInterface;
		this->playerIndex = playerIndex;
		this->playerStatus = npst_None;
		this->playerLanguage = "";
		this->playerUUID = "";
		this->platform = "";
		this->currentFrameCount = 0;
		this->currentLagCount = 0;
		this->graceLagCtr = 0;
		this->gotLagCountWarning = false;
		this->lastReceiveCommandListTime = 0;
		this->receivedNetworkGameStatus = false;

		this->autoPauseGameCountForLag = 0;
		this->skipLagCheck = true;
		this->joinGameInProgress = false;
		this->canAcceptConnections = true;
		this->startInGameConnectionLaunch = false;
		this->pauseForInGameConnection = false;
		this->unPauseForInGameConnection = false;
		this->sentSavedGameInfo = false;

		this->ready = false;
		this->gotIntro = false;
		this->connectedTime = 0;

		this->networkGameDataSynchCheckOkMap = false;
		this->networkGameDataSynchCheckOkTile = false;
		this->networkGameDataSynchCheckOkTech = false;
		this->setNetworkGameDataSynchCheckTechMismatchReport("");
		this->setReceivedDataSynchCheck(false);

		this->clearChatInfo();

		this->setSocket(NULL);
		this->slotThreadWorker = NULL;
		static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
		this->slotThreadWorker = new ConnectionSlotThread(this->serverInterface, playerIndex);
		this->slotThreadWorker->setUniqueID(mutexOwnerId);
		this->slotThreadWorker->start();
	}

	ConnectionSlot::~ConnectionSlot() {
		//printf("===> Destructor for ConnectionSlot = %d\n",playerIndex);

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

		//printf("Deleting connection slot\n");
		close();

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

		//printf("#1 Ending client SLOT: %d slotThreadWorker: %p\n",playerIndex,slotThreadWorker);
		if (slotThreadWorker != NULL) {
			slotThreadWorker->signalQuit();
		}
		if (slotThreadWorker != NULL &&
			slotThreadWorker->canShutdown(false) == true &&
			slotThreadWorker->getRunningStatus() == false) {
			//printf("#2 Ending client SLOT: %d\n",playerIndex);

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

			delete slotThreadWorker;

			if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
		} else if (slotThreadWorker != NULL &&
			slotThreadWorker->canShutdown(true) == true) {

			if (slotThreadWorker->getRunningStatus() == false) {
				//printf("#3 Ending client SLOT: %d\n",playerIndex);
				if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);

				delete slotThreadWorker;

				if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
			} else {
				slotThreadWorker->setDeleteSelfOnExecutionDone(true);
				slotThreadWorker->setDeleteAfterExecute(true);
			}
		}
		//printf("#4 Ending client SLOT: %d\n",playerIndex);
		slotThreadWorker = NULL;

		delete socketSynchAccessor;
		socketSynchAccessor = NULL;

		delete mutexPendingNetworkCommandList;
		mutexPendingNetworkCommandList = NULL;

		delete mutexCloseConnection;
		mutexCloseConnection = NULL;

		delete mutexSocket;
		mutexSocket = NULL;

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

	int ConnectionSlot::getAutoPauseGameCountForLag() {
		return autoPauseGameCountForLag;
	}

	void ConnectionSlot::incrementAutoPauseGameCountForLag() {
		autoPauseGameCountForLag++;
	}

	bool ConnectionSlot::getGameStarted() {
		bool result = false;
		if (this->slotThreadWorker != NULL) {
			result = this->slotThreadWorker->getGameStarted();
		}
		return result;
	}
	void ConnectionSlot::setGameStarted(bool value) {
		if (this->slotThreadWorker != NULL) {
			this->slotThreadWorker->setGameStarted(value);
		}
	}

	void ConnectionSlot::setPlayerIndex(int value) {
		playerIndex = value;

		if (this->slotThreadWorker != NULL) {
			this->slotThreadWorker->setSlotIndex(playerIndex);
		}
	}

	void ConnectionSlot::setReady() {
		this->ready = true;
		this->skipLagCheck = true;
		this->joinGameInProgress = false;
		this->sentSavedGameInfo = false;
	}

	void ConnectionSlot::updateSlot(ConnectionSlotEvent *event) {
		if (event != NULL) {
			bool &socketTriggered = event->socketTriggered;
			bool checkForNewClients =
				(serverInterface->getGameHasBeenInitiated() == false ||
					serverInterface->getAllowInGameConnections() == true);

			//if((serverInterface->getGameHasBeenInitiated() == false ||
			//	(serverInterface->getAllowInGameConnections() == true && this->isConnected() == false) ||
			//	socketTriggered == true)) {
			if (socketTriggered == true ||
				((serverInterface->getGameHasBeenInitiated() == false ||
					serverInterface->getAllowInGameConnections() == true) &&
					this->isConnected() == false)) {

				this->update(checkForNewClients, event->triggerId);
			}
			//}
		}
		if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
	}

	string ConnectionSlot::getIpAddress(bool mutexLock) {
		string result = "";
		MutexSafeWrapper safeMutexSlot((mutexLock == true ? mutexSocket : NULL), CODE_AT_LINE);
		if (socket != NULL) {
			result = socket->getIpAddress();
		}
		return result;
	}

	void ConnectionSlot::update(bool checkForNewClients, int lockedSlotIndex) {
		try {
			clearThreadErrorList();

			if (slotThreadWorker != NULL) {
				slotThreadWorker->purgeCompletedEvents();
			}

			pair<bool, Socket*> socketInfo = this->getSocketInfo();
			if (socketInfo.second == NULL) {
				if (networkGameDataSynchCheckOkMap) networkGameDataSynchCheckOkMap = false;
				if (networkGameDataSynchCheckOkTile) networkGameDataSynchCheckOkTile = false;
				if (networkGameDataSynchCheckOkTech) networkGameDataSynchCheckOkTech = false;
				this->setReceivedDataSynchCheck(false);

				// Is the listener socket ready to be read?
				if (checkForNewClients == true && this->canAcceptConnections == true) {

					if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] BEFORE accept new client connection, serverInterface->getOpenSlotCount() = %d\n", __FILE__, __FUNCTION__, __LINE__, serverInterface->getOpenSlotCount());

					//printf("Checking for new connections...\n");
					bool hasData = (serverInterface->getServerSocket() != NULL &&
						serverInterface->getServerSocket()->hasDataToRead() == true);
					//printf("Server socket hasData: %d\n",hasData);

					if (hasData == true) {
						if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] about to accept new client connection playerIndex = %d\n", __FILE__, __FUNCTION__, __LINE__, playerIndex);

						Socket *newSocket = serverInterface->getServerSocket()->accept(false);

						//printf("Server socket newSocket: %p\n",newSocket);

						if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] called accept new client connection playerIndex = %d newSocket = %p\n", __FILE__, __FUNCTION__, __LINE__, playerIndex, newSocket);
						if (newSocket != NULL) {
							// Set Socket as non-blocking
							newSocket->setBlock(false);

							MutexSafeWrapper safeMutex(mutexCloseConnection, CODE_AT_LINE);
							this->setSocket(newSocket);
							safeMutex.ReleaseLock();

							this->connectedTime = time(NULL);
							this->clearChatInfo();
							this->name = "";
							this->playerStatus = npst_PickSettings;
							this->playerLanguage = "";
							this->playerUUID = "";
							this->platform = "";
							this->ready = false;
							this->vctFileList.clear();
							this->receivedNetworkGameStatus = false;
							this->gotIntro = false;

							MutexSafeWrapper safeMutexSlot1(mutexPendingNetworkCommandList, CODE_AT_LINE);
							this->vctPendingNetworkCommandList.clear();
							safeMutexSlot1.ReleaseLock();

							this->currentFrameCount = 0;
							this->currentLagCount = 0;
							this->lastReceiveCommandListTime = 0;
							this->gotLagCountWarning = false;
							this->versionString = "";

							serverInterface->updateListen();
							if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] playerIndex = %d\n", __FILE__, __FUNCTION__, __LINE__, playerIndex);
						} else {
							close();
							return;
						}

						//send intro message when connected
						if (this->isConnected() == true) {
							//printf("Server socket newSocket is connected: %d\n",playerIndex);

							Chrono seed(true);
							srand((unsigned int) seed.getCurTicks() / (this->playerIndex + 1));

							sessionKey = rand() % 1000000;

							if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] accepted new client connection, serverInterface->getOpenSlotCount() = %d, sessionKey = %d\n", __FILE__, __FUNCTION__, __LINE__, serverInterface->getOpenSlotCount(), sessionKey);
							if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] client will be assigned to the next open slot\n", __FILE__, __FUNCTION__, __LINE__);

							NetworkMessageIntro networkMessageIntro(
								sessionKey,
								GameVersionString,
								getHostName(),
								playerIndex,
								nmgstOk,
								0,
								ServerSocket::getFTPServerPort(),
								"",
								serverInterface->getGameHasBeenInitiated(),
								Config::getInstance().getString("PlayerId", ""),
								getPlatformNameString());
							sendMessage(&networkMessageIntro);

							if (this->serverInterface->getGameHasBeenInitiated() == true) {
								setGameStarted(true);
							}
						}
					}
				}
			} else {
				if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);

				if (socketInfo.first == true) {
					this->clearChatInfo();

					bool gotTextMsg = true;
					bool gotCellMarkerMsg = true;
					bool waitForLaggingClient = false;
					bool waitedForLaggingClient = false;

					//printf("Update slot: %d this->hasDataToRead(): %d\n",this->playerIndex,this->hasDataToRead());

					for (; waitForLaggingClient == true ||
						(this->hasDataToRead() == true &&
						(gotTextMsg == true || gotCellMarkerMsg == true));) {

						//printf("Server slot checking for waitForLaggingClient = %d this->hasDataToRead() = %d gotTextMsg = %d gotCellMarkerMsg = %d\n",waitForLaggingClient,this->hasDataToRead(),gotTextMsg,gotCellMarkerMsg);

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

						NetworkMessageType networkMessageType = getNextMessageType();

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

						gotTextMsg = false;
						gotCellMarkerMsg = false;
						//process incoming commands
						switch (networkMessageType) {

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

							case nmtPing:
							{
								if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s] got nmtPing\n", __FILE__, __FUNCTION__);

								// client REQUIRES a ping before completing intro
								// authentication
								NetworkMessagePing networkMessagePing;
								if (receiveMessage(&networkMessagePing)) {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
									lastPingInfo = networkMessagePing;
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

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

								if (gotIntro == true) {
									NetworkMessageText networkMessageText;
									if (receiveMessage(&networkMessageText)) {
										ChatMsgInfo msg(networkMessageText.getText().c_str(), networkMessageText.getTeamIndex(), networkMessageText.getPlayerIndex(), networkMessageText.getTargetLanguage());
										this->addChatInfo(msg);
										gotTextMsg = true;
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

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

								if (gotIntro == true) {
									NetworkMessageMarkCell networkMessageMarkCell;
									if (receiveMessage(&networkMessageMarkCell)) {
										MarkedCell msg(networkMessageMarkCell.getTarget(),
											networkMessageMarkCell.getFactionIndex(),
											networkMessageMarkCell.getText().c_str(),
											networkMessageMarkCell.getPlayerIndex());

										this->addMarkedCell(msg);
										gotCellMarkerMsg = true;
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

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

								if (gotIntro == true) {
									NetworkMessageUnMarkCell networkMessageMarkCell;
									if (receiveMessage(&networkMessageMarkCell)) {
										UnMarkedCell msg(networkMessageMarkCell.getTarget(),
											networkMessageMarkCell.getFactionIndex());

										this->addUnMarkedCell(msg);
										gotCellMarkerMsg = true;
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

							case nmtHighlightCell:
							{
								if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] got nmtMarkCell gotIntro = %d\n", __FILE__, __FUNCTION__, __LINE__, gotIntro);

								if (gotIntro == true) {
									NetworkMessageHighlightCell networkMessageHighlightCell;
									if (receiveMessage(&networkMessageHighlightCell)) {
										MarkedCell msg(networkMessageHighlightCell.getTarget(),
											networkMessageHighlightCell.getFactionIndex(), "none", -1);

										this->setHighlightedCell(msg);
										gotCellMarkerMsg = true;
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

							//command list
							case nmtCommandList: {

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

								if (gotIntro == true) {
									NetworkMessageCommandList networkMessageCommandList;
									if (receiveMessage(&networkMessageCommandList)) {
										currentFrameCount = networkMessageCommandList.getFrameCount();
										lastReceiveCommandListTime = time(NULL);

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

										MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList, CODE_AT_LINE);
										for (int i = 0; i < networkMessageCommandList.getCommandCount(); ++i) {
											vctPendingNetworkCommandList.push_back(*networkMessageCommandList.getCommand(i));
										}
										//printf("Got commands from client frame: %d count: %d\n",currentFrameCount,vctPendingNetworkCommandList.size());

										//printf("#2 Server slot got currentFrameCount = %d\n",currentFrameCount);
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
													break;

													//process intro messages
							case nmtIntro:
							{
								if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s] got nmtIntro\n", __FILE__, __FUNCTION__);

								NetworkMessageIntro networkMessageIntro;
								if (receiveMessage(&networkMessageIntro)) {
									int32 msgSessionId = networkMessageIntro.getSessionId();
									this->name = networkMessageIntro.getName();
									this->versionString = networkMessageIntro.getVersionString();
									this->connectedRemoteIPAddress = networkMessageIntro.getExternalIp();
									this->playerLanguage = networkMessageIntro.getPlayerLanguage();
									this->playerUUID = networkMessageIntro.getPlayerUUID();
									this->platform = networkMessageIntro.getPlayerPlatform();

									//printf("Got uuid from client [%s]\n",this->playerUUID.c_str());
									if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s] got name [%s] versionString [%s], msgSessionId = %d\n", __FILE__, __FUNCTION__, name.c_str(), versionString.c_str(), msgSessionId);

									/*if (msgSessionId != sessionKey) {
										string playerNameStr = name;
										string sErr = "Client gave invalid sessionid for player [" + playerNameStr + "] actual [" + intToStr(msgSessionId) + "] expected [" + intToStr(sessionKey) + "]";
										printf("%s\n", sErr.c_str());
										if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] %s\n", __FILE__, __FUNCTION__, __LINE__, sErr.c_str());

										close();
										return;
									} else */if (this->playerUUID == "") {
										string playerNameStr = name;
										string sErr = "Client gave an invalid UUID for player [" + playerNameStr + "]";
										printf("%s\n", sErr.c_str());
										if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] %s\n", __FILE__, __FUNCTION__, __LINE__, sErr.c_str());

										close();
										return;
									} else {
										//check consistency
										if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);

										bool compatible = checkVersionCompatibility(networkMessageIntro.getVersionString(), GameVersionString);

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

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

											string playerNameStr = name;
											string sErr = "Server and client version mismatch!\nYou have to use the exactly same versions!\n\nServer: " + GameVersionString +
												"\nClient: " + networkMessageIntro.getVersionString() + " player [" + playerNameStr + "]";
											printf("%s\n", sErr.c_str());

											serverInterface->sendTextMessage("Server and client version mismatch", -1, true, "", lockedSlotIndex);
											serverInterface->sendTextMessage(" Server:" + GameVersionString, -1, true, "", lockedSlotIndex);
											serverInterface->sendTextMessage(" Client: " + networkMessageIntro.getVersionString(), -1, true, "", lockedSlotIndex);
											serverInterface->sendTextMessage(" Client player [" + playerNameStr + "]", -1, true, "", lockedSlotIndex);
										}

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

										int factionIndex = this->serverInterface->gameSettings.getFactionIndexForStartLocation(playerIndex);
										this->serverInterface->addClientToServerIPAddress(this->getSocket()->getConnectedIPAddress(this->getSocket()->getIpAddress()), this->connectedRemoteIPAddress);

										this->serverInterface->gameSettings.setNetworkPlayerUUID(factionIndex, this->playerUUID);
										this->serverInterface->gameSettings.setNetworkPlayerPlatform(factionIndex, this->platform);

										if (serverInterface->getGameHasBeenInitiated() == true &&
											serverInterface->getAllowInGameConnections() == true) {
											this->serverInterface->gameSettings.setNetworkPlayerStatuses(factionIndex, npst_None);
										}

										if (getAllowGameDataSynchCheck() == true && serverInterface->getGameSettings() != NULL) {
											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] sending NetworkMessageSynchNetworkGameData\n", __FILE__, __FUNCTION__, __LINE__);

											NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData(serverInterface->getGameSettings());
											sendMessage(&networkMessageSynchNetworkGameData);
										}

										if (serverInterface->getGameHasBeenInitiated() == true &&
											serverInterface->getAllowInGameConnections() == true) {

											ConnectionSlot *slot = serverInterface->findSlotForUUID(this->playerUUID, true);
											if (slot != NULL) {
												slot->setJoinGameInProgressFlags();
												slot->setPauseForInGameConnection(true);

												serverInterface->switchSlot(this->playerIndex, slot->getPlayerIndex());
											} else {
												setJoinGameInProgressFlags();
												this->setPauseForInGameConnection(true);
											}
										} else {
											ConnectionSlot *slot = serverInterface->findSlotForUUID(this->playerUUID, true);
											if (slot != NULL) {
												serverInterface->switchSlot(this->playerIndex, slot->getPlayerIndex());
											}
										}
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

							case nmtLaunch:
							case nmtBroadCastSetup:
							{
								if (gotIntro == true) {
									/*if (this->serverInterface->getGameSettings() == NULL ||
										(joinGameInProgress == false && sessionKey != this->serverInterface->getGameSettings()->getMasterserver_admin())) {
										string playerNameStr = name;
										string sErr = "Client has invalid admin sessionid for player [" + playerNameStr + "]";
										printf("%s\n", sErr.c_str());
										if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] %s\n", __FILE__, __FUNCTION__, __LINE__, sErr.c_str());

										close();
										return;
									}*/

									NetworkMessageLaunch networkMessageLaunch;
									if (receiveMessage(&networkMessageLaunch, networkMessageType)) {
										if (networkMessageLaunch.getMessageType() == nmtLaunch) {
											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Lined: %d] got nmtLaunch\n", __FILE__, __FUNCTION__, __LINE__);
											//printf("Got launch request from client joinGameInProgress = %d joinGameInProgress = %d!\n",joinGameInProgress,joinGameInProgress);
										} else if (networkMessageLaunch.getMessageType() == nmtBroadCastSetup) {
											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Lined: %d] got nmtBroadCastSetup\n", __FILE__, __FUNCTION__, __LINE__);
										} else {
											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Lined: %d] got networkMessageLaunch.getMessageType() = %d\n", __FILE__, __FUNCTION__, __LINE__, networkMessageLaunch.getMessageType());

											char szBuf[1024] = "";
											snprintf(szBuf, 1023, "In [%s::%s Line: %d] Invalid networkMessageLaunch.getMessageType() = %d", __FILE__, __FUNCTION__, __LINE__, networkMessageLaunch.getMessageType());
											throw game_runtime_error(szBuf);
										}

										int minHeadLessPlayersRequired = Config::getInstance().getInt("MinHeadlessPlayersRequired", "1");
										if (this->joinGameInProgress == false &&
											networkMessageLaunch.getMessageType() == nmtLaunch &&
											this->ready == false &&
											this->serverInterface->getConnectedSlotCount(true) < minHeadLessPlayersRequired) {

											Lang &lang = Lang::getInstance();
											const vector<string> languageList = this->serverInterface->getGameSettings()->getUniqueNetworkPlayerLanguages();
											for (unsigned int index = 0; index < languageList.size(); ++index) {
												char szBuf[4096] = "";
												string msgTemplate = "You must have have at least %d player(s) connected to start this game!";
												if (lang.hasString("HeadlessAdminRequiresMorePlayers", languageList[index]) == true) {
													msgTemplate = lang.getString("HeadlessAdminRequiresMorePlayers", languageList[index]);
												}
#ifdef WIN32
												_snprintf(szBuf, 4095, msgTemplate.c_str(), minHeadLessPlayersRequired);
#else
												snprintf(szBuf, 4095, msgTemplate.c_str(), minHeadLessPlayersRequired);
#endif
												if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] %s\n", __FILE__, __FUNCTION__, __LINE__, szBuf);

												string sMsg = szBuf;
												bool echoLocal = lang.isLanguageLocal(languageList[index]);
												this->serverInterface->sendTextMessage(sMsg, -1, echoLocal, languageList[index], this->getPlayerIndex());
											}
										} else {
											if (this->joinGameInProgress == false) {
												GameSettings gameSettingsBuffer;
												networkMessageLaunch.buildGameSettings(&gameSettingsBuffer);

												//printf("Connection slot got networkMessageLaunch.getMessageType() = %d, got map [%s]\n",networkMessageLaunch.getMessageType(),gameSettings.getMap().c_str());
												//printf("\n\n\n\n=====Connection slot got settings:\n%s\n",gameSettings.toString().c_str());

												this->serverInterface->broadcastGameSetup(&gameSettingsBuffer, true);
											}

											if (this->joinGameInProgress == false &&
												networkMessageLaunch.getMessageType() == nmtLaunch) {

												this->serverInterface->setMasterserverAdminRequestLaunch(true);
											} else if (this->joinGameInProgress == true &&
												networkMessageLaunch.getMessageType() == nmtLaunch) {
												//printf("!!! setStartInGameConnectionLaunch for client joinGameInProgress = %d!\n",joinGameInProgress);

												int factionIndex = this->serverInterface->gameSettings.getFactionIndexForStartLocation(playerIndex);
												this->serverInterface->gameSettings.setFactionControl(factionIndex, ctNetwork);
												this->serverInterface->gameSettings.setNetworkPlayerName(factionIndex, this->name);
												this->serverInterface->gameSettings.setNetworkPlayerUUID(factionIndex, this->playerUUID);
												this->serverInterface->gameSettings.setNetworkPlayerPlatform(factionIndex, this->platform);

												if (this->serverInterface->gameSettings.getNetworkPlayerStatuses(factionIndex) == npst_Disconnected) {
													this->serverInterface->gameSettings.setNetworkPlayerStatuses(factionIndex, npst_None);
												}

												this->serverInterface->broadcastGameSetup(&this->serverInterface->gameSettings, true);

												this->setStartInGameConnectionLaunch(true);
											}
										}
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

							//process datasynch messages
							case nmtSynchNetworkGameDataStatus:
							{
								if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] got nmtSynchNetworkGameDataStatus, gotIntro = %d\n", __FILE__, __FUNCTION__, __LINE__, gotIntro);

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

									NetworkMessageSynchNetworkGameDataStatus networkMessageSynchNetworkGameDataStatus;
									if (receiveMessage(&networkMessageSynchNetworkGameDataStatus)) {
										this->setNetworkGameDataSynchCheckTechMismatchReport("");
										this->setReceivedDataSynchCheck(false);

										Config &config = Config::getInstance();
										string scenarioDir = "";
										if (serverInterface->getGameSettings()->getScenarioDir() != "") {
											scenarioDir = serverInterface->getGameSettings()->getScenarioDir();
											if (EndsWith(scenarioDir, ".xml") == true) {
												scenarioDir = scenarioDir.erase(scenarioDir.size() - 4, 4);
												scenarioDir = scenarioDir.erase(scenarioDir.size() - serverInterface->getGameSettings()->getScenario().size(), serverInterface->getGameSettings()->getScenario().size() + 1);
											}

											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] gameSettings.getScenarioDir() = [%s] gameSettings.getScenario() = [%s] scenarioDir = [%s]\n", __FILE__, __FUNCTION__, __LINE__, serverInterface->getGameSettings()->getScenarioDir().c_str(), serverInterface->getGameSettings()->getScenario().c_str(), scenarioDir.c_str());
										}

										//tileset
										uint32 tilesetCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTilesets, scenarioDir), string("/") + serverInterface->getGameSettings()->getTileset() + string("/*"), ".xml", NULL);
										uint32 techCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTechs, scenarioDir), "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL);
										Checksum checksum;
										string file = Config::getMapPath(serverInterface->getGameSettings()->getMap(), scenarioDir, false);
										checksum.addFile(file);
										uint32 mapCRC = checksum.getSum();

										networkGameDataSynchCheckOkMap = (networkMessageSynchNetworkGameDataStatus.getMapCRC() == mapCRC);
										networkGameDataSynchCheckOkTile = (networkMessageSynchNetworkGameDataStatus.getTilesetCRC() == tilesetCRC);
										networkGameDataSynchCheckOkTech = (networkMessageSynchNetworkGameDataStatus.getTechCRC() == techCRC);

										// For testing
										//techCRC++;

										if (networkGameDataSynchCheckOkMap == true &&
											networkGameDataSynchCheckOkTile == true &&
											networkGameDataSynchCheckOkTech == true) {
											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s] client data synch ok\n", __FILE__, __FUNCTION__);
										} else {
											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s] mapCRC = %d, remote = %d\n", __FILE__, __FUNCTION__, mapCRC, networkMessageSynchNetworkGameDataStatus.getMapCRC());
											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s] tilesetCRC = %d, remote = %d\n", __FILE__, __FUNCTION__, tilesetCRC, networkMessageSynchNetworkGameDataStatus.getTilesetCRC());
											if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s] techCRC = %d, remote = %d\n", __FILE__, __FUNCTION__, techCRC, networkMessageSynchNetworkGameDataStatus.getTechCRC());

											if (allowDownloadDataSynch == true) {
												// Now get all filenames with their CRC values and send to the client
												vctFileList.clear();

												Config &config = Config::getInstance();
												string scenarioDir = "";
												if (serverInterface->getGameSettings()->getScenarioDir() != "") {
													scenarioDir = serverInterface->getGameSettings()->getScenarioDir();
													if (EndsWith(scenarioDir, ".xml") == true) {
														scenarioDir = scenarioDir.erase(scenarioDir.size() - 4, 4);
														scenarioDir = scenarioDir.erase(scenarioDir.size() - serverInterface->getGameSettings()->getScenario().size(), serverInterface->getGameSettings()->getScenario().size() + 1);
													}

													if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] gameSettings.getScenarioDir() = [%s] gameSettings.getScenario() = [%s] scenarioDir = [%s]\n", __FILE__, __FUNCTION__, __LINE__, serverInterface->getGameSettings()->getScenarioDir().c_str(), serverInterface->getGameSettings()->getScenario().c_str(), scenarioDir.c_str());
												}

												if (networkGameDataSynchCheckOkTile == false) {
													if (tilesetCRC == 0) {
														vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTilesets, scenarioDir), string("/") + serverInterface->getGameSettings()->getTileset() + string("/*"), "", &vctFileList);
													} else {
														vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTilesets, scenarioDir), "/" + serverInterface->getGameSettings()->getTileset() + "/*", ".xml", &vctFileList);
													}
												}
												if (networkGameDataSynchCheckOkTech == false) {
													if (techCRC == 0) {
														vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs, scenarioDir), "/" + serverInterface->getGameSettings()->getTech() + "/*", "", &vctFileList);
													} else {
														vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs, scenarioDir), "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", &vctFileList);
													}

													string report = networkMessageSynchNetworkGameDataStatus.getTechCRCFileMismatchReport(serverInterface->getGameSettings()->getTech(), vctFileList);
													this->setNetworkGameDataSynchCheckTechMismatchReport(report);
												}
												if (networkGameDataSynchCheckOkMap == false) {
													vctFileList.push_back(std::pair<string, uint32>(Config::getMapPath(serverInterface->getGameSettings()->getMap(), scenarioDir, false), mapCRC));
												}

												NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck((int) vctFileList.size(), 1, vctFileList[0].second, vctFileList[0].first);
												sendMessage(&networkMessageSynchNetworkGameDataFileCRCCheck);
											} else {
												if (networkGameDataSynchCheckOkTech == false) {
													vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs, scenarioDir), "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL);

													string report = networkMessageSynchNetworkGameDataStatus.getTechCRCFileMismatchReport(serverInterface->getGameSettings()->getTech(), vctFileList);
													this->setNetworkGameDataSynchCheckTechMismatchReport(report);
												}
											}
										}

										this->setReceivedDataSynchCheck(true);
										receivedNetworkGameStatus = true;
										if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

							case nmtSynchNetworkGameDataFileCRCCheck:
							{

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

								if (gotIntro == true) {
									NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck;
									if (receiveMessage(&networkMessageSynchNetworkGameDataFileCRCCheck)) {
										int fileIndex = networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex();
										NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck((int) vctFileList.size(), fileIndex, vctFileList[fileIndex - 1].second, vctFileList[fileIndex - 1].first);
										sendMessage(&networkMessageSynchNetworkGameDataFileCRCCheck);
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

							case nmtSynchNetworkGameDataFileGet:
							{

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

								if (gotIntro == true) {
									NetworkMessageSynchNetworkGameDataFileGet networkMessageSynchNetworkGameDataFileGet;
									if (receiveMessage(&networkMessageSynchNetworkGameDataFileGet)) {
										FileTransferInfo fileInfo;
										fileInfo.hostType = eServer;
										//fileInfo.serverIP   = this->ip.getString();
										fileInfo.serverPort = Config::getInstance().getInt("PortServer", intToStr(GameConstants::serverPort).c_str());
										fileInfo.fileName = networkMessageSynchNetworkGameDataFileGet.getFileName();

										FileTransferSocketThread *fileXferThread = new FileTransferSocketThread(fileInfo);
										fileXferThread->start();
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
							break;

							case nmtSwitchSetupRequest:
							{
								//printf("Got nmtSwitchSetupRequest A gotIntro = %d\n",gotIntro);
								if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] got nmtSwitchSetupRequest gotIntro = %d\n", __FILE__, __FUNCTION__, __LINE__, gotIntro);

								if (gotIntro == true) {
									//printf("Got nmtSwitchSetupRequest B\n");

									SwitchSetupRequest switchSetupRequest;
									if (receiveMessage(&switchSetupRequest)) {
										MutexSafeWrapper safeMutex(getServerSynchAccessor(), CODE_AT_LINE);

										int slotIdx = switchSetupRequest.getCurrentSlotIndex();
										//int newSlotIdx = switchSetupRequest.getToSlotIndex();
										//printf("slotIdx = %d newSlotIdx = %d\n",slotIdx,newSlotIdx);

										if (serverInterface->getSwitchSetupRequests(slotIdx) == NULL) {
											serverInterface->setSwitchSetupRequests(slotIdx, new SwitchSetupRequest());
										}
										*(serverInterface->getSwitchSetupRequests(slotIdx)) = switchSetupRequest;

										//printf("slotIdx = %d newSlotIdx = %d\n",serverInterface->getSwitchSetupRequests(slotIdx)->getCurrentSlotIndex(),serverInterface->getSwitchSetupRequests(slotIdx)->getToSlotIndex());

										this->playerStatus = switchSetupRequest.getNetworkPlayerStatus();
										this->name = switchSetupRequest.getNetworkPlayerName();
										this->playerLanguage = switchSetupRequest.getNetworkPlayerLanguage();

										//printf("Got nmtSwitchSetupRequest C\n");
										//printf("In [%s::%s Line %d] networkPlayerName [%s]\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getSwitchSetupRequests()[factionIdx]->getNetworkPlayerName().c_str());

										if (SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d] networkPlayerName [%s]\n", __FILE__, __FUNCTION__, __LINE__, serverInterface->getSwitchSetupRequests()[slotIdx]->getNetworkPlayerName().c_str());
										if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] factionIdx = %d, switchSetupRequest.getNetworkPlayerName() [%s] switchSetupRequest.getNetworkPlayerStatus() = %d, switchSetupRequest.getSwitchFlags() = %d\n", __FILE__, __FUNCTION__, __LINE__, slotIdx, switchSetupRequest.getNetworkPlayerName().c_str(), switchSetupRequest.getNetworkPlayerStatus(), switchSetupRequest.getSwitchFlags());
									} else {
										if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
										this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
										close();
										return;
									}
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}

								break;
							}

							case nmtReady:
							{
								NetworkMessageReady networkMessageReady;
								this->receiveMessage(&networkMessageReady);

								// its simply ignored here. Probably we are starting a game
								//printf("Got ready message from client slot joinGameInProgress = %d\n",joinGameInProgress);
								if (joinGameInProgress == true) {
									NetworkMessageReady networkMessageReady(0);
									this->sendMessage(&networkMessageReady);
									this->setGameStarted(true);

									this->currentFrameCount = serverInterface->getCurrentFrameCount();
									//printf("#2 Server slot got currentFrameCount = %d\n",currentFrameCount);

									this->currentLagCount = 0;
									this->graceLagCtr = 0;
									
									this->lastReceiveCommandListTime = time(NULL);

									this->setReady();
								}
								// unpause the game
								else {
									this->setUnPauseForInGameConnection(true);
								}
								break;
							}
							case nmtLoadingStatusMessage:
								break;

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

								if (gotIntro == true) {
									//throw game_runtime_error("Unexpected message in connection slot: " + intToStr(networkMessageType));
									string sErr = "Unexpected message in connection slot: " + intToStr(networkMessageType);
									//sendTextMessage(sErr,-1);
									//DisplayErrorMessage(sErr);
									threadErrorList.push_back(sErr);
									return;
								} else {
									if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] got invalid message type before intro, disconnecting socket.\n", __FILE__, __FUNCTION__, __LINE__);

									if (SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__, networkMessageType, this->playerIndex, this->getIpAddress().c_str());
									this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
									close();
									return;
								}
							}
						}

						//printf("#3 Server slot got currentFrameCount = %d\n",currentFrameCount);

						// This may end up continuously lagging and not disconnecting players who have
						// just the 'wrong' amount of lag (but not enough to be horrible for a disconnect)
						if (Config::getInstance().getBool("AutoClientLagCorrection", "true") == true) {
							//printf("#4 Server slot got currentFrameCount = %d\n",currentFrameCount);

							if (this->serverInterface->getGameStartTime() > 0 &&
								difftime((long int) time(NULL), this->serverInterface->getGameStartTime()) >= LAG_CHECK_GRACE_PERIOD &&
								difftime((long int) time(NULL), this->getConnectedTime()) >= LAG_CHECK_GRACE_PERIOD) {
								if (this->isConnected() == true && this->gotIntro == true && this->skipLagCheck == false) {
									double clientLag = this->serverInterface->getCurrentFrameCount() - this->getCurrentFrameCount();
									double clientLagCount = (gameSettings.getNetworkFramePeriod() > 0 ? (clientLag / gameSettings.getNetworkFramePeriod()) : 0);
									double clientLagTime = difftime((long int) time(NULL), this->getLastReceiveCommandListTime());

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

										waitForLaggingClient = true;
										if (waitedForLaggingClient == false) {
											waitedForLaggingClient = true;
											printf("START Waiting for lagging client playerIndex = %d [%s] clientLagCount = %f [%f]\n", playerIndex, name.c_str(), clientLagCount, clientLagTime);
										}
									}
								}
							}

							//printf("#5 Server slot got currentFrameCount = %d\n",currentFrameCount);
						}
						//printf("#5a Server slot got currentFrameCount = %d\n",currentFrameCount);
					}

					//printf("#6 Server slot got currentFrameCount = %d\n",currentFrameCount);

					if (waitedForLaggingClient == true) {
						printf("*TESTING*: FINISHED Waiting for lagging client playerIndex = %d [%s]\n", playerIndex, name.c_str());
					}

					//if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());

					validateConnection();

					//printf("#7 Server slot got currentFrameCount = %d\n",currentFrameCount);

					//if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
				} else {
					if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] calling close...\n", __FILE__, __FUNCTION__, __LINE__);

					//printf("Closing connection slot socketInfo.first = %d\n",socketInfo.first);

					close();

					//if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
				}

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

			threadErrorList.push_back(ex.what());

			//if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
		}

		//printf("#8 Server slot got currentFrameCount = %d\n",currentFrameCount);
		//if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
	}

	void ConnectionSlot::validateConnection() {
		if (this->isConnected() == true &&
			gotIntro == false && connectedTime > 0 &&
			difftime((long int) time(NULL), connectedTime) > GameConstants::maxClientConnectHandshakeSecs) {

			//printf("Closing connection slot timed out!\n");
			close();
		}
	}

	//void ConnectionSlot::resetJoinGameInProgressFlags() {
	//	this->gotIntro 				= false;
	//	this->skipLagCheck 			= false;
	//	this->joinGameInProgress 	= false;
	//	this->ready					= false;
	//}

	void ConnectionSlot::setJoinGameInProgressFlags() {
		this->gotIntro = true;
		this->skipLagCheck = true;
		this->joinGameInProgress = true;
		this->ready = false;
		this->sentSavedGameInfo = false;
	}

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

		//printf("Closing slot for playerIndex = %d\n",playerIndex);
		//if(serverInterface->getAllowInGameConnections() == true) {
			//printf("Closing connection slot!\n");
		//}
		//printf("ConnectionSlot::close() #1 this->getSocket() = %p\n",this->getSocket());

		this->gotIntro = false;
		this->skipLagCheck = true;
		this->joinGameInProgress = false;
		this->sentSavedGameInfo = false;
		this->pauseForInGameConnection = false;
		this->unPauseForInGameConnection = false;
		this->ready = false;
		this->connectedTime = 0;

		if (this->slotThreadWorker != NULL) {
			if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
			this->slotThreadWorker->setAllEventsCompleted();
			if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__);
		}

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

		//printf("ConnectionSlot::close() #2 this->getSocket() = %p\n",this->getSocket());

		MutexSafeWrapper safeMutex(mutexCloseConnection, CODE_AT_LINE);
		bool updateServerListener = (this->getSocket() != NULL);

		//printf("ConnectionSlot::close() #3 this->getSocket() = %p updateServerListener = %d\n",this->getSocket(),updateServerListener);

		this->deleteSocket();
		safeMutex.ReleaseLock();

		if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s LINE: %d]\n", __FILE__, __FUNCTION__, __LINE__);
		//printf("Closing slot for playerIndex = %d updateServerListener = %d ready = %d\n",playerIndex,updateServerListener,ready);

		if (updateServerListener == true) {
			if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s LINE: %d]\n", __FILE__, __FUNCTION__, __LINE__);
			serverInterface->updateListen();
		}

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

	Mutex * ConnectionSlot::getServerSynchAccessor() {
		return (serverInterface != NULL ? serverInterface->getServerSynchAccessor() : NULL);
	}

	void ConnectionSlot::signalUpdate(ConnectionSlotEvent *event) {
		if (slotThreadWorker != NULL) {
			slotThreadWorker->signalUpdate(event);
		}
	}

	bool ConnectionSlot::updateCompleted(ConnectionSlotEvent *event) {
		bool waitingForThread = (slotThreadWorker != NULL &&
			slotThreadWorker->isSignalCompleted(event) == false &&
			slotThreadWorker->getQuitStatus() == false &&
			slotThreadWorker->getRunningStatus() == true);

		return (waitingForThread == false);
	}

	void ConnectionSlot::sendMessage(NetworkMessage* networkMessage) {
		MutexSafeWrapper safeMutex(socketSynchAccessor, CODE_AT_LINE);

		// Skip text messages not intended for the players preferred language
		NetworkMessageText *textMsg = dynamic_cast<NetworkMessageText *>(networkMessage);
		if (textMsg != NULL) {
			//printf("\n\n\n~~~ SERVER HAS NetworkMessageText target [%s] player [%s] msg[%s]\n\n\n",textMsg->getTargetLanguage().c_str(),this->getNetworkPlayerLanguage().c_str(), textMsg->getText().c_str());
			if (textMsg->getTargetLanguage() != "" &&
				textMsg->getTargetLanguage() != this->getNetworkPlayerLanguage()) {
				return;
			}
		}

		NetworkInterface::sendMessage(networkMessage);
	}

	string ConnectionSlot::getHumanPlayerName(int index) {
		return serverInterface->getHumanPlayerName(index);
	}

	vector<NetworkCommand> ConnectionSlot::getPendingNetworkCommandList(bool clearList) {
		vector<NetworkCommand> ret;
		MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList, CODE_AT_LINE);
		if (vctPendingNetworkCommandList.empty() == false) {
			ret = vctPendingNetworkCommandList;
			if (clearList == true) {
				vctPendingNetworkCommandList.clear();
			}
		}

		return ret;
	}

	//void ConnectionSlot::clearPendingNetworkCommandList() {
	//	MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList,CODE_AT_LINE);
	//	if(vctPendingNetworkCommandList.empty() == false) {
	//		vctPendingNetworkCommandList.clear();
	//	}
	//}

	bool ConnectionSlot::hasValidSocketId() {
		bool result = false;
		MutexSafeWrapper safeMutexSlot(mutexSocket, CODE_AT_LINE);
		if (socket != NULL && socket->getSocketId() > 0) {
			result = true;
		}
		return result;

	}

	bool ConnectionSlot::isConnected() {
		bool result = false;
		MutexSafeWrapper safeMutexSlot(mutexSocket, CODE_AT_LINE);
		if (socket != NULL && socket->isConnected() == true) {
			result = true;
		}
		return result;
	}

	PLATFORM_SOCKET ConnectionSlot::getSocketId() {
		PLATFORM_SOCKET result = 0;
		MutexSafeWrapper safeMutexSlot(mutexSocket, CODE_AT_LINE);
		if (socket != NULL) {
			result = socket->getSocketId();
		}
		return result;
	}

	pair<bool, Socket*> ConnectionSlot::getSocketInfo() {
		pair<bool, Socket*> result;
		MutexSafeWrapper safeMutexSlot(mutexSocket, CODE_AT_LINE);
		result.first = (socket != NULL && socket->isConnected());
		result.second = socket;

		return result;

	}

	Socket* ConnectionSlot::getSocket(bool mutexLock) {
		MutexSafeWrapper safeMutexSlot(NULL, CODE_AT_LINE);
		if (mutexLock == true) {
			safeMutexSlot.setMutex(mutexSocket, CODE_AT_LINE);
		}
		return socket;
	}

	void ConnectionSlot::setSocket(Socket *newSocket) {
		MutexSafeWrapper safeMutexSlot(mutexSocket, CODE_AT_LINE);
		socket = newSocket;
	}

	void ConnectionSlot::deleteSocket() {
		MutexSafeWrapper safeMutexSlot(mutexSocket, CODE_AT_LINE);
		delete socket;
		socket = NULL;
	}

	bool ConnectionSlot::hasDataToRead() {
		bool result = false;

		MutexSafeWrapper safeMutexSlot(mutexSocket, CODE_AT_LINE);
		if (socket != NULL && socket->hasDataToRead() == true) {
			result = true;
		}

		return result;
	}

} //end namespace
