/*
    Copyright 2004-2005 Electronic Arts Inc.
*/

#include "EABase/EABase.h"
#include "GameTalk/GameTalkBase.h"
#include "GameTalk/realcomm7/GameTalkProtocol.h"

using namespace EA;

namespace EA
{
namespace GameTalk
{
GameTalkProtocol::GameTalkProtocol(EA::Allocator::ICoreAllocator *ialloc, REALCOMM::ITimer *itimer, const char* const ipAddress, const int port)
:
IGameTalkProtocol(ipAddress, port),
mConnection(NULL)
{
	REALCOMM::CONNECTION_TCP* connection = InitializeRealComm(ialloc, itimer);
	if (connection != NULL)
	{
		bool result = connection->Connect(mIpAddress, uint16_t(mPort));
		if (!result)
		{
			// Switch to listen mode and let the target manager decide
			connection->Listen(NULL, mPort);
		}
	}
}

GameTalkProtocol::GameTalkProtocol(EA::Allocator::ICoreAllocator *ialloc, REALCOMM::ITimer *itimer, const int port)
:
IGameTalkProtocol(port),
mConnection(NULL)
{
	REALCOMM::CONNECTION_TCP* connection = InitializeRealComm(ialloc, itimer);
	if (connection != NULL)
	{
		connection->Listen(NULL, uint16_t(mPort));
	}
}

GameTalkProtocol::~GameTalkProtocol()
{
}

REALCOMM::CONNECTION_TCP* GameTalkProtocol::InitializeRealComm(EA::Allocator::ICoreAllocator *ialloc, REALCOMM::ITimer *itimer)
{
	// Get the REALCOMM config options.
	REALCOMM::CONFIG_OPTIONS* pOptions = REALCOMM::GetConfigOptions();
	pOptions->mAllocator = ialloc;
	pOptions->mTimer = itimer;
	pOptions->threadMode = REALCOMM::THREAD_MODE_SINGLE;
    REALCOMM::Init(pOptions);

	// Create the connection
	REALCOMM::CONNECTION_OPTIONS connectionOptions;
	connectionOptions.packetizer.on = false;
	connectionOptions.packetizer.doAckNak = false;
	connectionOptions.asyncSend.bufferSize = (40 * 1024);
	REALCOMM::CONNECTION_TCP* connection = new REALCOMM::CONNECTION_TCP(&connectionOptions, this);

	return connection;
}

int GameTalkProtocol::Poll()
{
	REALCOMM::Update();
	// Need to get the number of bytes sent from the above
	return 0;
}

bool GameTalkProtocol::IsConnected()
{
	return (mConnection != NULL);
}

bool GameTalkProtocol::Send(void* buffer, size_t msgSize)
{
	if (mConnection != NULL)
	{
		if (REALCOMM::CONNECTION_STATE_ONLINE == mConnection->GetState())
		{
			if (0 != msgSize)
			{
				mConnection->Send(buffer, static_cast<int>(msgSize));
			}

			return true;
		}
	}

	return false;
}

bool GameTalkProtocol::Connect()
{
	// This protocol needs to be updated to support graceful reconnect!
	return false;
}

u_int GameTalkProtocol::ConnectionCallback(REALCOMM::CONNECTION_CALLBACK::MSG msg, u_int wParam, u_int lParam, REALCOMM::CONNECTION *pConnection)
{
    switch (msg)
    {
		case MSG_DATA:
		{
			int size = (int)lParam;
			char *pData = (char *)wParam;
			if ((pData != NULL) && (size > 0) && (mGameTalkReceiverFnc != NULL))
			{
				mParser->DigestReceivedData(pData, size);
			}
			break;
		}
		case MSG_NEW_CONNECTION:
		case MSG_CONNECTED:
		{
			ClientConnected(pConnection);
			break;
		}
		case MSG_CONNECTION_LOST:
			{
				if (pConnection != NULL)
				{
					ClientDisconnected(pConnection);
					pConnection->Disconnect();
					pConnection->Flush();
					pConnection->Clear();

					// delete the connection
					REALCOMM::RequestToDeleteConnection(pConnection);
				}
			}
			break;
		default:
			break;
    }

    return 0;
}

void GameTalkProtocol::ClientConnected(REALCOMM::CONNECTION* connection)
{
	if (connection != NULL)
	{
		mConnection = connection;
	}
}

void GameTalkProtocol::ClientDisconnected(REALCOMM::CONNECTION* connection)
{
	if (connection == mConnection)
	{
		mConnection = NULL;
	}
}

} // namespace GameTalk
} // namespace EA

