/*
**	termLists.c
**
**	Generic list management routines
**
**	Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* ClearGenericList(struct GenericList *List):
	 *
	 *	Clear a generic list, free its contents.
	 */

VOID __regargs
ClearGenericList(struct GenericList *List)
{
	struct Node *Node,*NextNode;

	ObtainSemaphore(&List -> ListSemaphore);

	Node = (struct Node *)List -> ListHeader . mlh_Head;

	while(NextNode = Node -> ln_Succ)
	{
		Remove(Node);

		FreeVec(Node);

		Node = NextNode;
	}

	List -> ListCount = 0;

	ReleaseSemaphore(&List -> ListSemaphore);
}

	/* DeleteGenericList(struct GenericList *List):
	 *
	 *	Free a generic list, including its contents.
	 */

VOID __regargs
DeleteGenericList(struct GenericList *List)
{
	ClearGenericList(List);

	FreeVec(List);
}

	/* CreateGenericList():
	 *
	 *	Create a generic list.
	 */

struct GenericList *
CreateGenericList()
{
	struct GenericList *List;

	if(List = (struct GenericList *)AllocVec(sizeof(struct GenericList),MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
	{
		NewList((struct List *)&List -> ListHeader);

		InitSemaphore(&List -> ListSemaphore);

		List -> ListCount = 0;
	}

	return(List);
}

	/* FirstGenericListNode(struct GenericList *List):
	 *
	 *	Pick the first node in a generic list.
	 */

struct Node * __regargs
FirstGenericListNode(struct GenericList *List)
{
	struct Node *Node;

	ObtainSemaphore(&List -> ListSemaphore);

	if(List -> ListHeader . mlh_Head -> mln_Succ)
		Node = List -> ListNode = (struct Node *)List -> ListHeader . mlh_Head;
	else
		Node = NULL;

	ReleaseSemaphore(&List -> ListSemaphore);

	return(Node);
}

	/* LastGenericListNode(struct GenericList *List):
	 *
	 *	Pick the last node in a generic list.
	 */

struct Node * __regargs
LastGenericListNode(struct GenericList *List)
{
	struct Node *Node;

	ObtainSemaphore(&List -> ListSemaphore);

	if(List -> ListHeader . mlh_TailPred -> mln_Succ)
		Node = List -> ListNode = (struct Node *)List -> ListHeader . mlh_TailPred;
	else
		Node = NULL;

	ReleaseSemaphore(&List -> ListSemaphore);

	return(Node);
}

	/* NextGenericListNode(struct GenericList *List):
	 *
	 *	Pick the next successive node in a generic list.
	 */

struct Node * __regargs
NextGenericListNode(struct GenericList *List)
{
	struct Node *Node;

	ObtainSemaphore(&List -> ListSemaphore);

	if(List -> ListNode)
	{
		if(List -> ListNode -> ln_Succ -> ln_Succ)
			Node = List -> ListNode = List -> ListNode -> ln_Succ;
		else
			Node = NULL;

		ReleaseSemaphore(&List -> ListSemaphore);
	}
	else
	{
		ReleaseSemaphore(&List -> ListSemaphore);

		Node = FirstGenericListNode(List);
	}

	return(Node);
}

	/* PrevGenericListNode(struct GenericList *List):
	 *
	 *	Pick the preceding node in a generic list.
	 */

struct Node * __regargs
PrevGenericListNode(struct GenericList *List)
{
	struct Node *Node;

	ObtainSemaphore(&List -> ListSemaphore);

	if(List -> ListNode)
	{
		if(List -> ListNode -> ln_Pred -> ln_Pred)
			Node = List -> ListNode = List -> ListNode -> ln_Pred;
		else
			Node = NULL;

		ReleaseSemaphore(&List -> ListSemaphore);
	}
	else
	{
		ReleaseSemaphore(&List -> ListSemaphore);

		Node = LastGenericListNode(List);
	}

	return(Node);
}

	/* DeleteGenericListNode(struct GenericList *List,struct Node *Node):
	 *
	 *	Delete a single node from a generic list.
	 */

VOID __regargs
DeleteGenericListNode(struct GenericList *List,struct Node *Node)
{
	ObtainSemaphore(&List -> ListSemaphore);

	if(!Node)
		Node = List -> ListNode;

	if(Node)
	{
		if(Node == List -> ListNode)
		{
			if(Node -> ln_Succ -> ln_Succ)
				List -> ListNode = Node -> ln_Succ;
			else
			{
				if(Node -> ln_Pred -> ln_Pred)
					List -> ListNode = Node -> ln_Pred;
				else
					List -> ListNode = NULL;
			}
		}

		Remove(Node);

		FreeVec(Node);

		List -> ListCount--;
	}

	ReleaseSemaphore(&List -> ListSemaphore);
}

	/* CreateGenericListNode(LONG Size,STRPTR Name):
	 *
	 *	Create a new generic list node.
	 */

struct Node * __regargs
CreateGenericListNode(LONG Size,STRPTR Name)
{
	struct Node	*Node;
	LONG		 Head;

	if(Size < sizeof(struct Node))
		Head = Size = sizeof(struct Node);
	else
		Head = Size;

	if(Name)
		Size += strlen(Name) + 1;

	if(Node = (struct Node *)AllocVec(Size,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
	{
		if(Name)
		{
			Node -> ln_Name = ((char *)Node) + Head;

			strcpy(Node -> ln_Name,Name);
		}
		else
			Node -> ln_Name = NULL;
	}

	return(Node);
}

	/* AddGenericListNode(struct GenericList *List,struct Node *Node,BYTE Mode):
	 *
	 *	Add a node to a generic list.
	 */

VOID __regargs
AddGenericListNode(struct GenericList *List,struct Node *Node,BYTE Mode)
{
	ObtainSemaphore(&List -> ListSemaphore);

	switch(Mode)
	{
		case ADD_GLIST_BOTTOM:

			AddTail((struct List *)&List -> ListHeader,Node);
			break;

		case ADD_GLIST_TOP:

			AddHead((struct List *)&List -> ListHeader,Node);
			break;

		case ADD_GLIST_BEHIND:

			if(List -> ListNode)
				Insert((struct List *)&List -> ListHeader,Node,List -> ListNode);
			else
				AddTail((struct List *)&List -> ListHeader,Node);

			break;

		case ADD_GLIST_BEFORE:

			if(List -> ListNode && List -> ListNode != (struct Node *)List -> ListHeader . mlh_Head)
				Insert((struct List *)&List -> ListHeader,Node,List -> ListNode -> ln_Pred);
			else
				AddHead((struct List *)&List -> ListHeader,Node);

			break;
	}

	List -> ListNode = Node;
	List -> ListCount++;

	ReleaseSemaphore(&List -> ListSemaphore);
}

	/* GenericListCount(struct GenericList *List):
	 *
	 *	Return the number of generic list entries.
	 */

LONG __regargs
GenericListCount(struct GenericList *List)
{
	LONG Count;

	ObtainSemaphore(&List -> ListSemaphore);

	Count = List -> ListCount;

	ReleaseSemaphore(&List -> ListSemaphore);

	return(Count);

}
