// Copyright DOVICO Software (C)2008
function CLinkedList()
{
	this.m_ptrHead = new CLinkedListItem();
	this.m_ptrHead.m_ptrPrevious = null;
	this.m_ptrHead.m_ptrNext = null;
	this.m_ptrHead.m_ptrValue = null;
	
	this.m_ptrTail = new CLinkedListItem();
	this.m_ptrTail.m_ptrPrevious = this.m_ptrHead;
	this.m_ptrTail.m_ptrNext = null;
	this.m_ptrTail.m_ptrValue = null;
	
	this.m_ptrHead.m_ptrNext = this.m_ptrTail;

	
	this.AddItem = function AddItem(objItem)
	{
		var lliNewItem = new CLinkedListItem();
		
		
		if (this.m_ptrHead.m_ptrNext == this.m_ptrTail)
		{
			
			
			this.m_ptrHead.m_ptrNext = lliNewItem;
			lliNewItem.m_ptrPrevious = this.m_ptrHead;
		}
		
		else
		{
			
			
			lliNewItem.m_ptrPrevious = this.m_ptrTail.m_ptrPrevious;
			lliNewItem.m_ptrPrevious.m_ptrNext = lliNewItem;
		}
		
		
		lliNewItem.m_ptrValue = objItem;
		
		
		lliNewItem.m_ptrNext = this.m_ptrTail;
		this.m_ptrTail.m_ptrPrevious = lliNewItem;
		
		return lliNewItem;
	}
	
	
	this.InsertAfter = function InsertAfter(ptrValue, objItem)
	{
		
		var lliInsertAfter = this.GetLinkedListItemForObject(ptrValue);
		if (lliInsertAfter == null) {this.AddItem(objItem);}
		
		
		var lliNewItem = new CLinkedListItem();
		
		
		
		lliInsertAfter.m_ptrNext.m_ptrPrevious = lliNewItem;
		lliNewItem.m_ptrNext = lliInsertAfter.m_ptrNext;
		
		
		
		lliNewItem.m_ptrPrevious = lliInsertAfter;
		lliInsertAfter.m_ptrNext = lliNewItem;
		
		
		lliNewItem.m_ptrValue = objItem;
		
		return lliNewItem;
	}
	
	this.InsertBefore = function InsertBefore(ptrValue, objItem)
	{
		
		var lliInsertBefore = this.GetLinkedListItemForObject(ptrValue);
		if (lliInsertBefore == null) {this.AddItem(objItem);}
		
		
		return this.InsertAfter(lliInsertBefore.m_ptrPrevious.Value, objItem);
	}
	
	this.InsertAt = function InsertAt(iIndex, objItem)
	{
		
		var lliInsertPos = null;
		
		if (!this.ListHasItems())
		{
			lliInsertPos = this.m_ptrTail;	
		}
		else
		{
			lliInsertPos = this.GetLinkedListItemAt(iIndex);
		}
		
		
		this.InsertAfter(lliInsertPos.m_ptrPrevious, objItem);
	}
	
	
	this.ListHasItems = function ListHasItems()
	{
		return this.m_ptrHead.m_ptrNext != this.m_ptrTail;
	}
	
	
	this.GetFirst = function GetFirst()
	{	
		
		var lleEnum = new CLinkedListEnum();
		lleEnum.m_posCurrent = this.m_ptrHead;
		
		return lleEnum;
	}
	
	
	
	this.GetNext = function GetNext(lleEnum)
	{
		
		var ptrNext = lleEnum.m_posCurrent.m_ptrNext;
		
		
		if (ptrNext == this.m_ptrTail) {return null;}
		
		lleEnum.m_posCurrent = ptrNext;
		
		
		return ptrNext.m_ptrValue;
	}
	
	
	this.GetLast = function GetLast()
	{
		var lleEnum = new CLinkedListEnum();
		lleEnum.m_posCurrent = this.m_ptrTail;
		
		return lleEnum;
	}
	
	
	this.GetPrevious = function GetPrevious(lleEnum)
	{
		var ptrPrev = lleEnum.m_posCurrent.m_ptrPrevious;
		
		
		if (ptrPrev == this.m_ptrHead) {return null;}
		
		lleEnum.m_posCurrent = ptrPrev;
		
		return ptrPrev.m_ptrValue;
	}
	
	this.GetLastObject = function GetLastItem()
	{
		return this.GetLast().m_posCurrent.m_ptrPrevious.m_ptrValue;
	}
	
	this.GetPreviousObjectForObject = function GetPreviousObjectForObject(ptrValue)
	{
		return this.GetLinkedListItemForObject(ptrValue).m_ptrPrevious.m_ptrValue;
	}
	
	this.GetNextObjectForObject = function GetNextObjectForObject(ptrValue)
	{
		return this.GetLinkedListItemForObject(ptrValue).m_ptrNext.m_ptrValue;
	}
	
	
	this.GetLinkedListItemAt = function GetLinkedListItemAt(iIndex)
	{
		
		if (this.ListHasItems() == false) {return null;}
		
		
		var iListIndex = 0;
		var ptrEnum = this.m_ptrHead.m_ptrNext;
		
		
		while (ptrEnum != null)
		{
			
			if (iIndex == iListIndex)
			{
				return ptrEnum;
			}
			
			
			iListIndex ++;
			ptrEnum = ptrEnum.m_ptrNext;
		}
		
		return null;		
	}
	
	this.GetObjectAt = function GetObjectAt(iIndex)
	{
		var llItem = this.GetLinkedListItemAt(iIndex);
		
		if (llItem != null)
		{
			return llItem.m_ptrValue;
		}
		
		return null;
	}
	
	
	this.GetLinkedListItemForObject = function GetLinkedListItemForObject(objItem)
	{
		var ptrEnum = this.m_ptrHead.m_ptrNext;
		
		
		while (ptrEnum != null)
		{
			
			if (ptrEnum.m_ptrValue == objItem)
			{
				return ptrEnum;
			}
			
			
			ptrEnum = ptrEnum.m_ptrNext;
		}
		
		return null;
	}
	
	
	this.GetValueAt = function GetValueAt(iIndex)
	{
		return this.GetLinkedListItemAt(iIndex).m_ptrValue;
	}
	
	
	this.Remove = function Remove(lliItem)
	{
		
		if (this.ListHasItems() == false) {return;}
		
		var ptrEnum = this.m_ptrHead.m_ptrNext;
		
		
		while (ptrEnum != null)
		{
			
			if (ptrEnum == lliItem)
			{
				
				ptrEnum.m_ptrPrevious.m_ptrNext = ptrEnum.m_ptrNext;
				ptrEnum.m_ptrNext.m_ptrPrevious = ptrEnum.m_ptrPrevious;
				ptrEnum = null;
				
				return;
			}
			
			
			ptrEnum = ptrEnum.m_ptrNext;
		}	
	}
	
	
	this.RemoveAt = function RemoveAt(iIndex)
	{
		var lliItem = this.GetLinkedListItemAt(iIndex);
		if (lliItem != null) {this.Remove(lliItem);}
	}
	
	this.RemoveObject = function RemoveObject(ptrValue)
	{
		var llItemToRemove = this.GetLinkedListItemForObject(ptrValue);
		
		if (llItemToRemove != null)
		{
			this.Remove(llItemToRemove);
		}
	}
	
	
	this.RemoveAll = function RemoveAll()
	{
		var ptrCurrent = this.m_ptrHead.m_ptrNext;
		
		while (ptrCurrent != this.m_ptrTail)
		{
			
			ptrCurrent.m_ptrValue = null;
			
			
			ptrCurrent.m_ptrPrevious = null;
			
			
			var ptrNextItem = ptrCurrent.m_ptrNext;
			ptrCurrent.m_ptrNext = null;
			
			
			ptrCurrent = ptrNextItem;
		}
		
		
		this.m_ptrHead.m_ptrNext = this.m_ptrTail;
		this.m_ptrTail.m_ptrPrevious = this.m_ptrHead;
	}
	
	
	this.FreeMemory = function FreeMemory()
	{
		this.RemoveAll();
	}
	
	
	this.GetLength = function GetLength()
	{
		var ptrEnum = this.m_ptrHead.m_ptrNext.m_ptrNext;
		var iCount = 0;
		
		while (ptrEnum != null)
		{
			iCount ++;
			ptrEnum = ptrEnum.m_ptrNext;
		}
		
		return iCount;
	}
}


function CLinkedListEnum()
{
	this.m_posCurrent = null;
}


function CLinkedListItem()
{
	this.m_ptrPrevious = null;
	this.m_ptrNext = null;
	this.m_ptrValue = null;
}


function CDictionary()
{
	this.m_llItems = new CLinkedList();
	
	
	this.AddItem = function AddItem(sKey, objItem)
	{
		this.m_llItems.AddItem(new CDictionaryItem(sKey, objItem));
	}
	
	
	this.RemoveItem = function RemoveItem(sKey)
	{
		this.m_llItems.Remove(this.m_llItems.GetLinkedListItemForObject(this.GetDictionaryItem(sKey)));
	}
	
	
	this.Lookup = function Lookup(sKey)
	{
		
		var diItem = this.GetDictionaryItem(sKey);
		if (diItem != null) {return diItem.m_ptrValue;}
		
		
		return null;
	}
	
	
	this.GetDictionaryItem = function GetDictionaryItem(sKey)
	{
		
		var ptrEnum = this.m_llItems.GetFirst();
		var diItem;
		
		
		while ((diItem = this.m_llItems.GetNext(ptrEnum)) != null)
		{
			
			if (diItem.m_sKey == sKey)
			{
				return diItem;
			}
		}
		
		return null;  
	}
	
	
	this.RemoveAll = function RemoveAll()
	{
		this.m_llItems.RemoveAll();
	}
	
	
	this.FreeMemory = function FreeMemory()
	{
		this.RemoveAll();
	}
}


function CDictionaryItem(sKey, objItem)
{
	this.m_sKey = sKey;
	this.m_ptrValue = objItem;
}

