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


#pragma once

#include "NetConstants.hpp"
#include "NetUpdateManager.hpp"

namespace MechWarrior4 
{

	//##########################################################################
	//###########################   Dictionary
	//##########################################################################


	class DictionaryParagraph:
		public Stuff::Plug
	{
	public:
		DictionaryParagraph();
		DictionaryParagraph(Entity *entity, int message_type, int active_update_cycle, int inactive_update_cycle);
		~DictionaryParagraph();

		SlotOf<Entity*> entitySlot;
		int messageType;
		int activeUpdateCycle;
		int inactiveUpdateCycle;


		bool active;
		int activeCycle;

		// this is for the messages that use sizes 
		// based off of the entity.
		// that way it doesn't need the entity to 
		// skip the message.  
		// We should never have to skip a message
		// from a mech we haven't decoded at lease once.

		int entityVariableMessageSize;

		void Encode(Stuff::DynamicMemoryStream* memory_stream, int connection_to, int debug_level, int bandwidth);
		void Decode(Stuff::MemoryStream* memory_stream, Time till, Scalar packet_latency, int connection_from, int debug_level, int bandwidth);

		bool ReadyToUpdate(int cycles_to_update);

	};

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

	class DictionaryPage:
		public Stuff::Plug
	{
	public:
		
		
		DictionaryPage(int page_number);
		~DictionaryPage();

		ChainOf<DictionaryParagraph*>
			dictionaryParagraphs;

		int
			pageNumber;

		int
			paragraphCount;

		// Cycle support

		int 
			CalculateCycles(Time till);

		bool 
			MaintainCycles(Time till, int connection_id);

		bool
			RequireUpdate(Time new_time, int connection_id);

		enum {
			HalfhzBit = 0,
			OneHzBit,
			TwoHzBit,
			ThreeHzBit,
			FourHzBit,
			SixHzBit,
			EightHzBit,
			NineHzBit,
			TwelveHzBit,
			SixteenHzBit,
			UpdateCycleCount
		};

		enum {
			HalfhzType = 1 << HalfhzBit,
			OneHzType = 1 << OneHzBit,
			TwoHzType = 1 << TwoHzBit,
			ThreeHzType = 1 << ThreeHzBit,
			FourHzType = 1 << FourHzBit,
			SixHzType = 1 << SixHzBit,
			EightHzType = 1 << EightHzBit,
			NineHzType	= 1 << NineHzBit,
			TwelveHzType = 1 << TwelveHzBit,
			SixteenHzType = 1 << SixteenHzBit
		};

		int 
			currentCycleCount[UpdateCycleCount];

		Time
			lastExecuted;

		BYTE
			lastPacketNumber;

		Scalar
			timeFromLastSlowestUpdate;

		int usedUpdateCycle;
		int cyclesToUpdate;


		// active / inactive cycle support

		int currentActiveCycle;
		Time activeCycles[8];
		
		
		// update support

		DictionaryParagraph *
			MakeDictionaryParagraph(Entity *entity, int message_type, UpdateRate update_cycle);

		void Encode(Stuff::DynamicMemoryStream* memory_stream, int connection_to, int debug_level, int bandwidth);
		void Decode(Stuff::MemoryStream* memory_stream, Time till, int connection_to, int debug_level, int bandwidth);

		static Scalar CalculateSeconds(int type);
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	class Dictionary:
		public Stuff::Plug
	{
		friend class DictionaryManager;

	protected:
		Dictionary(int version_number, int connection);
		
	public:
		Dictionary(int version_number, int connection, int debug_level, int bandwidth);
		~Dictionary();

		SortedChainOf<DictionaryPage*, int>
			dictionaryPages;
		
		int 
			versionNumber;
		int 
			connectionID;

		int
			debugDictionaryLevel;
		int
			dictionaryBandwidth;


		DictionaryPage *
			MakeDictionaryPage(int page_number);

		
		void Encode(Time till);
		void Decode(int message_type, Stuff::MemoryStream* memory_stream, Time till);

	};

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


	class DictionaryManager:
		public Stuff::Plug
	{
	public:
		DictionaryManager(int connection);
		~DictionaryManager();

		Dictionary *MakeNewDictionary(int version_number, int debug_level, int bandwidth);
		Dictionary *GetCurrentDictionary();
		Dictionary *GetDictionary(int version);
				
		void Encode(Time till);
		void Decode(int message_type, Stuff::MemoryStream* memory_stream);
		
		int GetNextDictionaryID();

	protected:
		int 
			connectionID;
		int 
			activeDictionaryIndex;

		Dictionary*
			activeDictionary;

		SortedChainOf<Dictionary*, int>
			dictionaryIndex;

	};
};