// ------------------------------------------------------------------
//	File: gtlist.h
//
//
// ==================================================================
// IF YOU DO NOT AGREE WITH THE FOLLOWING STATEMENT, YOU MUST 
// PROMPTLY RETURN THE SOFTWARE AND ANY ACCOMPANYING DOCUMENTATION 
// ("PRODUCT") TO PCBest Networks(www.pcbest.net).
//
// PCBest Networks owns all title and 
// ownership rights to Software.  "Software" means any data processing
// programs (hereinafter "programs") consisting of a series of 
// instructions or statements in object code form, including any 
// systemized collection of data in the form of a data base, and any
// related proprietary materials such as flow charts, logic diagrams, 
// manuals media and listings provided for use with the programs.
// User has no right, express or implied, to transfer, sell, provide
// access to or dispose of Software to any third party without PCBest Networks'
// prior written consent.  User will not copy, reverse assemble,
// reverse engineer, decompile, modify, alter, translate or display
// the Software other than as expressly permitted by PCBest Networks in writing.
// ------------------------------------------------------------------



#if !defined(__GTAPI_LIST_HEADER_FILE_H)
#define __GTAPI_LIST_HEADER_FILE_H

#include "GTBase.h"

typedef void* Pointer;
#define DEFAULT_CAPACITY 1024
#define DEFAULT_MAX_DATA_BUFFER_SIZE (1024*1024*200) //100MB

#ifdef USE_GTAPI_NAMESPACE
namespace GTAPI
{
#endif

// ------------------------------------------------------------------
// CLASS: CPtArray  // A thread safe pointer array
// ------------------------------------------------------------------

	class GT_DLL_API CPtArray
	{
	public:
		CPtArray(bool bUseMutex = true);
		CPtArray(int capacity, bool bUseMutex = true);
		virtual ~CPtArray();

		int   size()     { return m_Size; }
		int   capacity() { return m_Capacity; }
		bool  isEmpty()  { return m_Size == 0; }

		bool  indexOf(void *element, int *index);

		// Array processing functions
		void *get(int index);
		void *set(int index, void *element);

		int   add(void *element);
		int   insert(void *element, int index);
		void  *remove(int index);
		bool  remove(void *element);
		void  removeall(){clear();}

		Pointer operator[](int nIndex);

		bool BeginAccess();
		bool EndAccess();
		CMutex*   GetAccessMutex(){return m_mtxData;}

	private:
		void clear() { m_Size = 0; }
		bool grow(int size); // initializes new entries
		bool verifyCapacity(int size); // increases array size if needed

		Pointer *m_Data;
		int  m_Size;
		int  m_Capacity;
		CMutex*   m_mtxData;

		unsigned int		m_uiMaxDataBufSize;
	}; // class CPtArray
	

#ifdef USE_GTAPI_NAMESPACE
}
#endif



///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

template <class T> class TCQueue
{
public:
	TCQueue(bool bUseMutex = true);
	TCQueue(unsigned int capacity, bool bNotify, bool bUseMutex = true);
	virtual ~TCQueue();

public:
	bool Lock(DWORD timeout=INFINITE);
	bool Unlock();

	bool WaitForNotify(DWORD dwMilliseconds=INFINITE);
	bool Notify();

	bool grow(unsigned int gsize);

public:
	int   size(){ return m_Size; }
	int   Size(){return m_Size;}

	int   capacity() { return m_Capacity; }
	int   Capacity() { return m_Capacity; }

	bool  isEmpty()  { return m_Size == 0; }
	bool  Empty()    {return m_Size == 0;}

	void clear(){Lock(); m_Size = 0;m_uiAddIndex = 0;m_uiRemoveIndex = 0; Unlock();}
	void Clear(){clear();}

	bool Push_Back(T* p, DWORD dwMilliseconds = INFINITE);
	bool Pop_Front(T* p=NULL, DWORD dwMilliseconds = INFINITE);

	int Push_BackEx(T* p, int len, DWORD dwMilliseconds = INFINITE);
	int Pop_FrontEx(T* p, int len, DWORD dwMilliseconds = INFINITE);

	T* Front();
	T* Back();

	T* operator[](int nIndex);

	bool GetData(T* x, DWORD dwMilliseconds = INFINITE);
	bool PutData(T* x, DWORD dwMilliseconds=INFINITE);

	int GetDataEx(T* x, int len, DWORD dwMilliseconds = INFINITE);
	int PutDataEx(T* x, int len, DWORD dwMilliseconds = INFINITE);

private:
	HANDLE				m_hSignal;
	bool				m_bNotify;
    HANDLE				m_hLock;

	T*					m_Data;
	unsigned int		m_Size;
	unsigned int		m_Capacity;
	unsigned int		m_uiAddIndex;
	unsigned int		m_uiRemoveIndex;

	unsigned int		m_uiMaxDataBufSize;
};

template <class T> 
TCQueue<T>::TCQueue<T>(bool bUseMutex)
{   
	m_hSignal = 0;

	if(bUseMutex)
		m_hLock = CreateMutex(NULL,FALSE,NULL);
	else
		m_hLock = 0;
	m_Capacity = DEFAULT_CAPACITY;
	m_Data = new T[m_Capacity];
	m_bNotify = false;
	m_Size = 0;
	m_uiAddIndex = 0;
	m_uiRemoveIndex = 0;
	m_uiMaxDataBufSize = DEFAULT_MAX_DATA_BUFFER_SIZE;
}

template <class T> 
TCQueue<T>::TCQueue<T>(unsigned int capacity, bool bNotify, bool bUseMutex)
{
	if(bNotify)
		m_hSignal = CreateSemaphore(NULL,0,MAX_SEM_VALUE,NULL);
	else
		m_hSignal = 0;

	if(bUseMutex)
		m_hLock = CreateMutex(NULL,FALSE,NULL);
	else
		m_hLock = 0;
	m_Capacity = capacity;
	m_Data = new T[m_Capacity];
	m_bNotify = bNotify;
	m_Size = 0;
	m_uiAddIndex = 0;
	m_uiRemoveIndex = 0;
	m_uiMaxDataBufSize = DEFAULT_MAX_DATA_BUFFER_SIZE;
}

template <class T> 
TCQueue<T>::~TCQueue<T>()
{
	if(m_hLock)
		CloseHandle(m_hLock); 

	if(m_hSignal)
		CloseHandle(m_hSignal); 

	if(m_Data)
	{
		delete []m_Data;
		m_Data = NULL;
	}
}

template <class T> 
bool TCQueue<T>::Lock(DWORD timeout)
{
	if(m_hLock)
		return (WaitForSingleObject(m_hLock,timeout) == WAIT_OBJECT_0);
	else
		return true;
}

template <class T> 
bool TCQueue<T>::Unlock()
{
	if(m_hLock)
	{
		if(ReleaseMutex(m_hLock))
			return true;
		else
			return false;
	}
	else
		return true;
}

template <class T> 
T* TCQueue<T>::Front()
{
	T* ret = NULL;
	Lock();
	if(m_Size>0)
	{
		ret = &m_Data[m_uiRemoveIndex];
	}
	Unlock();
	return ret;
}

template <class T> 
T* TCQueue<T>::Back()
{
	T* ret = NULL;
	Lock();
	if(m_Size>0)
	{
		if(m_uiAddIndex == 0)
			ret = &m_Data[m_Capacity-1];
		else
			ret = &m_Data[m_uiAddIndex-1];
	}
	Unlock();
	return ret;
}

template <class T>
int TCQueue<T>::Push_BackEx(T* p, int len, DWORD dwMilliseconds)
{
	int cnt = 0;

	if(Lock(dwMilliseconds))
	{
		for(int i=0; i<len; i++)
		{
			if (m_Size >= m_Capacity)
			{
				if(!grow(m_Capacity*2))
				{
					Unlock();
					return cnt;
				}
			}

			m_Size ++;
			memcpy(&m_Data[m_uiAddIndex], &p[i], sizeof(T));
			m_uiAddIndex++;
			m_uiAddIndex = m_uiAddIndex % m_Capacity;

			cnt++;
		}

		Unlock();
	}
	
	return cnt;
}

template <class T>
int TCQueue<T>::Pop_FrontEx(T* p, int len, DWORD dwMilliseconds)
{
	int cnt = 0;

	if(Lock(dwMilliseconds))
	{
		for(int i=0; i<len; i++)
		{
			if(m_Size>0)
			{
				if(p)
					memcpy(&p[cnt], &m_Data[m_uiRemoveIndex], sizeof(T));

				m_Size--;
				m_uiRemoveIndex++;
				m_uiRemoveIndex = m_uiRemoveIndex % m_Capacity;

				cnt++;
			}
			else
				break;
		}

		Unlock();
	}

	return cnt;
}

template <class T> 
bool TCQueue<T>::Push_Back(T* p, DWORD dwMilliseconds)
{
	if(!p)
		return false;

	if(Lock(dwMilliseconds))
	{
		if (m_Size >= m_Capacity)
		{
			if(!grow(m_Capacity*2))
			{
				Unlock();
				return false;
			}
		}
		m_Size ++;
		memcpy(&m_Data[m_uiAddIndex], p, sizeof(T));
		m_uiAddIndex++;
		m_uiAddIndex = m_uiAddIndex % m_Capacity;
		Unlock();
		return true;
	}
	
	return false;
}

template <class T> 
bool TCQueue<T>::Pop_Front(T* p, DWORD dwMilliseconds)
{
	bool ret = false;

	if(Lock(dwMilliseconds))
	{
		if(m_Size>0)
		{
			if(p)
				memcpy(p, &m_Data[m_uiRemoveIndex], sizeof(T));

			m_Size--;
			m_uiRemoveIndex++;
			m_uiRemoveIndex = m_uiRemoveIndex % m_Capacity;

			ret = true;
		}

		Unlock();
	}

	return ret;
}

template <class T> 
bool TCQueue<T>::grow(unsigned int gsize)
{
	T* oldData = m_Data;
	unsigned int m_oldCapacity = m_Capacity;

	while (gsize > m_Capacity)
		m_Capacity *= 2;

	if(m_Capacity * sizeof(T) >= m_uiMaxDataBufSize)
	{
		//cannot go over so much. has to give up and stop
		m_Data = oldData;
		m_Capacity = m_oldCapacity;
		return false;
	}

	m_Data = new T[m_Capacity];

	if(!m_Data)
	{
		m_Data = oldData;
		m_Capacity = m_oldCapacity;
		return false;
	}

	if(m_uiRemoveIndex < m_uiAddIndex)
	{
		memcpy(m_Data, oldData + m_uiRemoveIndex, (m_uiAddIndex - m_uiRemoveIndex) * sizeof(T));
		m_uiAddIndex -= m_uiRemoveIndex; //should be same as: m_uiAddIndex = m_Size;
		m_uiRemoveIndex = 0;
	}
	else
	{
		memcpy(m_Data, oldData + m_uiRemoveIndex, (m_oldCapacity - m_uiRemoveIndex) * sizeof(T));
		memcpy(m_Data + (m_oldCapacity - m_uiRemoveIndex), oldData, m_uiAddIndex * sizeof(T));
		m_uiAddIndex = (m_oldCapacity - m_uiRemoveIndex) + m_uiAddIndex; //should be same as: m_uiAddIndex = m_Size;
		m_uiRemoveIndex = 0;
	}
	
	delete []oldData;

	return true;
}

template <class T>
bool TCQueue<T>::WaitForNotify(DWORD dwMilliseconds)
{
	if(m_bNotify && m_hSignal)
		return (WaitForSingleObject(m_hSignal,dwMilliseconds)==WAIT_OBJECT_0);
	else
		return false;
}

template <class T>
bool TCQueue<T>::Notify()
{
	if(m_bNotify && m_hSignal)
	{
		if(ReleaseSemaphore(m_hSignal, 1, NULL))
			return true;
		else
			return false;
	}
	else
		return false;
}

template <class T>
T* TCQueue<T>::operator[](int nIndex)
{
	T* ret = NULL;

	Lock();

	if(nIndex >= 0 && nIndex < m_Size)
	{
		ret = &m_Data[(m_uiRemoveIndex + nIndex) % m_Capacity];
	}

	Unlock();

	return ret;
}

template <class T>
int TCQueue<T>::GetDataEx(T* x, int len, DWORD dwMilliseconds)
{
	if(m_bNotify)
	{
		if(WaitForNotify(dwMilliseconds))
		{
			return Pop_FrontEx(x, len, dwMilliseconds);
		}
	}
	else
	{
		return Pop_FrontEx(x, len, dwMilliseconds);
	}
		
	return 0;
}

template <class T>
int TCQueue<T>::PutDataEx(T* x, int len, DWORD dwMilliseconds)
{
	if(m_bNotify)
	{
		if(Push_BackEx(x, len, dwMilliseconds))
		{
			return Notify();
		}
	}
	else
	{
		return Push_BackEx(x, len, dwMilliseconds);
	}

	return 0;
}

template <class T>
bool TCQueue<T>::GetData(T* x, DWORD dwMilliseconds)
{
	if(m_bNotify)
	{
		if(WaitForNotify(dwMilliseconds))
		{
			return Pop_Front(x, dwMilliseconds);
		}
	}
	else
	{
		return Pop_Front(x, dwMilliseconds);
	}
		
	return false;
}

template <class T>
bool TCQueue<T>::PutData(T* x, DWORD dwMilliseconds)
{
	if(m_bNotify)
	{
		if(Push_Back(x, dwMilliseconds))
		{
			return Notify();
		}
	}
	else
	{
		return Push_Back(x, dwMilliseconds);
	}

	return false;
}

//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

template <class T> class TCArray
{
public:
	TCArray();
	TCArray(int capacity);
	virtual ~TCArray();

	int   size()     { return m_Size; }
	int   Size()     { return m_Size; }

	int   capacity() { return m_Capacity; }
	int   Capacity() { return m_Capacity; }

	bool  isEmpty()  { return m_Size == 0; }
	bool  IsEmpty()  { return m_Size == 0; }

	bool  indexOf(T* element, int *index);

	// Array processing functions
	T* get(int index);
	T* set(int index, T* element);

	int   add(T* element);
	int   insert(T *element, int index);
	void  remove(int index); 
	bool  remove(T* element);
	void  removeall(){clear();}

	T*	  operator[](int nIndex);

	BOOL Lock(DWORD timeout=INFINITE);
	BOOL Unlock();

	bool BeginAccess(){return m_mtxData.Lock();}
	bool EndAccess(){return m_mtxData.Unlock();}

private:
	void  clear() { m_Size = 0; }
	bool  grow(int size); // initializes new entries

	bool  verifyCapacity(int size); // increases array size if needed

	T*		 m_Data;
	int		 m_Size;
	int		 m_Capacity;
	HANDLE   m_mtxData;

	unsigned int		m_uiMaxDataBufSize;
}; // class CPtArray

template <class T> 
BOOL TCArray<T>::Lock(DWORD timeout)
{
	return (WaitForSingleObject(m_mtxData,timeout) == WAIT_OBJECT_0);
}

template <class T> 
BOOL TCArray<T>::Unlock()
{
	return ReleaseMutex(m_mtxData);
}

template <class T>
TCArray<T>::TCArray<T>()
{
	m_Capacity = DEFAULT_CAPACITY;
	m_Data     = new T[m_Capacity];
	m_Size     = 0;
	m_mtxData   = CreateMutex(NULL,FALSE,NULL);
	m_uiMaxDataBufSize = DEFAULT_MAX_DATA_BUFFER_SIZE;
}

template <class T>
TCArray<T>::TCArray<T>(int capacity)
{
  if (capacity < 0)
    m_Capacity = DEFAULT_CAPACITY;
  else
  	m_Capacity = capacity;

	m_Data = new T[m_Capacity];
	m_Size = 0;
	m_mtxData   = CreateMutex(NULL,FALSE,NULL);
	m_uiMaxDataBufSize = DEFAULT_MAX_DATA_BUFFER_SIZE;
}

template <class T>
TCArray<T>::~TCArray<T>()
{
	delete []m_Data;
	CloseHandle(m_mtxData);
}


// ------------------------------------------------------------------
template <class T>
T* TCArray<T>::operator[](int nIndex)
{
	if(nIndex >= 0 && nIndex < m_Size)
	{
		return &m_Data[nIndex];
	}

	return NULL;
}

template <class T>
bool TCArray<T>::indexOf(T *element, int *index)
{
	bool fnd = false;
	if(Lock())
	{
		for (NCC_INT i = 0; i < m_Size; i++) 
		{
			if (m_Data[i] == element) 
			{			
				*index = i;
				fnd = true;
				break;
			}
		}
		Unlock();
	}
	return fnd;
}

// ------------------------------------------------------------------
template <class T>
T* TCArray<T>::get(int index)
{
	T* ret = NULL;

	if(Lock())
	{
		if (index >= 0 && index < m_Size)
			ret = &m_Data[index];

		Unlock();
	}

	return ret;
}

//-------------------------------------------------------------------
template <class T>
T* TCArray<T>::set(int index, T* element)
{
	T* oldElem = NULL;

	if (index < 0 || index >= m_Size)
		return NULL;

	// grow() this CPtArray if set()ing at an index larger than our
	// current size. We use an if check here as this will not be the
	// normal case (minor speed opt).

	if(Lock())
	{
/*
		if (index >= m_Size)
			grow(index + 1);
*/
		oldElem = &m_Data[index];
		m_Data[index] = *element;

		Unlock();
	}

	return oldElem;
}

// ------------------------------------------------------------------
template <class T>
int TCArray<T>::add(T *element)
{
	int index = 0;

	if(Lock())
	{
		if(verifyCapacity(m_Size + 1))
		{
			index = m_Size++;
			m_Data[index] = *element;
		}

		Unlock();
	}

	return index;
}

// ------------------------------------------------------------------
template <class T>
int TCArray<T>::insert(T* element, int index)
{
	if(Lock())
	{
		if (index < 0)
			index = 0;

		if(index > m_Size)
			index = m_Size;

		if(verifyCapacity(m_Size + 1))
		{
			int toMove = (m_Size - index) * sizeof(T);
			if (toMove > 0)
				memmove(m_Data + index + 1, m_Data + index, toMove);

			m_Data[index] = element;
			m_Size++;
		}

		Unlock();
	}

	return index;
}

// ------------------------------------------------------------------
template <class T>
void TCArray<T>::remove(int index)
{
//	GT_VOID *oldElem;

	if (index < 0 || index >= m_Size)
		return GT_NULL;

	if(Lock())
	{
//		oldElem = &m_Data[index];

		int toMove = (m_Size - (index+1)) * sizeof(T);
		if (toMove > 0)
			memmove(m_Data + index, m_Data + index + 1, toMove);

		m_Size--;

		Unlock();
	}

//	return (T*)oldElem;
}

template <class T>
bool TCArray<T>::remove(T* element)
{
	bool fnd = false;
	int indx;


	if(Lock())
	{

		for (int i = 0; i < m_Size; i++) {
			if (&m_Data[i] == element) {
				indx = i;
				fnd = true;
				break;
			}
		}

		if(fnd)
		{
			int toMove = (m_Size - (indx+1)) * sizeof(T);
			if (toMove > 0)
				memmove(m_Data + indx, m_Data + indx + 1, toMove);
			m_Size--;
		}

		Unlock();

	}

	return fnd;
}

// ------------------------------------------------------------------
template <class T>
bool TCArray<T>::grow(int size)
{
	if (size > m_Size) 
	{
		if(verifyCapacity(size))
		{
			memset(m_Data + m_Size, 0, (size - m_Size) * sizeof(T));
			m_Size = size;
			return true;
		}
		else
			return false;
	}

	return true;
}

// ------------------------------------------------------------------
template <class T>
bool TCArray<T>::verifyCapacity(int size)
{
	if (size > m_Capacity) 
	{
		T* oldData = m_Data;
		unsigned int oldCapacity = m_Capacity;

		while (size > m_Capacity)
			m_Capacity *= 2;

		if(m_Capacity * sizeof(T) >= m_uiMaxDataBufSize)
		{
			//cannot add more memory to this array
			m_Data = oldData;
			m_Capacity = oldCapacity;
			return false;
		}

		m_Data = new T[m_Capacity];
		if(!m_Data)
		{
			m_Data = oldData;
			m_Capacity = oldCapacity;
			return false;
		}

		memcpy(m_Data, oldData, m_Size * sizeof(T));
		delete []oldData;
	}

	return true;
}


#endif