//===========================================================================//
// File:	EntityUpdateManager.hpp											
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 07/26/1999  JSE  Inital coding
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Microsoft Corp.										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//



/*

	Future enhancements:
		
		multiple dictionaries need a way to share the updates which means
		that all active pages must run together and then post their data
		then the dictionaries run and pull the data that they need. 

		This will allow for us to tailor messages to each persons bandwidth.
		It will also allow us to optimize messages based off of a broadcast server.

		If a broadcast server exsists then we will just send all the mech data in one 
		packet as well as sending first person updates to the individual player. 

		If there is not a broadcast server then each player receives everyone elses
		vehicles but not his own in the uber updates.

		It is possible that doubling the full position update and completly removing the
		partial updates will be a better solution.

		It is also possible that we need to double the control update to 1/2 a second or
		even higher under high bandwidth games
*/




#pragma once

#include "MW4.hpp"
#include <Adept\EntityManager.hpp>

#include "NetConstants.hpp"
#include "Dictionary.hpp"
#include "NetUpdateManager.hpp"
#include "NetMovement.hpp"
#include "NetSubsystems.hpp"
#include "NetWeapon.hpp"
#include "NetGenericMessages.hpp"
#include "NetDamage.hpp"
#include "NetClientServerController.hpp"
#include "NetVehicleMovement.hpp"
#include "NetBitDepths.hpp"
#include "Airplane.hpp"
#include "Boat.hpp"
#include "Dropship.hpp"
#include "Helicopter.hpp"
#include "Hovercraft.hpp"
#include "Tank.hpp"
#include "Truck.hpp"
#include "Turret.hpp"

namespace MechWarrior4 
{

	class VehicleCommand;

	//##########################################################################
	//###########################   MWEntityManager
	//##########################################################################

	class MWEntityManager:
		public Adept::EntityManager
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction and destruction
	//
	public:
		MWEntityManager();
		~MWEntityManager();

		void
			TestInstance() const;	
		

		static MWEntityManager*
			GetInstance() 
		{
			return reinterpret_cast<MWEntityManager *>(GlobalPointers::GetGlobalPointer(EntityManagerGlobalPointerIndex));
		};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Client Server Stuff
	//

		BitDepthManager *bitManager;


		static BYTE *Packet_Buffer;

		enum {
			ToMechOffset=0,
			ToGroundOffset,
			ToServerOffset,
			ToNoTargetOffset
		};

		enum {
			DictionaryIndexMessageID = Network::FirstDictionaryPageMessageID,

			FirstPersonControlMessageID,
			FirstPersonObserverControlMessageID,
			FirstPersonSmallConfirmationMessageID,
			FirstPersonFullConfirmationMessageID,

			StartFirstPersonWeaponMessageID,
			FirstPersonWeaponToMechCommandMessageID = StartFirstPersonWeaponMessageID,
			FirstPersonWeaponToGroundCommandMessageID,
			FirstPersonWeaponToServerObjectCommandMessageID,
			FirstPersonWeaponNoTargetCommandMessageID,
			EndFirstPersonWeaponMessageID = FirstPersonWeaponNoTargetCommandMessageID,
			
			StartThirdPersonWeaponMessageID,
			ThirdPersonWeaponToMechCommandMessageID = StartThirdPersonWeaponMessageID,
			ThirdPersonWeaponToGroundCommandMessageID,
			ThirdPersonWeaponToServerObjectCommandMessageID,
			ThirdPersonWeaponNoTargetCommandMessageID,
			EndThirdPersonWeaponMessageID = ThirdPersonWeaponNoTargetCommandMessageID,

			StartAIWeaponMessageID,
			AIWeaponCommandToMechtMessageID = StartAIWeaponMessageID,
			AIWeaponCommandToGroundtMessageID,
			AIWeaponCommandToServerObjectMessageID,
			AIWeaponCommandToNoTargetMessageID,
			EndAIWeaponMessageID = AIWeaponCommandToNoTargetMessageID,

			WeaponBundleMessageID,

			DictionaryPage0MessageID,
			DictionaryPageMaxMessageID = DictionaryPage0MessageID + MaximumPages
		};

	
		


		void
			UpdateEntities();

		void
			ServeLocalEntities(Time till);
		
		void
			ResetActivityFlags();

		void
			UpdateClientEntites(int connection, int message_type, Stuff::MemoryStream *message);

		void
			CreateWeaponEffect(WeaponUpdate &weapon_packet);

		void
			AddMover(Mover *mover);

		void
			RemoveMover(Mover *mover);

		void
			BuildTileBoundDamageList();


		void
			AddPlayerVehicle(Mover *mover);
		void
			RemovePlayerVehicle(Mover *mover);


		void 
			UpdateDictionaries(void);
		void 
			UpdateDictionaries(int connection);


		void 
			MakeDictionaryPages(Dictionary *dictionary);

		void SetPlayerReady(Entity *entity);

		Stuff::Scalar
			GetTimeSlice(Stuff::Time till)
				{
					Stuff::Scalar slice = static_cast<Stuff::Scalar>(till - lastExecuted);
					return slice;
				}

		void
			StartUpdates();
		void
			EndUpdates();

		void RespawnClient(int connection_id, Point3D trans);

		void StartClient();
		void StopClient();

		void StartServer();
		void StopServer();

		void Reset();

		void PreCollisionNetworkEvents();

	public:

			
		ChainOf<WeaponUpdate*>
			weaponUpdates;

		void
			PlayerWeaponUpdate(WeaponUpdate *weapon);
		void
			AIWeaponUpdate(WeaponUpdate *weapon);

		ChainOf<VehicleCommand*> quedCommands;
		
		int commandCount;
		void QueCommand(int command);


		// these are the incomming weapon ques

		ChainOf<WeaponUpdate*>
			networkWeaponsQue;
		void
			QueWeapon(WeaponUpdate *weapon);

		DictionaryManager *
			GetDictionaryManager(int connection)
				{return dictionaryManager[connection];}

		void
			SetDirtyFlag()
				{dictionaryDirtyFlag = true;}

		void
			SetDirtyFlag(bool flag)
				{dictionaryDirtyFlag = flag;}

		bool
			GetDirtyFlag()
				{return dictionaryDirtyFlag;}


	protected:
		
		bool
			dictionaryDirtyFlag;

		DictionaryManager
			*dictionaryManager[Maximum_Players];
		

		

	public:
		SortedChainOf<Mech*, Adept::ReplicatorID>
			servedMechs;

		ChainOf<Mech*> servedRespawnLances; // jcem - for delayed lancemate respawn

		ChainOf<Airplane*>
			servedAirplanes;
		ChainOf<Boat*>
			servedBoats;
		ChainOf<Dropship*>
			servedDropships;
		ChainOf<Helicopter*>
			servedHelicopters;
		ChainOf<Hovercraft*>
			servedHovercraft;
		ChainOf<Tank*>
			servedTanks;
		ChainOf<Truck*>
			servedTrucks;
		ChainOf<Turret*>
			servedTurrets;

		

		Time
			lastExecuted;
		Time
			lastScore;
		Time
			lastWeapon;
		Time
			lastActiveReset;

		int 
			maximumNearBuildings,
			maximumMidBuildings,
			maximumFarBuildings;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	


	public:
		Vehicle *playerVehicle[Maximum_Players];

		Scalar FindGroundHeight(Stuff::Scalar x_position, Stuff::Scalar z_position);



		ServerController *serverController;
		ClientController *clientController;

		

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


		static bool IsNumberAhead(int value, int position, int number_ahead, int wrap_around_number);
		static bool IsNumberBehind(int value, int position, int number_behind, int wrap_around_number);
		static bool IsNumberWithin(int value, int positoin, int number_within, int wrap_around_number);


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;
    public:
        unsigned int m_uPostDeathFlags;
    public:
        void QueRespawnLancemate(Mech* lancemateMech); // jcem - for delayed lancemate respawn
	};

};