//===========================================================================//
// File:	network.hh                                                          //
// Project: MUNGA           Brick: Network Manager                           //
// Contents: Interface specification for network brick                       //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 11/01/94  JMA  Initial coding.                                            //
// 11/03/94  ECH	Made compatible with BC4.0											  //
// 11/03/94  ECH	Changed InBox to inherit from Node					  //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#pragma once

#include "Adept.hpp"
#include "Receiver.hpp"

namespace Adept {

	const int Maximum_Connection_Numbers=static_cast<int>(255);

	class Connection;
	class NetStatCollector;

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef Receiver__ClassData			InBox__ClassData;
	typedef Receiver__Message			InBox__Message;


	//-----------------------  End of inheritance stuff -----------------------

	class __declspec(novtable) InBox:
		public Receiver
	{
	public:
		friend class NetworkManager;

	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef InBox__ClassData			ClassData;
		typedef InBox__Message			Message;

		static ClassData 
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction, Testing
	//
	public:
		InBox(
			ClassData *class_data,
			int boxID
		);
		~InBox();

		void
      	TestInstance();
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Message packet receiving
	//
	public:
		virtual void
			ReceiveNetworkPacket(
				const _NetPacket *packet,
				const Message *message
			);

		void
			Send(
				const Message *message,
				Connection *connection
			);
		void
			Broadcast(const Message *message)
				{
					Check_Object(this); Check_Object(message);
					ExclusiveBroadcast(message);
					ReceiveNetworkPacket(NULL, message);
				}
		void
			ExclusiveBroadcast(const Message *message);

	protected:
		void
			SendIt(
				DWORD destination,
				const Message *message
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Protected data
	//
	protected:
		int
			boxID;
	};

	class Network__DataTransferMessage
	{
	public:
		BYTE
			inBox;
		size_t
			dataLength;

		void
			TestInstance() const
				{}
	};



	struct BigMessageCollector
	{
	public:
		BigMessageCollector()
		{
			m_bigMessageSize = 0;
			m_bigMessageType = 0;
			m_bigPacketCRC = 0;
			m_bigMessage = 0;
		}

		int
			m_bigMessageSize;
		int
			m_bigMessageType;

		DWORD
			m_bigPacketCRC;

		Stuff::DynamicMemoryStream
			*m_bigMessage;

	};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Network ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


	class QuedPacket:
		public Stuff::Plug
	{
	public:
		Stuff::MemoryStream *packetData;
		int	messageType;
		int connectionID;

		QuedPacket(int connection, int type, Stuff::MemoryStream *data);
		~QuedPacket();
	};

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef InBox__ClassData		Network__ClassData;
	typedef InBox__Message			Network__Message;

	class Network:
		public InBox
	{
		friend class InBox;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Public Types
	//
	public:
		typedef Network__ClassData					ClassData;
		typedef Network__Message					Message;
		typedef Network__DataTransferMessage	DataTransferMessage;

		static int DefaultPacketSize;

		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;
		
		static Network*
			GetInstance() 
		{
			return reinterpret_cast<Network *>( GlobalPointers::GetGlobalPointer(NetworkGlobalPointerIndex));
		};



		enum BoxID {
			SystemMessageStartID,
				NetworkBoxID,
				ConnectionBoxID,
				ApplicationBoxID,
				BigPacketStartBufferBoxID,
				BigPacketPartBufferBoxID,
				BigPacketEndBufferBoxID,
			SystemMessageStopID,

			GameMessageStartID,
				FullConnectionListMessageID,
				FirstDirectApplicationMessageID,
				LastDirectApplicationMessageID = FirstDirectApplicationMessageID+60,
				FirstDictionaryPageMessageID,
				LastDictionaryPageMessageID = FirstDictionaryPageMessageID+80,
			GameMessageStopID,

			GosMessageStartID = 224,
			GosMessageStopID = 256,
		};



		enum {
			NoHash = 0, // don't hash this message type
			Hash,		// hash this message type
			GameSpecificHash // hash this message type with data about the current game
		};


		static int
			HashMessageTypeFlags[255];

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Intialize, Construction, Destruction
	//
	public:
		Network();
		~Network();
		
		void Recycle(void);

		void
      	TestInstance();
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Message packet receiving
	//
	public:
		void
			ReceiveNetworkPacket(
				const _NetPacket *packet,
				const Message *message
			);

	
		BigMessageCollector m_bigMessageCollectors[Maximum_Connection_Numbers];

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Public Interface
	//
	public:
		bool
			RoutePacket();
        void net_AddPlayer(const char* player_name, DWORD net_id); // jcem for Mission review
        void net_RemovePlayer(DWORD net_id); // jcem for Mission review
		bool
			RouteLocalPacket();

		InBox*
			FindInBox(BoxID box_id);

	public:
		static DWORD
			BroadcastAddress;
		static DWORD
			ServerAddress;
		static DWORD
			MyAddress;

		static bool
			bUseNewUI;

		int
			packetsSent[Maximum_Connection_Numbers];
		int
			packetsDropped[Maximum_Connection_Numbers];


	private:
		bool amIServer;
		int  currentPlayerCount;
		int  serverKey;
		int	 nextConnectionID;

		Stuff::ChainOf<QuedPacket*> localPacketQue;
	public: // jcem Accssor for Mission review
        int  Get_currentPlayerCount() const { return currentPlayerCount; }
        int  Get_serverKey() const { return serverKey; }
        int	 Get_nextConnectionID() const { return nextConnectionID; }
        void Set_currentPlayerCount(int n) { currentPlayerCount = n; }
        void Set_serverKey(int n) { serverKey = n; }
        void Set_nextConnectionID(int n) { nextConnectionID = n; }


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Connection Methods
	//
	public:
		Connection*
			GetConnection(int host_ID);
				
		Connection*
			FindConnection(DWORD net_address);
		
		void RemoveConnection(int host_ID);

		void
			SendConnections();

		
		void
			SendNetMessage(int connection, int message_type, Stuff::MemoryStream *message, bool reliable);
		void
			SendBigMessage(int connection, int message_type, Stuff::MemoryStream *message, bool reliable);
		void
			ReceiveMessage(int connection, int message_type, Stuff::MemoryStream *message);

		bool
			AmIServer(){Check_Object(this); return amIServer;}

		int
			GetPlayerCount(){Check_Object(this); return currentPlayerCount;}

		int
			GetServerKey(){Check_Object(this); return serverKey;}

		const char *GetGameName();

		void 
			RemovePlayer(int connection_id);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Statistics Methods
	//

		NetStatCollector *netStatCollector;

		// these need to be propegated into the mech layer eventually

		enum {
			
			IncomingProtocolHeaderBitSizeStat,
			OutgoingProtocolHeaderBitSizeStat,

			IncomingHeaderBitSizeStat,
			OutgoingHeaderBitSizeStat,

			IncomingSystemMessageBitSizeStat,
			OutgoingSystemMessageBitSizeStat,
			
			IncomingWeaponMessageBitSizeStat,
			OutgoingWeaponMessageBitSizeStat,

			OutgoingMechMovementBitSizeStat,
			IncomingMechMovementBitSizeStat,

			MovementConfirmationBitSizeStat,
			
			MechInternalBitSizeStat,
			BuildingDamageBitSizeStat,

			VehicleBitSizeStat,

			IncomingPacketCountStat,
			OutgoingPacketCountStat,
			
			IncomingTotalPacketSizeStat,
			OutgoingTotalPacketSizeStat,

			NetStatCount
		};

		void AddConnectionToStats(int id);
		void RemoveConnectionToStats(int id);

		void AdvanceStats();

	protected:
		Connection*
			activeConnections[Maximum_Connection_Numbers];


	

		bool
			startedGosNet;

	};

	inline void
		InBox::ExclusiveBroadcast(const Message *message)
			{
				Check_Object(this); Check_Object(message);
				SendIt(Network::BroadcastAddress, message);
			}

}

