/******************************************************************************/
/*!
    GameTalkProtocol
    Copyright 2005 Electronic Arts Inc.

    \file
    \ingroup    Debug
    \brief      GameTalk messaging over EasyTCP transport (DirtySock)
*/
/******************************************************************************/

/*** Documentation ************************************************************/

/******************************************************************************/
/*! \class  GameTalkProtocol

    \brief  GameTalk messaging over EasyTCP transport (DirtySock)
*/
/******************************************************************************/

/*** Includes *****************************************************************/

#include <GameTalk/DirtySock/GameTalkProtocol.h>
#include <GameTalk/DirtySock/easytcp.h>

/*** Using ********************************************************************/

/*** Macros *******************************************************************/

/*** Interface ****************************************************************/

/*** Variables ****************************************************************/

/*** Implementation ***********************************************************/

/******************************************************************************/
/*! GameTalkProtocol :: GameTalkProtocol

    \brief  Constructor

    \param  HostName - Hostname or IPAddress (in textual form) of the server
    \param  Port     - The TCP port where the GameTalk server listens
    \return          - void.
*/
/******************************************************************************/
EA::GameTalk::GameTalkProtocol::GameTalkProtocol(const char* hostname, const uint32_t port):
IGameTalkProtocol(hostname, port),
mConnection(NULL)
{
	Connect();
}


/******************************************************************************/
/*! GameTalkProtocol :: GameTalkProtocol

\brief  Constructor

\param  Port     - The TCP port where the GameTalk server listens
\return          - void.
*/
/******************************************************************************/
EA::GameTalk::GameTalkProtocol::GameTalkProtocol(const uint32_t port):
IGameTalkProtocol(NULL, port),
mConnection(NULL)
{
	Connect();
}


/******************************************************************************/
/*! GameTalkProtocol :: ~GameTalkProtocol

    \brief  GameTalkProtocol destructor

    \param          - none.
    \return         - void.
*/
/******************************************************************************/
EA::GameTalk::GameTalkProtocol::~GameTalkProtocol()
{
    delete(mConnection);
    mConnection = NULL;
}

bool EA::GameTalk::GameTalkProtocol::Connect()
{
	if (!mConnection)
	{
		// If we have a NULL mIpAddress that means we're in passive mode (listening for a connection)
		mConnection = new EasyTCP::Connection(!mIpAddress);
		if (!mIpAddress) // In passive mode - we initialize the listener socket (once) before we attempt to listen on it
			mConnection->InitListenerSocket(uint16_t(mPort & 0xffff));
	}
	else if (mConnection->ConnectionError()) // If we've had a connection error - we'll have to reinitialize the socket
		mConnection->Disconnect();

	bool gotConnection = false;
	if (mConnection)
	{
		if (mIpAddress && mIpAddress[0] != 0) // The user has given us a hostname to connect to
		{
			if (mConnection->Connect(mIpAddress, uint16_t(mPort & 0xffff)))
				gotConnection = true;
		}
		else if (mConnection->Listen())
			gotConnection = true;
	}

	return gotConnection;
}

/******************************************************************************/
/*! GameTalkProtocol :: IsConnected

    \brief  Determine whether or not we're connected to the GameTalk server.

    \param          - none.
    \return         - true if connected to the GameTalk server
*/
/******************************************************************************/
bool EA::GameTalk::GameTalkProtocol::IsConnected()
{
	if (mConnection)
		return mConnection->IsConnected();

	return false;
}

/******************************************************************************/
/*! GameTalkProtocol :: Send

    \brief  Send a GameTalk message to the server

    \param  Msg     - What to send
    \param  MsgSize - How much to send
    \return         - true if successful

    NOTE:  This method is called from either the GAME thread or the network
           thread (in response to a received message).
*/
/******************************************************************************/
bool EA::GameTalk::GameTalkProtocol::Send(void *msg, size_t msgSize)
{
	if (this->IsConnected())
	{
		return mConnection && mConnection->Send(static_cast<uint8_t *>(msg), static_cast<uint32_t>(msgSize));
	}

	return false;
}

/******************************************************************************/
/*! GameTalkProtocol :: Poll

    \brief  Heartbeat hook; called once per frame.

    \param          - none.
    \return         - void.

    NOTE:  This method is called from the GAME thread.
*/
/******************************************************************************/
int EA::GameTalk::GameTalkProtocol::Poll()
{
    if (mConnection)
    {
		mConnection->IdlePulse();
		if (mConnection->IsConnected())
			return mConnection->PollSocket();
		else // Let the user of our Poll know we're disconnected by returning a "less than zero" value
			return -1;
    }
	return 0;
}

/******************************************************************************/
/*! GameTalkProtocol :: RegisterReceiverCallback

    \brief  virtual overridden function to hand our Connection member a pointer to the Utility::Parser.

    \param  callback     - The member function callback
    \param  gameTalkManager - a pointer to the GameTalkManager
    \return         - void.

    NOTE:  This method is called from the GAME thread.
*/
/******************************************************************************/

void EA::GameTalk::GameTalkProtocol::RegisterReceiverCallback(GameTalkReceiverFnc callback, GameTalkInstance * gameTalkInstance) 
{
	IGameTalkProtocol::RegisterReceiverCallback(callback, gameTalkInstance);
	if (mConnection) // If the network cable isn't connected - mConnection will be NULL
		mConnection->SetParser(mParser);
}

bool EA::GameTalk::GameTalkProtocol::InitNetwork()
{
	// Only use the following function if you are going to secure communications.
	//NetConnStartup();
	// Use the following function invocation if you are going to have insecure communication.
	return (NetConnStartup("-nosecure") == 0)? true : false;
}

bool EA::GameTalk::GameTalkProtocol::ShutdownNetwork()
{
	const int open = USER_GAMETALK_CREATE_BINARY_GUID('o','p','e','n');
	int32_t status = NetConnStatus(open, 0, NULL, 0);
	if (status != 0)
	{
		if (NetConnShutdown(0))
			return false;
		else
			return true;
	}
	return true;
}
