//------------------------ CSPPool.h --------------------------

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


#ifndef _CSPPOOL
#define _CSPPOOL

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

template<class T>
class CSPPool : public CSPObject
{
	public:
	
	class ObjectPtr : public CSPPtr<T>
	{
		public:
			ObjectPtr(): pPool(0){}
			virtual ~ObjectPtr(){ Release(); }
			ObjectPtr( CSPPool<T>& Pool ) : CSPPtr<T>( Pool.GetObjPtr() ), pPool( &Pool ){}

			void Attach( CSPPool<T>& Pool )
			{
				Release();
				pPool = &Pool;
				m_p = Pool.GetObjPtr();
			}

			void Release()
			{
				if( pPool && m_p ) pPool->Release( m_p );
				else delete m_p;
				m_p = 0;
				pPool = 0;
			}

			ObjectPtr& operator = ( CSPPool<T>& Pool )
			{
				Attach( Pool );
				return *this;
			}

		protected:
			CSPPool<T>* pPool;

		private:
			ObjectPtr( ObjectPtr& );
			ObjectPtr& operator = ( ObjectPtr& );
	};

	friend class ObjectPtr;

	public:
		CSPPool();
		virtual ~CSPPool();
		void AddNew( unsigned long ulCount = 1 );
		void Add( const T& Object, unsigned long ulCount = 1 );
		void Add( T* pObject );
		unsigned long GetCount() const { return ObjectStack.GetCount(); }
		void Get( ObjectPtr& spObject );

	protected:
		CSPLockStack<T> ObjectStack;
		HANDLE hLock;
		CSPThreadLock CS;

		T* GetObjPtr();
		void Release( T* pObject );
};

//--------------- Member function definitions for CSPPool class ------------------
template<class T>
CSPPool<T>::CSPPool()
{
	hLock = CreateEvent( NULL, TRUE, TRUE, NULL );
}

template<class T>
CSPPool<T>::~CSPPool()
{
	CloseHandle( hLock );
}

template<class T>
void CSPPool<T>::Add( const T& Object, unsigned long ulCopies )
{
	CSPThreadLockHandler CSH( ObjectStack );
	CSH.Lock();

	for( unsigned long x = 0; x < ulCopies; x++ )
	{
		CSPPtr<T> spObjectCopy( new T( Object ) );
		if( !spObjectCopy )ThrowOutOfMemory();
		ObjectStack.Push( spObjectCopy );
		spObjectCopy.Detach();
	}

	SetEvent( hLock );

	CSH.Unlock();
}

template<class T>
void CSPPool<T>::AddNew( unsigned long ulQuantity )
{
	CSPThreadLockHandler CSH( ObjectStack );
	CSH.Lock();

	for( unsigned long x = 0; x < ulQuantity; x++ )
	{
		CSPPtr<T> spObject( new T );
		if( !spObject )ThrowOutOfMemory();
		ObjectStack.Push( spObject );
		spObject.Detach();
	}

	SetEvent( hLock );

	CSH.Unlock();
}

template<class T>
void CSPPool<T>::Add( T* pObject )
{
	if( !pObject )return;

	CSPThreadLockHandler TLH( ObjectStack );
	TLH.Lock();

	ObjectStack.Push( pObject );
	SetEvent( hLock );

	TLH.Unlock();
}

template<class T>
T* CSPPool<T>::GetObjPtr()
{
	CSPThreadLockHandler TLHMain( CS );
	TLHMain.Lock();

	if( ObjectStack.GetCount() == 0 )WaitForSingleObject( hLock, INFINITE );

	CSPThreadLockHandler TLH( ObjectStack );
	TLH.Lock();

	T* pObject = ObjectStack.Pop();
	if( ObjectStack.GetCount() == 0 )ResetEvent( hLock );
	TLH.Unlock();

	TLHMain.Unlock();

	return pObject;
}

template<class T>
void CSPPool<T>::Release(T* pObject)
{
	CSPThreadLockHandler TLH( ObjectStack );
	TLH.Lock();

	ObjectStack.Push( pObject );
	if( ObjectStack.GetCount() != 0 )SetEvent( hLock );

	TLH.Unlock();
}

template<class T>
void CSPPool<T>::Get( ObjectPtr& spObject )
{
	spObject.Attach( *this );
}

#endif
