/*
**	Lists.c
**
**	Generic list management routines
**
**	Copyright © 1990-1996 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

///#ifndef _GLOBAL_H
///#include "Global.h"
///#endif


/* globals */
	/* Generic list types. */

enum	{	GLIST_UPLOAD,GLIST_DOWNLOAD,GLIST_DIAL,GLIST_WAIT,GLIST_TRAP,GLIST_COUNT };

	/* Generic list add operations. */

enum	{	ADD_GLIST_BOTTOM,ADD_GLIST_TOP,ADD_GLIST_BEHIND,ADD_GLIST_BEFORE };

	/* A list as employed by the ARexx interface. */

struct GenericList
{
	struct MinList	       ListHeader;     /* Kopf der Liste */
	struct Node	          *ListNode;       /* Zeiger auf aktuellen Node */
	LONG                   ListCount;      /* Nutzungszähler der Liste ... */
	struct SignalSemaphore ListSemaphore;  /* ... und entspr. Semaphore */
};

/* end globals */

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

VOID
ClearGenericList(struct GenericList *List)
{
	ObtainSemaphore(&List -> ListSemaphore);

	FreeList((struct List *)&List -> ListHeader);

	List -> ListCount = 0;

	ReleaseSemaphore(&List -> ListSemaphore);
}

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

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

	FreeVecPooled(List);
}

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

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

	if(List = (struct GenericList *)AllocVecPooled(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 *
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 *
LastGenericListNode(struct GenericList *List)
{
	struct Node *Node;

	ObtainSemaphore(&List -> ListSemaphore);

	if(List -> ListHeader . mlh_Head -> 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 *
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 *
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
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;
			}
		}

		FreeNode(Node);

		List -> ListCount--;
	}

	ReleaseSemaphore(&List -> ListSemaphore);
}

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

struct Node *
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 *)AllocVecPooled(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
AddGenericListNode(struct GenericList *List,struct Node *Node,LONG 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
GenericListCount(struct GenericList *List)
{
	LONG Count;

	ObtainSemaphore(&List -> ListSemaphore);

	Count = List -> ListCount;

	ReleaseSemaphore(&List -> ListSemaphore);

	return(Count);
}
