/*
 * Copyright (C) 1992, Board of Trustees of the University of Illinois.
 *
 * Permission is granted to copy and distribute source with out fee.
 * Commercialization of this product requires prior licensing
 * from the National Center for Supercomputing Applications of the
 * University of Illinois.  Commercialization includes the integration of this 
 * code in part or whole into a product for resale.  Free distribution of 
 * unmodified source and use of NCSA software is not considered 
 * commercialization.
 *
 */


/*
 * list.c:  This module contains list manipulation routines that cunstruct
 * and maintain a linked list of data items.  The record at the head of each
 * list contains pointers to the head, tail, and current list position.
 * the list itsself is doubly linked with both next and previous pointers.
 *
 * ddt 
 */
#include <stdio.h>
#include "listP.h"
#include "../config.h"
#ifndef MALLOC
#define MALLOC  malloc
#define FREE    free
#endif

#define NIL	0

#ifndef DISABLE_TRACE
extern int htmlwTrace;
#endif

static void ListPrintErr(s)
char *s;
{
#ifndef DISABLE_TRACE
	if (htmlwTrace) {
		fprintf(stderr,"%s",s);
	}
#endif
}

/*
 * This function returns the data located at the head of the linked list,
 * or NIL if the list is empty.  As a side effect current is also set to
 * the head of the list.
 */
char *ListHead(theList)
List theList;
{
	if (!theList)
		return(NIL);
	theList->current = theList->head;
	if (theList->head)
		return(theList->head->value);
	else
		return(NIL);
}

/*
 * This function returns the data located at the tail of the linked list,
 * or NIL if the list is empty.  As a side effect current is also set to
 * the tail of the list.
 */
char *ListTail(theList)
List theList;
{
	if (!theList)
		return(NIL);
	theList->current = theList->tail;
	if (theList->tail)
		return(theList->tail->value);
	else
		return(NIL);
}

/*
 * This function returns the data located at the current position in the
 * linked list, or NIL if the list is empty.
 */
char *ListCurrent(theList)
List theList;
{
	if (!theList)
		return(NIL);
	if (theList->current)
		return(theList->current->value);
	else
		return(NIL);
}

/*
 * This function returns the data located at the next element of the linked
 * list after the current position, or NIL if the list is empty, or you
 * are at its end.
 * As a side effect current is also set to the next entry in the list.
 */
char *ListNext(theList)
List theList;
{
	if (!theList)
		return(NIL);
	if (theList->current) {
		theList->current = theList->current->next;
		return(ListCurrent(theList));
		}
	else
		return(NIL);
}

/*
 * This function returns the data located at the previous element of the linked
 * list before the current position, or NIL if the list is empty.
 * As a side effect current is also set to the previous entry in the list.
 */
char *ListPrev(theList)
List theList;
{
	if (!theList)
		return(NIL);
	if (theList->current) {
		theList->current = theList->current->prev;
		return(ListCurrent(theList));
		}
	else
		return(NIL);
}

/*
 * Create a list head and initialize it to NIL.
 */
List ListCreate()
{
List retVal;

	if (!(retVal = (List) MALLOC(sizeof(struct LISTSTRUCT)))) {
		ListPrintErr("Out of Memory\n");
		return((List) 0);
		}
	retVal->head = NIL;
	retVal->tail = NIL;
	retVal->current = NIL;
	retVal->listCount = 0;
	return(retVal);
}

/*
 * Destroy a list head, and free all associated memory.
 */
void ListDestroy(theList)
List theList;
{
struct LISTINSTANCE *l;
struct LISTINSTANCE *m;

	if (!theList)
		return;
	l = theList->head;
	while(l) {
		m = l;
		l = l->next;
		FREE(m);
		}
	FREE(theList);
		
}


/*
 * Add an entry to the end of the linked list.  Current is changed to point to
 * the added element.
 */
int ListAddEntry(theList,v)
/* return 0 on failure */
List theList;
char *v; /* data to be added */
{
struct LISTINSTANCE *l;

	if (!(l =(struct LISTINSTANCE *) MALLOC(sizeof(struct LISTINSTANCE)))){
		ListPrintErr("Out of Memory\n");
		return(0);
		}

	l->value = v;

	l->next = NIL;
	l->prev = NIL;

	if (theList->head == NIL)
		theList->tail = theList->head = l;
	else {
		theList->tail->next = l;
		l->prev = theList->tail;
		theList->tail = l;
		}

	theList->current = l;

	theList->listCount++;
	
	return(1);
}

/*
 * Search the list for an entry with a matching value field, and return
 * a pointer to that list element.  Current is changed to point to the
 * element returned.
 */
static struct LISTINSTANCE *SearchListByValue(theList,v)
List theList;
char *v;
{
struct LISTINSTANCE *l;

	l = theList->head;
	while (l != NIL) {
		if (l->value == v) {
			theList->current = l;
			return(l);
			}
		else {
			l = l->next;
			}
		}
	theList->current = l;

	return(NIL);
	
}

/*
 * Find the list entry with a matching value field, and delete it
 * from the list.  Set current to point to the element after the deleted
 * element in the list.
 */
int ListDeleteEntry(theList,v)
/* removes the first occurance of v from the list */
/* return 0 if value not in list else 1 */
List theList;
char *v;
{
struct LISTINSTANCE *l;
char *retV;

	if (!(l = SearchListByValue(theList,v)))
		return(0);

	if (l->prev)
		l->prev->next = l->next;
	else
		theList->head = l->next;

	if (l->next)
		l->next->prev = l->prev;
	else
		theList->tail = l->prev;

	theList->current = l->next;

	retV = l->value;
	FREE(l);

	theList->listCount--;

	return(1);
}


int ListMakeEntryCurrent(theList,entry)
/* return 0 on failure  */
List theList;
char *entry;
{
struct LISTINSTANCE *l;

	if (theList) {
		if (!(l = SearchListByValue(theList,entry)))
			return(0);
		theList->current = l;
		return(1);
		}
	return(0);

}

int ListCount(theList)
/* return the number of elements in the list */
/* current position pointer is not affected */
List theList;
{
/*
char *entry;
int count;
struct LISTINSTANCE *saveCurrent;
*/	
	if (theList) {
		return(theList->listCount);
		}
	else {
		return(0);
		}
}


/* return indexed entry. Index starts at 0 */
/* the current list pointer will be set to this entry */
/* return 0 on failure */
char *ListGetIndexedEntry(theList,number)
List theList;
int number;
{
char *entry;
register int x;

	if (!theList) {
		return(0);
		}
	entry = ListHead(theList);
	for (x = 0; x < number; x++) {
		if (!entry) {
			return(0);
			}
		entry = ListNext(theList);
		}
	return(entry);
}
