// ------------------------ CSPList.h -------------------------

//*************************************************************
//*****       Copyright ©2002 - 2004 Micronovae Ltd       *****
//*****                All rights reserved                *****
//*************************************************************


#ifndef _CSPLIST
#define _CSPLIST

#include "CSPConf.h"
#include "CSPLib.h"
#include "CSPThread.h"

#pragma warning ( disable : 4251 )

//------------------ CSPList class template -----------------

template <class ListItem>
class CSPList : public CSPObject
{
	public:
		CSPList( unsigned long ulLength = 0 );
		virtual ~CSPList();
		CSPList( const CSPList& List );
		CSPList& operator = ( const CSPList& List );
		void Add( ListItem* pLI );
		ListItem* Get( unsigned long ulIndex ) const;
		ListItem* operator[]( unsigned long ulIndex ) const;
		unsigned long GetCount() const;
		unsigned long GetIndex( ListItem* pLI ) const;
		bool Replace( unsigned long ulIndex, ListItem* pLI );
		bool Remove( unsigned long index );
		void RemoveAll( bool bDelete = true );

	protected:
		ListItem** ppList;
		unsigned long ulListLength;
		unsigned long ulTop;

		void ReAllocMem(unsigned long ulNewLength);
};

//------------------ CSPLockList class template -----------------

template <class ListItem>
class CSPLockList: public CSPList<ListItem>, public CSPThreadLock
{
	public:
		CSPLockList( unsigned long ulLength = DEFAULT_LIST_LENGTH );
		CSPLockList( const CSPLockList& LockList );
		CSPLockList( const CSPList< ListItem >& List );
		virtual ~CSPLockList();

		CSPLockList& operator = ( const CSPLockList& LockList );
		CSPLockList& operator = ( const CSPList< ListItem >& List );
};


//------------------- CSPList class template implementation----------------

template<class ListItem>
CSPList<ListItem>::CSPList( unsigned long ulLength ) : ppList( 0 ), ulListLength( 0 ), ulTop( 0 )
{
	if( ulLength )ReAllocMem( ulLength );
}

template<class ListItem>
CSPList<ListItem>::CSPList( const CSPList< ListItem >& List ) : ppList( 0 ), ulListLength( 0 ), ulTop( 0 )
{
	ReAllocMem( List.ulListLength );

	for( unsigned long x = 0; x < List.ulTop; x++ )
	{
		ppList[x] = new ListItem( *List.ppList[x] );
		if( !ppList[x] ){ RemoveAll(); ThrowOutOfMemory(); }
		ulTop++;
	}
}

template<class ListItem>
CSPList<ListItem>::~CSPList()
{
	if( ppList )
	{
		for( unsigned long x = 0; x < ulTop; x++ )delete ppList[x];
		free( ppList );
	}
}

template<class ListItem>
CSPList<ListItem>& CSPList<ListItem>::operator = ( const CSPList<ListItem>& List )
{
	if( &List == this )return *this;
	RemoveAll();

	ReAllocMem( List.ulListLength );
	
	for( unsigned long x = 0; x < List.ulTop; x++ )
	{
		ppList[x] = new ListItem( *List.ppList[x] );
		if( !ppList[x] ){ RemoveAll(); ThrowOutOfMemory(); }
		ulTop++;
	}

	return *this;
}



template<class ListItem>
void CSPList<ListItem>::Add( ListItem *pLI )
{
	if( !pLI )return;

	for( unsigned long x = 0; x < ulTop; x++ )
		if( pLI == ppList[ x ] )return;
 
	if( ulTop >= ulListLength )ReAllocMem( ( ulListLength + 1 )* 2 );
		
	*( ppList + ulTop ) = pLI;
	ulTop++;
}


template<class ListItem>
void CSPList<ListItem>::ReAllocMem( unsigned long ulNewLength )
{
	if( ulNewLength == 0 ){ RemoveAll(); return; }

	if( ulNewLength < ulTop )
	{
		for( unsigned long x = ulNewLength; x < ulTop; x++ )delete ppList[ x ];
		ulTop = ulNewLength;
	}

	ListItem** pTemp = ( ListItem** )realloc( ppList, ulNewLength * sizeof( ListItem** ) );
	if( !pTemp )ThrowOutOfMemory();

	ulTop = min( ulTop, ulNewLength );
	ulListLength = ulNewLength;
	ppList = pTemp;
}


template<class ListItem>
ListItem* CSPList<ListItem>::Get( unsigned long ulIndex ) const
{
	if( ulIndex >= ulTop )return 0;

	return ppList[ ulIndex ];
}

template<class ListItem>
ListItem* CSPList<ListItem>::operator[]( unsigned long ulIndex ) const
{
	if( ulIndex >= ulTop )return 0;

	return ppList[ ulIndex ];
}


template<class ListItem>
unsigned long CSPList<ListItem>::GetCount() const
{
	return ulTop;
}


template<class ListItem>
unsigned long CSPList<ListItem>::GetIndex(ListItem* pLI) const
{
	if( !pLI )return 0xFFFFFFFFUL;

	for( unsigned long x = 0; x < ulTop; x++ )
		if( *ppList[x] == *pLI ) return x;

	return 0xFFFFFFFFUL;
}


template<class ListItem>
bool CSPList<ListItem>::Replace( unsigned long ulIndex, ListItem* pLI )
{
	if( ulIndex == 0xFFFFFFFFUL || ulIndex >= ulTop || !pLI )return false;

	for( unsigned long x = 0; x < ulTop; x++ )
		if( pLI == ppList[ x ] )return false;

	//if(ppList[ulIndex])delete ppList[ulIndex];
	ppList[ ulIndex ] = pLI;

	return false;
}


template<class ListItem>
bool CSPList<ListItem>::Remove(unsigned long index)
{
	if( index >= ulTop )return false;

	delete ppList[ index ];
	ulTop--;
	ppList[ index ] = ppList[ ulTop ];
	ppList[ ulTop ] = 0;

	if( ulTop < ulListLength / 4  &&  !ReAllocMem( ulListLength / 2 ) )return false;

	return true;
}


template<class ListItem>
void CSPList<ListItem>::RemoveAll( bool bDelete )
{
	if( bDelete )for( unsigned long x = 0; x < ulTop; x++ )delete ppList[ x ];
	ulTop = 0;

	free( ppList );
	ppList = 0;
	ulListLength = 0;
}



//------------------- CSPLockList class template implementation----------------


template<class ListItem>
CSPLockList<ListItem>::CSPLockList(unsigned long ulLength) : CSPList<ListItem>( ulLength ), CSPThreadLock()
{ 
}

template<class ListItem>
CSPLockList<ListItem>::CSPLockList( const CSPLockList<ListItem>& LockList) : CSPList<ListItem>( LockList ), CSPThreadLock()
{
}

template<class ListItem>
CSPLockList<ListItem>::CSPLockList( const CSPList<ListItem>& List) : CSPList<ListItem>( List ), CSPThreadLock()
{
}

template<class ListItem>
CSPLockList<ListItem>::~CSPLockList()
{
}



template<class ListItem>
CSPLockList<ListItem>& CSPLockList<ListItem>::operator = ( const CSPLockList<ListItem>& LockList )
{
	CSPList<ListItem>::operator = ( LockList );
	return *this;
}

template<class ListItem>
CSPLockList<ListItem>& CSPLockList<ListItem>::operator = ( const CSPList<ListItem>& List )
{
	CSPList<ListItem>::operator = ( List );
	return *this;
}

#endif
