#include "precompiled.h"

#include "TurnManager.h"
#include "ps/Network/NetMessage.h"
#include "ps/Network/Network.h"
#include "ps/GameRecord.h"
#include "ps/CLogger.h"

#include <vector>

CSinglePlayerTurnManager *g_SinglePlayerTurnManager=NULL;

CTurnManager::CTurnManager()
{
	for (int i=0;i<3;i++)
		m_Batches[i].m_TurnLength=40;
}

void CTurnManager::ClearBatch(uint batch)
{
	typedef std::vector<SMessageSyncEntry> MsgVector;
	MsgVector &messages=m_Batches[batch].m_Messages;
	MsgVector::iterator it=messages.begin();
	while (it != messages.end())
	{
		delete it->m_pMessage;
		++it;
	}
	messages.clear();
}

void CTurnManager::SBatch::Swap(SBatch &other)
{
	std::swap(m_Messages, other.m_Messages);
	std::swap(m_TurnLength, other.m_TurnLength);
}

void CTurnManager::RotateBatches()
{
	// {a, b, c} => {b, c, a}:
		// {a, b, c}
		// -- swap (0, 1)
		// {b, a, c}
		// -- swap (1, 2)
		// {b, c, a}

	m_Batches[0].Swap(m_Batches[1]);
	m_Batches[1].Swap(m_Batches[2]);
}

void CTurnManager::IterateBatch(uint batch, BatchIteratorFunc *fp, void *userdata)
{
	typedef std::vector<SMessageSyncEntry> MsgVector;
	MsgVector &messages=m_Batches[batch].m_Messages;
	MsgVector::iterator it=messages.begin();
	while (it != messages.end())
	{
		it->m_ClientMask=(*fp)(it->m_pMessage, it->m_ClientMask, userdata);
		++it;
	}
}

void CTurnManager::SendBatch(uint batch)
{
	typedef std::vector<SMessageSyncEntry> MsgVector;
	MsgVector &messages=m_Batches[batch].m_Messages;
	MsgVector::iterator it=messages.begin();
	while (it != messages.end())
	{
		SendMessage(it->m_pMessage, it->m_ClientMask);
		++it;
	}
	CEndCommandBatch *pMsg=new CEndCommandBatch();
	pMsg->m_TurnLength=m_Batches[batch].m_TurnLength;
	SendMessage(pMsg, (uint)-1);
}

void CTurnManager::SendMessage(CNetMessage *pMsg, uint clientMask)
{
	for (uint i=0;i<m_Clients.size();i++)
	{
		if (clientMask & (1<<i))
		{
			if (m_Clients[i].m_Pipe)
				m_Clients[i].m_Pipe->Push(pMsg->Copy());
		}
	}
}

void CTurnManager::QueueMessage(uint batch, CNetMessage *pMsg)
{
	m_Batches[batch].m_Messages.push_back(SMessageSyncEntry(pMsg));
}

void CTurnManager::SetClientPipe(uint client, IMessagePipeEnd *pipe)
{
	m_Clients[client].m_Pipe=pipe;
}

void CTurnManager::SetTurnLength(uint batch, uint turnLength)
{
	m_Batches[batch].m_TurnLength=turnLength;
}

uint CTurnManager::GetTurnLength()
{
	return m_Batches[0].m_TurnLength;
}

void CTurnManager::Initialize(size_t numClients)
{
	m_Clients.resize(numClients);
}


void CTurnManager::RecordBatch(uint batch)
{
	IterateBatch(batch, RecordIterator, m_pRecord);
	CEndCommandBatch msg;
	m_pRecord->WriteMessage(&msg);
}

uint CTurnManager::RecordIterator(CNetMessage *pMsg, uint clientMask, void *userdata)
{
	CGameRecord *pRecord=(CGameRecord *)userdata;

	pRecord->WriteMessage(pMsg);

	return clientMask;
}

CSinglePlayerTurnManager::CSinglePlayerTurnManager()
{}

void CSinglePlayerTurnManager::NewTurn()
{
	RecordBatch(2);

	RotateBatches();
	ClearBatch(2);
}

void CSinglePlayerTurnManager::QueueLocalCommand(CNetMessage *pMsg)
{
	QueueMessage(2, pMsg);
}
