//////////////////////////////////////////////////////////////////////////////////
// $Source: /cvsroot/cdx/cdx3.0/addons/CDXLIST/CDXLIST.H,v $
// $Author: mindcry $
//
// $Log: CDXLIST.H,v $
// Revision 1.2  2000/07/31 15:47:56  mindcry
// Memory leak removed and some other small improvements
//
// Revision 1.1.1.1  2000/04/22 16:50:35  hebertjo
// Initial checkin of v3.0 to SourceForge CVS.
//
// Revision 1.4  1999/10/27 12:47:15  Mindcry
// added the Insert function
//
// Revision 1.3  1999/10/23 09:13:22  Mindcry
// - Load/Save added
// - Many other new functions added
// - Some Variable Names changed so they have now the Same style
// - And misc other changes
//
// Revision 1.2  1999/08/14 16:01:16  Mindcry
// sorry, there was a bug in it so it wont compile ;( now fixed
//
// Revision 1.1  1999/08/02 15:25:29  Mindcry
// Initial release, will post some examples later
//
//
// Notes on usage:
// You have to provide a Next and a Last pointer of the class or stuct you use.
// e.G.  struct sSample
//       { int x, y;
//         sSample *Next, *Last;
//       };
//       CDXList<sSample> LinkedList;
//
// $Revision: 1.2 $
//////////////////////////////////////////////////////////////////////////////////
#ifndef CDXLIST_H
#define CDXLIST_H

//////////////////////////////////////////////////////////////////////////////////
// The whole CDXList template
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
class CDXList
{	
public:
	CDXList();
	~CDXList();
	void Clear( void );
	void Add( TYPE *newElement , bool Last=true);
	void Insert( TYPE *newElement, int pos );
	TYPE *Get( int Pos );
	inline TYPE *GetFirst( void );
	TYPE *Next( TYPE *&Search );
	TYPE *Delete( TYPE *&search );
	TYPE *Delete( int Pos);
	void InitList( void );
	
	int m_Count;
private:
	TYPE *m_First, *m_Last;
	TYPE **m_PtrList;
};

//////////////////////////////////////////////////////////////////////////////////
// Constuctor
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
CDXList<TYPE>::CDXList()
{
	m_Last=m_First=NULL;
	m_Count=0;
	m_PtrList=NULL;
}

//////////////////////////////////////////////////////////////////////////////////
// Destructor
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
CDXList<TYPE>::~CDXList()
{
	Clear( );
	DELETEARRAY( m_PtrList );
}

//////////////////////////////////////////////////////////////////////////////////
// Add a new Element to list
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
void CDXList<TYPE>::Add( TYPE *newElement , bool Last)
{	
	if( !newElement) return; //Cannot add a NULL to the list.
	if( !m_First )
	{	
		newElement->Next = NULL;
		newElement->Last = NULL;
		m_Last=newElement;
		m_First=newElement;
	}
	else
	{
		if (Last)
		{
			newElement->Next = NULL;	
			newElement->Last = m_Last;
			m_Last->Next = newElement;
			m_Last=newElement;
		} else
		{
			newElement->Next = m_First;
			newElement->Last = NULL;
			m_First->Last = newElement;
			m_First = newElement;
		}
	}
	
	m_Count++;
	DELETEARRAY( m_PtrList );
}

////////////////////////////////////////////////////////////////////////////////
//
// Insert a new element into the List
////////////////////////////////////////////////////////////////////////////////
//
template<class TYPE>
void CDXList<TYPE>::Insert( TYPE *newElement, int pos )
{
	if( !newElement) return; //Cannot add a NULL to the list.
	if( pos<0 ) pos=0;
	if( pos>=m_Count )
	{
		Add( newElement );
	}
	else
	{
		TYPE *Search = Get( pos );
		
		if( Search->Last )
			Search->Last->Next = newElement;
		else
			m_First = newElement;
		
		newElement->Next = Search;
		newElement->Last = Search->Last;
		Search->Last = newElement;
		m_Count++;
		DELETEARRAY( m_PtrList );
	}
}


//////////////////////////////////////////////////////////////////////////////////
// Clears the List
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
void CDXList<TYPE>::Clear( )
{
	if( m_First )
	{
		TYPE *Search = m_First;
		do
		{
			if( Search->Last ) delete Search->Last;
		}	while( (Search = Search->Next) != NULL );
		
		delete m_Last;

		m_First = m_Last = NULL;
		m_Count=0;
		DELETEARRAY( m_PtrList );
	}
}

//////////////////////////////////////////////////////////////////////////////////
// gets the Next element from Search
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
TYPE *CDXList<TYPE>::Next( TYPE *&Search )
{
	TYPE *tmp = m_First;
	if( Search ) tmp=Search->Next;
	
	Search=tmp;
	return tmp;
}

//////////////////////////////////////////////////////////////////////////////////
// Get's first element
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
inline TYPE *CDXList<TYPE>::GetFirst( )
{	return m_First;	}

//////////////////////////////////////////////////////////////////////////////////
// Gets the element at position Pos
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
TYPE *CDXList<TYPE>::Get( int Pos )
{
	TYPE *tmp = m_First;
	
	if( tmp )
	{
		if( m_PtrList )
		{
			return m_PtrList[Pos];
		}
		else
		{
			if (Pos==0) return m_First;
			if (Pos==m_Count-1) return m_Last;
			for( int i=0; i<Pos && tmp; i++ ) tmp = tmp->Next;
			return tmp;
		}
		
	}
	return NULL;
}

//////////////////////////////////////////////////////////////////////////////////
// Deletes the given Element, and returns the pointer to the one before it
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
TYPE *CDXList<TYPE>::Delete( TYPE *&Search )
{
	TYPE *tmp;
	if (!Search) return NULL; //need to be handled.
	
	if( Search->Last )
		Search->Last->Next = Search->Next;
	else 
		m_First = Search->Next;
	
	if( Search->Next )
		Search->Next->Last = Search->Last;
	else
		m_Last=Search->Last;
	
	tmp = Search->Last;
	
	delete Search;
	m_Count--;
	DELETEARRAY( m_PtrList );
	
	Search=tmp;
	return tmp;
}

//////////////////////////////////////////////////////////////////////////////////
// Deletes the given Element, and returns the pointer to the one before it
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
TYPE *CDXList<TYPE>::Delete( int Pos )
{
	TYPE* T = Get(Pos);
	T = Delete(T);
	return T;
}


//////////////////////////////////////////////////////////////////////////////////
// Inits a table for faster Get, but it will be released if you use, Add/Delete
//////////////////////////////////////////////////////////////////////////////////
template<class TYPE>
void CDXList<TYPE>::InitList( void )
{	
	DELETEARRAY( m_PtrList );
	
	m_PtrList = new TYPE*[m_Count];
	
	if( m_First )
	{
		TYPE *Search = m_First;
		int i=0;
		do
		{
			m_PtrList[i] = Search;
			i++;
		}	while( (Search = Search->Next) != NULL );
	}
}
#endif CDXLIST_H