//===========================================================================//
// 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 NetworkClient to inherit from Node					  //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#if !defined(NETWORK_HPP)
#	define NETWORK_HPP

#	if !defined(RECEIVER_HPP)
#		include <receiver.hpp>
#	endif

#	if !defined(TIME_HPP)
#		include <time.hpp>
#	endif

#	if !defined(HOSTID_HPP)
#		include <hostid.hpp>
#	endif

	class Mission;
	class NetworkManager;
	class NotationFile;

	//
	//---------------------------------------------------
	// Support types for interest manager
	//---------------------------------------------------
	//
	typedef Enumeration InterestZoneID;
	const InterestZoneID NullInterestZoneID = 0;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkAddress ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	typedef LWord NetworkAddress;

   extern const NetworkAddress NullNetworkAddress;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkClient ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class NetworkPacket;

	class NetworkClient:
		public Receiver
	{
		friend class NetworkManager;

	//##########################################################################
	// Shared Data support
	//
	public:
		static Derivation ClassDerivations;
		static SharedData DefaultData;

	//##########################################################################
	// Construction and destruction support
	//
	public:
		enum ClientID {
			NetworkManagerClientID = 0,
			EntityManagerClientID = 1,
			HostManagerClientID = 2,
			InterestManagerClientID = 3,
			ApplicationClientID = 4,
			ConsoleClientID = 5,
			IcomManagerClientID = 6
		};

	private:
		ClientID
			clientID;

	protected:
		NetworkClient(
      	ClassID class_ID,
			SharedData &virtual_data,
			ClientID clientID
		);

	public:
		~NetworkClient();

		Logical
      	TestInstance() const;

	//##########################################################################
	// Message packet receiving
	//
	public:
		virtual void
			ReceiveNetworkPacket(
				NetworkPacket *packet,
				Receiver::Message *packet_message
			);
	};

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

	#define NETWORKMANAGER_BUFFER_SIZE 1600

	class NetworkManager__ReceiveEggFileMessage;

	class NetworkManager:
		public NetworkClient
	{
	//##########################################################################
	// Shared Data support
	//
	public:
		static Derivation ClassDerivations;
		static SharedData DefaultData;

	public:
		typedef Enumeration GameID;

		const NetworkAddress&
			GetAddress()
				{return address;}

		NetworkManager(SharedData &shared_data);
		~NetworkManager();

		void
			SetGameID(GameID new_id)
				{gameID = new_id;}

		virtual void
			Send(
				Message *what,
				ClientID to,
				HostID host_id
			);
		void
			Broadcast(
				Message *what,
				ClientID to
			);
		virtual void
			ExclusiveBroadcast(
				Message *what,
				ClientID to
			);
		Logical
			RoutePacket();
		virtual Logical
			ExecuteBackground();

		NetworkClient*
			GetNetworkClientPointer(ClientID client_id);

		virtual void
			StartConnecting(Mission *mission);

		virtual Logical
			Shutdown();

		virtual void
			Marker(char *) {};

		enum NetworkMode
		{
			ReliableMode,
			UnreliableMode
		};

		virtual void
			Mode(NetworkMode) {};

//	protected:	//GY for test only
		virtual Logical
			CheckBuffers(NetworkPacket*);
		virtual void
			RemovePacket(NetworkPacket *packet);

		GameID
			gameID;
		NetworkAddress
			address;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Message Support
	//
	public:
		//
		// Message IDs
		//
		enum
		{
			ReceiveEggFileMessageID = NetworkClient::NextMessageID,
			NextMessageID
		};

		//
		// Message types
		//
		typedef NetworkManager__ReceiveEggFileMessage
			ReceiveEggFileMessage;

		//
		// Message table
		//
		static const HandlerEntry
			MessageHandlerEntries[];
		static MessageHandlerSet
			MessageHandlers;

		void
			ReceiveEggFileMessageHandler(ReceiveEggFileMessage* EggMessage);

	protected:
		char
			*eggTempBuffer;
		NotationFile
			*networkEggNotationFile;
		long
			eggTempNext;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkManager messages ~~~~~~~~~~~~~~~~~~~~~~~~~
	// NetworkManager__ReceiveEggFileMessage
	// NOTE: this message should be setup as variable length rather than fixing the
	// size at 1000, I wasn't sure how to do this and there wasn't anyone around
	// to ask at the time so I did it this way temporarily.
	//
	class NetworkManager__ReceiveEggFileMessage:
		public Receiver__Message
	{
	public:
		NetworkManager__ReceiveEggFileMessage(
			int sequence_number,
			int total_file_length,
			char* notation_data,
			int length
		):
			Receiver__Message(
				NetworkManager::ReceiveEggFileMessageID,
				sizeof(NetworkManager__ReceiveEggFileMessage)
			),
			sequenceNumber(sequence_number),
			notationFileLength(total_file_length),
			thisMessageLength(length)
				{Mem_Copy(notationData,notation_data,length,sizeof(notationData));}
		int
			sequenceNumber;
		int
			notationFileLength;
		int
			thisMessageLength;
		char
			notationData[1000];
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~ NetworkPacketHeader ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class NetworkPacketHeader
	{
	public:
		NetworkClient::ClientID
			clientID;
		NetworkManager::GameID
			gameID;
		HostID
			fromHost;
		Time
			timeStamp;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkPacket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class NetworkPacket:
		public NetworkPacketHeader
	{
	public:
		Receiver::Message
			messageData;

	};

#endif
