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

// --- Include guard

#ifndef EA_GAMETALK_IGAMETALKPROTOCOL_H
#define EA_GAMETALK_IGAMETALKPROTOCOL_H

// --- Includes
#include "GameTalk/GameTalkBase.h"
#include "GameTalk/Utility.h"

namespace EA
{
    namespace GameTalk
    {
		class IGameTalkProtocol
        {
		public:
			enum ConnectionMode
			{
				kActive,
				kPassive,
			};

			enum
			{
				DEFAULT_GAMETALK_PORT = 9876
			};

			// Constructor when you want the game to connect to the server
			IGameTalkProtocol(const char* ipAddress, int port = DEFAULT_GAMETALK_PORT):
				mParser(NULL),
				mIpAddress(ipAddress),
				mPort(port),
                mShouldSendInitializePacket(ipAddress != NULL)
			{
				// copy the memory from the ipAddress into our own buffer so we're not reliant on the user to keep that IP Address around in memory for the life-time of the GameTalkProtocol
				USER_GAMETALK_STRNCPY_ADD_NULL(mIpAddressBuffer, ipAddress, USER_GAMETALK_STRLEN(ipAddress) + 1);
				mIpAddress = mIpAddressBuffer;
			}
			// Constructor when you want the server to connect to the game
			IGameTalkProtocol(int port = DEFAULT_GAMETALK_PORT):
				mParser(NULL),
				mIpAddress(NULL),
				mPort(port),
                mShouldSendInitializePacket(false)
			{
			}
			virtual ~IGameTalkProtocol() 
			{
				if (mParser)
				{
					delete mParser;
					mParser = NULL;
				}
			}

			virtual bool IsConnected() = 0;
            virtual bool Send(void* buffer, size_t msgSize) = 0;
            virtual int Poll() = 0;

            virtual void ShouldSendInitializePacket(bool bValue) { mShouldSendInitializePacket = bValue; }
			// Typically we only want to send the initialize data (i.e. name, version, + platform) to server if we're in active mode
			// In passive mode the server is responsible for telling us our name - at which point we'll send it our version (and our registered channels)
            virtual bool ShouldSendInitializePacket() const { return mShouldSendInitializePacket; }

			virtual void RegisterReceiverCallback(GameTalkReceiverFnc callback, GameTalkInstance * gameTalkInstance) 
			{
				USER_GAMETALK_ASSERT(mParser == NULL, "mParser is non-null - this could indicate that a Parser and its corresponding callback have already been registered");
				if (!mParser) // Only new a Parser if we're not already pointing at something
					mParser = new Utility::Parser(callback, gameTalkInstance);
			}

			virtual bool Connect() = 0;

			ConnectionMode Mode()
			{
				if (mIpAddress)
					return EA::GameTalk::IGameTalkProtocol::kActive;
				else
					return EA::GameTalk::IGameTalkProtocol::kPassive;
			}

			// Gives GameTalkInstance access to reseat which Parser is used
			friend class EA::GameTalk::GameTalkInstance;
		protected:
			// Probably don't want to force users to implement this function
			virtual bool SetSocketBlocking(bool blocking){ USER_GAMETALK_USE_VAR_TO_AVOID_WARNING(blocking); return false; }

			// Re-entrant safe (supports recursion) parser of incoming data (converts to GameTalkMessage)
			EA::GameTalk::Utility::Parser * mParser;

			// Since we want GameTalkProtocols to be able to reconnect we store the IP address and/or port number for the connection
			const char* mIpAddress;
			int mPort;
            bool mShouldSendInitializePacket;
			char mIpAddressBuffer[32];
		private:
            IGameTalkProtocol(const IGameTalkProtocol& protocol);
            IGameTalkProtocol& operator=(const IGameTalkProtocol& protocol);
        };
    }
}

#endif  //  EA_GAMETALK_IGAMETALKPROTOCOL_H


