//===========================================================================//
// File:	Dictionary.cpp											
//---------------------------------------------------------------------------//
//   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               //
//===========================================================================//


#include "MW4Headers.hpp"

#include "Dictionary.hpp"
#include "MWEntityManager.hpp"
#include "NetUpdateManager.hpp"
#include "MWApplication.hpp"
#include "Adept\NetStatCollector.hpp"

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

Scalar OneCycle = 2.0f;

Scalar HerzPreSec[DictionaryPage::UpdateCycleCount] = 
{
	0.5f, //double of the hrz since we are in a 2 second cycle..
	1.0f,
	2.0f,
	3.0f,
	4.0f,
	6.0f,
	8.0f,
	9.0f,
	12.0f,
	16.0f
};


int Translation_Table[DictionaryPage::UpdateCycleCount] = 
{
	DictionaryPage::HalfhzType,
	DictionaryPage::OneHzType,
	DictionaryPage::TwoHzType,
	DictionaryPage::ThreeHzType,
	DictionaryPage::FourHzType,
	DictionaryPage::SixHzType,
	DictionaryPage::EightHzType,
	DictionaryPage::NineHzType,
	DictionaryPage::TwelveHzType,
	DictionaryPage::SixteenHzType
};



//##########################################################################
//###########################   DictionaryParagraph
//##########################################################################

DictionaryParagraph::DictionaryParagraph():
	Plug(DefaultData),
	entitySlot(NULL)
{
	activeUpdateCycle = 0x0;
	inactiveUpdateCycle = 0x0;
	active = true;
	activeCycle = -1;
}

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

DictionaryParagraph::DictionaryParagraph(Entity *entity, int message_type, int active_update_cycle, int inactive_update_cycle):
	Plug(DefaultData),
	entitySlot(NULL)
{
	Check_Object(entity);
	entitySlot.Add(entity);

	NetVerify(message_type > UpdateManager::BaseUpdateID);
	NetVerify(message_type < UpdateManager::UpdateCount);

	messageType = message_type;
	activeUpdateCycle = active_update_cycle;
	inactiveUpdateCycle = inactive_update_cycle;
	active = true;
	activeCycle = 0;

	entityVariableMessageSize = -1;
}

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

DictionaryParagraph::~DictionaryParagraph()
{
	
}

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

void DictionaryParagraph::Encode(Stuff::DynamicMemoryStream* memory_stream, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);

	Entity *entity = entitySlot.GetCurrent();
	Check_Object(entity);

	ReplicatorID rep_id = entity->GetReplicatorID();



	UpdateEntry *update = &UpdateManager::UpdateEntries[messageType];

	(update->m_encode)(entity, memory_stream, connection, debug_level, bandwidth);


}

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

void DictionaryParagraph::Decode(Stuff::MemoryStream* memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);	

	Entity *entity = entitySlot.GetCurrent();

	if (entity != NULL)
	{
		Check_Object(entity);

		ReplicatorID rep_id = entity->GetReplicatorID();

		UpdateEntry *update = &UpdateManager::UpdateEntries[messageType];

		int rate_type = BitDepthManager::GetUpdateRate(update->m_updateID, bandwidth).m_ActiveRate;
		Scalar rate = DictionaryPage::CalculateSeconds(rate_type);

		(*update->m_decode)(entity, memory_stream, till, packet_latency, connection, debug_level, bandwidth, rate);
	}
	else
	{
		UpdateEntry *update = &UpdateManager::UpdateEntries[messageType];
		(*update->m_skip)(memory_stream, entityVariableMessageSize, till, connection, debug_level, bandwidth);
	}
}

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


bool DictionaryParagraph::ReadyToUpdate(int cycles_to_update)
{
	if (active)
	{
		if (activeUpdateCycle & cycles_to_update)
			return true;
	}
	else
	{
		if (inactiveUpdateCycle & cycles_to_update)
			return true;
	}
	return false;
}



//##########################################################################
//###########################   DictionaryPage
//##########################################################################



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

DictionaryPage::DictionaryPage(int page_number):
	Plug(DefaultData),
	dictionaryParagraphs(NULL)
{

	pageNumber = page_number;
	paragraphCount = 0;
	usedUpdateCycle = 0x0;
	lastExecuted = -2.0f;
	timeFromLastSlowestUpdate = 0.0f;
	lastPacketNumber = 0;

	for (int i = 0; i < UpdateCycleCount; ++i)
	{
		currentCycleCount[i] = 0;
	}


	if (pageNumber >= MaximumPages)
		STOP(("DictionaryPage::DictionaryPage:TOO MANY PAGES"));

	NetVerify(pageNumber > -1);
	NetVerify(pageNumber < MaximumPages);


	Time current_time = gos_GetElapsedTime();
	for (i = 0; i < 8; ++i)
	{
		activeCycles[i] = current_time;
		current_time += 0.25;
	}
	currentActiveCycle = 0;

}

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

DictionaryPage::~DictionaryPage()
{
	Stuff::ChainIteratorOf<DictionaryParagraph*> iterator(&dictionaryParagraphs);
	Stuff::Plug *plug;
	while ((plug = iterator.GetCurrent()) != NULL)
	{
		iterator.Remove();
		Check_Object(plug);
		delete plug;
	}
}


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

void DictionaryPage::Encode(Stuff::DynamicMemoryStream* memory_stream, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);
	Stuff::ChainIteratorOf<DictionaryParagraph*> iterator(&dictionaryParagraphs);
	

	int paragraph_count = 0;


	++lastPacketNumber;

	if (lastPacketNumber == 255)
		lastPacketNumber = 0;

	
	MWEntityManager *manager = Cast_Object(MWEntityManager*, EntityManager::GetInstance());
	NetVerify(manager->serverController != NULL);
	Scalar current_time = (float)(gos_GetElapsedTime(1) * 1000.0);

	memory_stream->WriteBits(&lastPacketNumber, 8);
	memory_stream->WriteBits(&manager->serverController->lastPingDelta[connection], 32);
	memory_stream->WriteBits(&current_time, 32);

	//SPEWALWAYS(("jerryeds", "S-SEND - %d : t2-t1 : %f, t3 : %f", lastPacketNumber, manager->serverController->lastPingDelta[connection], current_time));


	//SPEW(("jerryeds", "ENCODE: packet %d", lastPacketNumber));
	//SPEW(("jerryeds", "ENCODE: t1 %d", manager->serverController->lastPingDelta[connection]));
	//SPEW(("jerryeds", "ENCODE: t2 %d", current_time));



	if (debug_level > 1)
	{
		BYTE magic_number = 0xAA;
		memory_stream->WriteBits(&magic_number, 8);
		//SPEW(("jerryeds", "ENCODE: MAGIC"));

		Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,8);
	}


	DictionaryParagraph *paragraph;

	while ((paragraph = iterator.ReadAndNext()) != NULL)
	{
		
		if (paragraph->ReadyToUpdate(cyclesToUpdate))
		{
			
			memory_stream->WriteBit(true);
			paragraph->Encode(memory_stream, connection, debug_level, bandwidth);
		}
		else
		{
			memory_stream->WriteBit(false);
		}

		if (debug_level > 1)
		{
			memory_stream->WriteBits(&paragraph_count, 8);
			Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,8);
	
		}

		++paragraph_count;



	}


	if (debug_level > 0)
	{
		BYTE magic_number = 0xAA;
		memory_stream->WriteBits(&magic_number, 8);
		Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,8);
	
	}

	Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,paragraph_count + 8);
	Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,64);
	

	
}

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

void DictionaryPage::Decode(Stuff::MemoryStream* memory_stream, Time till, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);

	// throw out old ones
	
	BYTE packet_number;
	Scalar t2_minus_t1;
	Scalar t3;
	
	memory_stream->ReadBits(&packet_number, 8);
	memory_stream->ReadBits(&t2_minus_t1, 32);
	memory_stream->ReadBits(&t3, 32);

	//SPEW(("jerryeds", "DECODE: packet %d", packet_number));
	//SPEW(("jerryeds", "DECODE: t1 %d", t2_minus_t1));
	//SPEW(("jerryeds", "DECODE: t2 %d", t3));


	if (debug_level > 1)
	{
		BYTE magic_number = 0;
		memory_stream->ReadBits(&magic_number, 8);
		Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,8);
		//SPEW(("jerryeds", "DECODE: MAGIC"));

		if(magic_number != 0xAA)
		{
			STOP(("UPDATE HEADER PAGE READ ERROR: %d",pageNumber));
		}
	}


	//SPEWALWAYS(("jerryeds", "DICTIONARY LATENCY : %f", packet_latency));

	if (MWEntityManager::IsNumberBehind(packet_number, lastPacketNumber, 40, 255))
	{
#if defined(LAB_ONLY)
		SPEWALWAYS(("jerryeds", "LATE DICTIONARY PACKET THROWN OUT"));
#endif
		return;
	}

	MWEntityManager *manager = Cast_Object(MWEntityManager*, EntityManager::GetInstance());
	Scalar t4 = (float)(gos_GetElapsedTime(1) * 1000.0);	
	manager->clientController->lastPingDelta = t4 - t3;
	MWApplication::GetInstance()->servedConnectionData[connection].effectivePing = t2_minus_t1 + (t4 - t3);

	//SPEWALWAYS(("jerryeds", "C-REC - %d : t2-t1 : %f,  t4-t3 %f  : t3 : %f  t4 : %f", packet_number, t2_minus_t1, t4 - t3, t3, t4));


	Scalar packet_latency = MWApplication::GetInstance()->servedConnectionData[connection].effectivePing * 0.5f;
	Min_Clamp(packet_latency, 1.0f);
	packet_latency *= 0.001f;


	//SPEWALWAYS(("jerryeds", "latency : %f\n", packet_latency));

	lastPacketNumber = packet_number;
	lastExecuted = till;

	Stuff::ChainIteratorOf<DictionaryParagraph*> iterator(&dictionaryParagraphs);
	
	int paragraph_count = 0;


	DictionaryParagraph *paragraph;
	while ((paragraph = iterator.ReadAndNext()) != NULL)
	{
		bool noskip_bit;
		memory_stream->ReadBit(noskip_bit);
		if (noskip_bit)
			paragraph->Decode(memory_stream, till, packet_latency, connection, debug_level, bandwidth);


		if (debug_level > 1)
		{
			int debug_paragraph_count = 0;
			memory_stream->ReadBits(&debug_paragraph_count, 8);

			Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,8);

			if (debug_paragraph_count != paragraph_count)
			{
				Entity *entity = paragraph->entitySlot.GetCurrent();

				if (entity != NULL && entity->instanceName)
				{
					STOP(("UPDATE PARAGRAPH READ ERROR: %s : Page %d, Paragraph %d, Type %d", (char*)entity->instanceName, pageNumber, paragraph_count, paragraph->messageType));
				}
				else
				{
					STOP(("UPDATE PARAGRAPH READ ERROR: NO ENTITY : Page %d, Paragraph %d, Type %d", pageNumber, paragraph_count, paragraph->messageType));
				}
			}
		}

		++paragraph_count;

	}


	if (debug_level > 0)
	{
		BYTE magic_number;
		memory_stream->ReadBits(&magic_number, 8);
		Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,8);
	
		if(magic_number != 0xAA)
		{
			STOP(("UPDATE PAGE READ ERROR: %d",pageNumber));
		}
	}

	Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,paragraph_count+8);
	Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,64);
}






Scalar DictionaryPage::CalculateSeconds(int type)
{
	Verify(type >= 0);
	Verify(type <= UpdateCycleCount);
	return 1.0f / HerzPreSec[type];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

int DictionaryPage::CalculateCycles(Time till)
{

	Scalar time_slice = static_cast<Stuff::Scalar>(till - lastExecuted);
	lastExecuted = till;

	//increment the time from the last full cycle.
	//The full cycle is OneCycle, which is also the 
	//slowest cycle.
	timeFromLastSlowestUpdate += time_slice;


	// calculate the carryover if there is any.
	Scalar carryover = 0;
	int carryover_count = 0;

	if (timeFromLastSlowestUpdate > OneCycle)
	{
		// how many cycles it carried over
		carryover_count = (int)(timeFromLastSlowestUpdate / OneCycle);
		// how far past the last cycle it carried over
		carryover = timeFromLastSlowestUpdate - (carryover_count * OneCycle);
	}

	// calculate the cycle counts
	int cycle_triggers = 0x0;
	for (int i = 0; i < UpdateCycleCount; ++i)
	{
		// this is how many times this cycle should have triggered
		int cycles_triggered = (int)(timeFromLastSlowestUpdate*HerzPreSec[i]);


		// if we haven't triggered that many times than trigger one
		if (cycles_triggered > currentCycleCount[i])
		{
			
			
			// add the cycle to the bit mask
			cycle_triggers |= (0x1<<i);

			// we only want to update once so 
			// rather than increment we just go ahead
			// and equal up to how many we should have 
			// updated.
			currentCycleCount[i] = cycles_triggered;
		}
		
		// subtract the carryover if there is any
		// if not the carryover_count will be zero and 
		// nothing will happen.
		currentCycleCount[i] -= (int)(carryover_count * HerzPreSec[i] * OneCycle);
		
	}


	if (carryover_count)
	{
		timeFromLastSlowestUpdate = carryover;
	}

	
	return cycle_triggers;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool DictionaryPage::MaintainCycles(Time till, int connection_id)
{

	Time largest_time = activeCycles[0];
		
	bool flip[8];

	bool req_update = false;

	Point3D cull_location;
	cull_location = MWApplication::GetInstance()->servedConnectionData[connection_id].vehiclePosition;
	

	// reset the counters
	for (int i = 0; i < 8; ++i)
	{
		flip[i] = false;

		if (till - activeCycles[i] > 2.0)
		{
			flip[i] = true;
			activeCycles[i] += 2.0;
			// deactivate any cylces that are on this cycle..


			// if this is the largest time to flip this frame
			// than this is the currentactivecycle.
			if (largest_time < activeCycles[i])
			{
				largest_time = activeCycles[i];
				currentActiveCycle = i;
			}
		}
	}


	// maintain the paragraphs active states
	DictionaryParagraph *paragraph;
	Stuff::ChainIteratorOf<DictionaryParagraph*> iterator(&dictionaryParagraphs);
	while ((paragraph = iterator.ReadAndNext()) != NULL)
	{
		if (paragraph->active && flip[paragraph->activeCycle])
		{
			paragraph->active = false;
			paragraph->activeCycle = -1;
		}

		UpdateEntry *update = &UpdateManager::UpdateEntries[paragraph->messageType];
		if ((update->m_maintainActiveFlag)(paragraph->entitySlot.GetCurrent(), cull_location))
		{
			paragraph->active = true;
			paragraph->activeCycle = currentActiveCycle;
		}

		if (paragraph->ReadyToUpdate(cyclesToUpdate))
		{
			req_update = true;
		}

	}

	return req_update;

}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

bool
	DictionaryPage::RequireUpdate(Time new_time, int connection_id)
{
	
	cyclesToUpdate = CalculateCycles(new_time);
	bool require_update = MaintainCycles(new_time, connection_id);

	return require_update;
}


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

DictionaryParagraph *
	DictionaryPage::MakeDictionaryParagraph(Entity *entity, int message_type, UpdateRate update_cycle)
{
	
	usedUpdateCycle |= Translation_Table[update_cycle.m_ActiveRate];
	usedUpdateCycle |= Translation_Table[update_cycle.m_InactiveRate];

	DictionaryParagraph *paragraph = new DictionaryParagraph(entity, message_type, Translation_Table[update_cycle.m_ActiveRate], Translation_Table[update_cycle.m_InactiveRate]);
	Check_Object(paragraph);

	dictionaryParagraphs.Add(paragraph);

	++paragraphCount;

	//NetVerify(paragraphCount < 64);

	return paragraph;

}


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

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

Dictionary::Dictionary(int version_number, int connection, int debug_level, int bandwidth):
	Plug(DefaultData),
	dictionaryPages(NULL, true)
{
	versionNumber = version_number;
	connectionID = connection;

	debugDictionaryLevel = debug_level;
	dictionaryBandwidth = bandwidth;


}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Dictionary::Dictionary(int version_number, int connection):
	Plug(DefaultData),
	dictionaryPages(NULL, true)
{
	versionNumber = version_number;
	connectionID = connection;

	debugDictionaryLevel = -1;
	dictionaryBandwidth = -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Dictionary::~Dictionary()
{
	Stuff::SortedChainIteratorOf<DictionaryPage*, int> iterator(&dictionaryPages);
	Stuff::Plug *plug;
	while ((plug = iterator.GetCurrent()) != NULL)
	{
		iterator.Remove();
		Check_Object(plug);
		delete plug;
	}
}


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

void
	Dictionary::Encode(Time till)
{
	
	Stuff::SortedChainIteratorOf<DictionaryPage*, int> iterator(&dictionaryPages);
	DictionaryPage *page;
	while ((page = iterator.ReadAndNext()) != NULL)
	{

		if (page->RequireUpdate(till, connectionID))
		{
			
			DynamicMemoryStream memory_stream(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize);
			// make stream

			// write dictionary format
			memory_stream.WriteBits(&versionNumber, 8);
			
			//SPEW(("jerryeds", "ENCODE: version %d", versionNumber));


			// write page data
			page->Encode(&memory_stream, connectionID, debugDictionaryLevel, dictionaryBandwidth);


			memory_stream.WriteByteAlign();
			memory_stream.Rewind();

			NetVerify(memory_stream.GetBufferBytesUsed() > 0);

			// send page
			Network::GetInstance()->SendNetMessage(
				connectionID, MWEntityManager::DictionaryPage0MessageID + page->pageNumber, &memory_stream, false);

			Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connectionID,4);
			
		}
		
	}
}

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

void
	Dictionary::Decode(int message_type, Stuff::MemoryStream* memory_stream, Time till)
{
	Check_Object(memory_stream);

	int version = 0;
	memory_stream->ReadBits(&version, 8);

	//SPEW(("jerryeds", "DECODE: version %d", version));


	Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connectionID,4);

	if (version != versionNumber)
		return;


	Stuff::SortedChainIteratorOf<DictionaryPage*, int> iterator(&dictionaryPages);
	
	int page_index = message_type - MWEntityManager::DictionaryPage0MessageID;

	DictionaryPage *page = iterator.Find(page_index);

	if (page == NULL)
		STOP(("Dictionary::Decode : Page in dictionary not found"));

	Check_Object(page);
	
	page->Decode(memory_stream, till, Connection::Local->GetID(), debugDictionaryLevel, dictionaryBandwidth);

	


}

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

DictionaryPage *
	Dictionary::MakeDictionaryPage(int page_number)
{
	NetVerify(page_number > -1);

	NetVerify(page_number < MaximumPages);

	DictionaryPage *page = new DictionaryPage(page_number);
	Check_Object(page);

	dictionaryPages.AddValue(page, page_number);

	return page;
}


//##########################################################################
//###########################   DictionaryManager
//##########################################################################


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DictionaryManager::DictionaryManager(int connection):
	Plug(DefaultData),
	dictionaryIndex(NULL, true)
{
	activeDictionaryIndex = -1;
	activeDictionary = NULL;
	connectionID = connection;

}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DictionaryManager::~DictionaryManager()
{
	Stuff::SortedChainIteratorOf<Dictionary*, int> iterator(&dictionaryIndex);
	Stuff::Plug *plug;
	while ((plug = iterator.GetCurrent()) != NULL)
	{
		iterator.Remove();
		Check_Object(plug);
		delete plug;
	}
}

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

Dictionary *
	DictionaryManager::MakeNewDictionary(int version_number, int debug_level, int bandwidth)
{
	
	// server keeps old copies but the client remove them

	SortedChainIteratorOf<Dictionary*, int> iterator(&dictionaryIndex);

	if (!Application::GetInstance()->serverFlag)
	{
		// clients remove all old dictionaries
		Stuff::SortedChainIteratorOf<Dictionary*, int> iterator(&dictionaryIndex);
		Stuff::Plug *plug;
		while ((plug = iterator.GetCurrent()) != NULL)
		{
			iterator.Remove();
			Check_Object(plug);
			delete plug;
			
		}
	}
	else
	{
		// we are the server, we only care about the last one and the new one...
		// remove everything but the old one and the new one...

		Stuff::SortedChainIteratorOf<Dictionary*, int> iterator(&dictionaryIndex);
		Stuff::Plug *plug;
		while ((plug = iterator.GetCurrent()) != NULL)
		{
			if (iterator.GetValue() != activeDictionaryIndex)
			{
				iterator.Remove();
				Check_Object(plug);
				delete plug;
			}
			else
			{
				iterator.Next();
			}
		}
		


	}

	activeDictionaryIndex = version_number;

	activeDictionary = new Dictionary(activeDictionaryIndex, connectionID, debug_level, bandwidth);
	Check_Object(activeDictionary);

	Dictionary* test = dictionaryIndex.Find(activeDictionaryIndex);
	if (test != NULL)
	{
		Unregister_Object(test);
		delete (test);
	}

	dictionaryIndex.AddValue(activeDictionary, activeDictionaryIndex);

	return activeDictionary;

}


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

int 
	DictionaryManager::GetNextDictionaryID()
{
	int next_dictionary = activeDictionaryIndex;

	if (next_dictionary == 254)
	{
		next_dictionary = 0;

	}
	else
	{
		++next_dictionary;
	}

	return next_dictionary;
}

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

Dictionary *
	DictionaryManager::GetCurrentDictionary()
{
	NetVerify(activeDictionaryIndex >= 0);
	Check_Object(activeDictionary);

	return activeDictionary;
}

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

Dictionary *
	DictionaryManager::GetDictionary(int version)
{
	// if it is already here we need to remove it...
	SortedChainIteratorOf<Dictionary*, int> iterator(&dictionaryIndex);

	Dictionary *dictionary = iterator.Find(version);
	return dictionary;
}

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

void
	DictionaryManager::Encode(Time till)
{

	activeDictionary->Encode(till);
	
}

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

void
	DictionaryManager::Decode(int message_type, Stuff::MemoryStream* memory_stream)
{
	
	
	NetVerify(message_type >= MWEntityManager::DictionaryPage0MessageID && message_type <= MWEntityManager::DictionaryPageMaxMessageID);

	if (activeDictionary == NULL)
		return;

	// change till to the packet latency...
	activeDictionary->Decode(message_type, memory_stream, 0.0f);

}

