//------------------------ CSPStack.h -------------------------

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


#ifndef _CSPSTACK
#define _CSPSTACK

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

#pragma warning ( disable : 4251 )

#define DEFAULT_STACK_SIZE 50

//------------------ CSPStack class template -----------------

template <class StackItem>
class CSPStack : public CSPObject
{
	public:
		CSPStack( unsigned long ulSize = DEFAULT_STACK_SIZE );
		virtual ~CSPStack();
		CSPStack( const CSPStack& Stack );
		CSPStack& operator = ( const CSPStack& Stack );
		void Push( StackItem* pSI );
		StackItem* Pop();
		unsigned long GetCount() const;
		void RemoveAll( bool bDelete = true );

	protected:
		StackItem** ppStack;
		unsigned long ulStackSize;
		unsigned long ulTop;
		StackItem** ppTop;

		void ReAllocMem( unsigned long ulNewSize );
};

//------------------ CSPLockStack class template -----------------

template <class StackItem>
class CSPLockStack: public CSPStack<StackItem>, public CSPThreadLock
{
	public:
		CSPLockStack( unsigned long ulSize = DEFAULT_STACK_SIZE );
		CSPLockStack( const CSPLockStack& LockStack );
		CSPLockStack( const CSPStack<StackItem>& Stack );
		virtual ~CSPLockStack();

		CSPLockStack& operator = ( const CSPLockStack& LockStack );
		CSPLockStack& operator = ( const CSPStack<StackItem>& Stack );
};


//------------------- CSPStack class template implementation----------------

template<class StackItem>
CSPStack<StackItem>::CSPStack( unsigned long ulSize ) : ppStack( 0 ), ulStackSize( 0 ), ulTop( 0 )
{
	ReAllocMem( ulSize );
}

template<class StackItem>
CSPStack<StackItem>::CSPStack( const CSPStack<StackItem>& Stack ) : ppStack( 0 ), ulStackSize( 0 ), ulTop( 0 )
{
	ReAllocMem( Stack.ulStackSize );
	
	for( unsigned long x = 0; x < Stack.ulTop; x++ )
	{
		ppStack[ x ] = new StackItem( *Stack.ppStack[ x ] );
		if( !ppStack[ x ] ){ RemoveAll(); ThrowOutOfMemory(); }
		ulTop++;
	}
}

template<class StackItem>
CSPStack<StackItem>::~CSPStack()
{
	RemoveAll();
	free( ppStack );
}

template<class StackItem>
CSPStack<StackItem>& CSPStack<StackItem>::operator = ( const CSPStack<StackItem>& Stack )
{
	if( ppStack )RemoveAll();

	ReAllocMem( Stack.ulStackSize );
	
	for( unsigned long x = 0; x < Stack.ulTop; x++ )
	{
		ppStack[ x ] = new StackItem( *Stack.ppStack[ x ] );
		if( !ppStack[ x ] ){ RemoveAll(); ThrowOutOfMemory(); }
		ulTop++;
	}

	return *this;
}


template<class StackItem>
void CSPStack<StackItem>::Push( StackItem* pSI )
{
	if( !pSI )return;

	if( ulTop >= ulStackSize - 1 )ReAllocMem( ulStackSize * 2 );
	if( ulTop < ulStackSize/4  &&  ulStackSize > DEFAULT_STACK_SIZE )ReAllocMem( ulStackSize / 2 );
	
	*( ppStack + ulTop ) = pSI;
	ulTop++;
}


template<class StackItem>
void CSPStack<StackItem>::ReAllocMem( unsigned long ulNewSize )
{
	StackItem** pTemp = ( StackItem** )realloc( ppStack, ulNewSize * sizeof( StackItem** ) );
	if( !pTemp )ThrowOutOfMemory();

	ppStack = pTemp;
	ulTop = min( ulTop, ulNewSize );
	ulStackSize = ulNewSize;
}


template<class StackItem>
StackItem* CSPStack<StackItem>::Pop()
{
	if( ulTop == 0 )return 0;
	return ppStack[ ulTop-- - 1 ];
}


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

template<class StackItem>
void CSPStack<StackItem>::RemoveAll( bool bDelete )
{
	if( bDelete )for( unsigned long x = 0; x < ulTop; x++ )delete ppStack[ x ];
	ulTop = 0;
}

//------------------- CSPLockStack class template implementation----------------

template<class StackItem>
CSPLockStack<StackItem>::CSPLockStack(unsigned long ulSize) : CSPStack<StackItem>( ulSize ), CSPThreadLock()
{ 
}

template<class StackItem>
CSPLockStack<StackItem>::CSPLockStack( const CSPLockStack<StackItem>& LockStack) : CSPStack<StackItem>( LockStack ), CSPThreadLock()
{
}

template<class StackItem>
CSPLockStack<StackItem>::CSPLockStack( const CSPStack<StackItem>& Stack) : CSPStack<StackItem>( Stack ), CSPThreadLock()
{
}


template<class StackItem>
CSPLockStack<StackItem>::~CSPLockStack()
{
}

template<class StackItem>
CSPLockStack<StackItem>& CSPLockStack<StackItem>::operator = ( const CSPLockStack<StackItem>& LockStack )
{
	CSPStack<StackItem>::operator = ( LockStack );
	return *this;
}

template<class StackItem>
CSPLockStack<StackItem>& CSPLockStack<StackItem>::operator = ( const CSPStack<StackItem>& Stack )
{
	CSPStack<StackItem>::operator = ( Stack );
	return *this;
}

#endif
