#include "List.h"

BOOL __fastcall DefEqualFcn(LPVOID lpA, LPVOID lpB)
{
	return (lpA == lpB);
}

LPLIST CreateList(LPEQUALFCN lpEqFcn)
{
	LPLIST lpLs = (LPLIST)DefAlloc(sizeof(LIST));
	
	InitializeCriticalSection(&lpLs->cs);
	lpLs->lpFirst	= NULL;
	lpLs->lpLast	= NULL;	
	lpLs->lpEqFcn	= (lpEqFcn == NULL) ? DefEqualFcn : lpEqFcn;	
	lpLs->iCount	= 0;	

	return lpLs;
}

LPVOID CreateItem(LPLIST lpLs, ULONG cItemSize, BOOL bFirst)
{
	LPLISTITEM  lpNewItem = (LPLISTITEM)DefAlloc(sizeof(LISTITEM) + cItemSize);

	lpNewItem->lpData = GetLIDataPtr(lpNewItem);	

	EnterCriticalSection(&lpLs->cs);
	if(bFirst)
	{
		if(lpLs->lpLast == NULL)
			lpLs->lpLast = lpNewItem;

		lpNewItem->lpNext	= (struct LISTITEMtag *)lpLs->lpFirst;
		lpLs->lpFirst		= lpNewItem;
	}
	else
	{
		if(lpLs->lpFirst == NULL)
			lpLs->lpFirst = lpNewItem;

		if(lpLs->lpLast != NULL)
			lpLs->lpLast->lpNext	= (struct LISTITEMtag *)lpNewItem;

		lpNewItem->lpNext		= NULL;
		lpLs->lpLast			= lpNewItem;
	}
	lpLs->iCount ++;
	LeaveCriticalSection(&lpLs->cs);

	return lpNewItem->lpData;
}

VOID AddItem(LPLIST lpLs, LPVOID lpData, BOOL bFirst)
{
	LPLISTITEM  lpNewItem = (LPLISTITEM)DefAlloc(sizeof(LISTITEM));

	lpNewItem->lpData = lpData;	

	EnterCriticalSection(&lpLs->cs);
	if(bFirst)
	{
		if(lpLs->lpLast == NULL)
			lpLs->lpLast = lpNewItem;

		lpNewItem->lpNext	= (struct LISTITEMtag *)lpLs->lpFirst;
		lpLs->lpFirst		= lpNewItem;
	}
	else
	{
		if(lpLs->lpFirst == NULL)
			lpLs->lpFirst = lpNewItem;

		if(lpLs->lpLast != NULL)
			lpLs->lpLast->lpNext	= (struct LISTITEMtag *)lpNewItem;

		lpNewItem->lpNext		= NULL;
		lpLs->lpLast			= lpNewItem;
	}
	lpLs->iCount ++;
	LeaveCriticalSection(&lpLs->cs);
}

LPVOID GetItemValue(LPLIST lpLs, INT id)
{
	LPLISTITEM lpLi = NULL;
	id ++;

	EnterCriticalSection(&lpLs->cs);
	lpLi = (LPLISTITEM)lpLs;
	while(lpLi != NULL && id > 0)
	{
		lpLi = (LPLISTITEM)lpLi->lpNext;
		id --;
	}
	LeaveCriticalSection(&lpLs->cs);

	if(lpLi == NULL)
		return NULL;
	else
		return lpLi->lpData;
}

BOOL RemoveItemById(LPLIST lpLs, INT id)
{
	LPLISTITEM lpPrevLi = NULL, lpLi = NULL;
	id ++;

	EnterCriticalSection(&lpLs->cs);
	lpLi = (LPLISTITEM)lpLs;
	while(lpLi != NULL && id > 0)
	{
		lpPrevLi = lpLi;
		lpLi = (LPLISTITEM)lpLi->lpNext;
		id --;
	}
	if(lpLi == NULL || lpPrevLi == NULL)
		return FALSE;
	lpPrevLi->lpNext = lpLi->lpNext;
	lpLs->iCount --;
	LeaveCriticalSection(&lpLs->cs);

	DefFree(lpLi);
	return TRUE;
}

BOOL RemoveItem(LPLIST lpLs, LPVOID lpData)
{
	LPLISTITEM lpPrevLi = NULL, lpLi = NULL;
	
	EnterCriticalSection(&lpLs->cs);
	lpLi = (LPLISTITEM)lpLs;
	while(lpLi != NULL && !lpLs->lpEqFcn(lpData, lpLi->lpData))
	{
		lpPrevLi = lpLi;
		lpLi = (LPLISTITEM)lpLi->lpNext;		
	}
	if(lpLi == NULL || lpPrevLi == NULL)
		return FALSE;
	lpPrevLi->lpNext = lpLi->lpNext;
	lpLs->iCount --;
	LeaveCriticalSection(&lpLs->cs);

	DefFree(lpLi);
	return TRUE;
}

VOID ClearList(LPLIST lpLs)
{
	LPLISTITEM lpOldLi, lpLi;

	EnterCriticalSection(&lpLs->cs);
	lpLi			= (LPLISTITEM)lpLs->lpFirst;
	lpLs->lpFirst	= NULL;
	lpLs->lpLast	= NULL;

	while(lpLi != NULL)
	{
		lpOldLi = lpLi;
		lpLi = (LPLISTITEM)lpLi->lpNext;
		DefFree(lpOldLi);
	}	
	lpLs->iCount = 0;
	LeaveCriticalSection(&lpLs->cs);
}

LPLISTENUM BeginListEnum(LPLIST lpLs)
{
	LPLISTENUM	lpLe = NULL;
	
	if(lpLs == NULL)
		return NULL;

	lpLe = (LPLISTENUM)DefAlloc(sizeof(LISTENUM));
	lpLe->lpLs = lpLs;
	lpLe->lpCurrentItem = lpLs->lpFirst;
	EnterCriticalSection(&lpLs->cs);

	return lpLe;
}

BOOL NextListItem(LPLISTENUM lpLe, LPVOID * lplpItem)
{
	if(lpLe->lpCurrentItem == NULL)
		return FALSE;

	*lplpItem = lpLe->lpCurrentItem->lpData;
	lpLe->lpCurrentItem = (LPLISTITEM)lpLe->lpCurrentItem->lpNext;

	return TRUE;
}

VOID EndListEnum(LPLISTENUM lpLe)
{
	LeaveCriticalSection(&lpLe->lpLs->cs);
	DefFree(lpLe);
}

VOID DestroyList(LPLIST lpLs)
{	
	ClearList(lpLs);
	DeleteCriticalSection(&lpLs->cs);
	DefFree(lpLs);
}