/****
 *
 * Implementation of list.h.
 *
 */

#include <stdio.h>
#include "list.h"


List::List() : first(null), last(null), size(0), enumstate(null) {}

List::~List()
{
    ListItem* i;

    for (i=first; i; i=i->next) {
	delete i->data;
	delete i;
    }
}

List* List::Put(ListElem* e)
{
    ListItem* newi = new ListItem;

    newi->data = e;
    newi->prev = last;
    if (last)
	last->next = newi;
    last = newi;
    if (! first) {
	first = newi;
	enumstate = first;
    }
    size++;
    return this;
}

ListElem* List::Pull()
{
    ListItem* item = first;
    ListElem* data;

    if (size == 0)
	return 0;
    if (first == last) {
	first = last = enumstate = 0;
	size = 0;
	data = item->data;
	/*delete item;*/
	return data;
    }
    first = enumstate = item->next;
    first->prev = 0;
    size--;
    data = item->data;
    delete item;
    return data;
}

List* List::Push(ListElem* e)
{
    ListItem* newi = new ListItem;

    newi->data = e;
    newi->next = first;
    if (first)
	first->prev = newi;
    enumstate = first = newi;
    if (! last)
	last = newi;
    size++;
    return this;
}

ListElem* List::Pop()
{
    ListItem* item = last;
    ListElem* data;

    if (size == 0)
	return 0;
    if (first == last) {
	first = last = enumstate = 0;
	size = 0;
	data = item->data;
	delete item;
	return data;
    }
    enumstate = first;
    last = item->prev;
    last->next = 0;
    size--;
    data = item->data;
    delete item;
    return data;
}

List* List::Insert(ListElem* e, int n)
{
    ListItem* newitem = new ListItem, *next;

    if (n == 0)
	return Push(e);

    if (n == size)
	return Put(e);

    if (! GetNth(n))
	return this;

    newitem->data = e;
    newitem->prev = gotitem;
    newitem->next = (next = gotitem->next);
    gotitem->next = newitem;
    if (next)
	next->prev = newitem;
    enumstate = newitem;
    size++;
    return this;
}

ListElem* List::GetNth(int n)
{
    ListItem* nexti;

    if ((n < 1) || (n > size)) {
	gotitem = null;
	return 0;
    }
    if (n < size/2) {
	gotitem = first;
	while(--n)
	    gotitem = gotitem->next;
    }
    else {
	gotitem = last;
	while(++n <= size)
	    gotitem = gotitem->prev;
    }
    enumstate = (nexti = gotitem->next) ? nexti : first;
    return gotitem->data;
}

ListElem* List::RemoveNth(int n)
{
    ListItem* item, prev;
    ListElem* data;

    if ((size == 0) || (n < 1) || (n > size))
	return 0;
    if (n == 1)
	return Pull();
    if (n == size)
	return Pop();
    if (n < size/2) {
	item = first;
	while(--n)
	    item = item->next;
    }
    else {
	item = last;
	while(++n <= size)
	    item = item->prev;
    }
    item->prev->next = item->next;
    item->next->prev = item->prev;
    size--;
    enumstate = (size == 0) ? null : item->next;
    data = item->data;
    delete item;
    return data;
}

ListElem* List::Find(ListElemKey* k)
{
    ListItem* ip;

    for (ip=first, curpos=0; ip; ip=ip->next, curpos++) {
	if (ip->data->Compare(k) == 0)
	    return ip->data;
    }
    return 0;
}
 
int List::FindPos(ListElemKey* k)
{
    ListItem* ip;

    for (ip=first, curpos=0; ip; ip=ip->next, curpos++) {
	if (ip->data->Compare(k) == 0) {
	    return curpos+1;
	}
    }
    return 0;
}

int List::Len()
{
    return size;
}

ListElem* List::Enum()
{
    ListItem* item;

    if ((item = enumstate)) {
	enumstate = enumstate->next;
	return item->data;
    }
    else {
	enumstate = first;
	return 0;
    }
}

void List::ResetEnum()
{
    enumstate = first;
}

/*
 * Less-than-totally-gross bubble sort algorithm.
 */
List* List::Sort(bool ascending)
{
    void Swap(ListItem*, ListItem*);
    int i, j, n = Len();
    ListItem *ip, *jp;

    for (i=1, ip=first; i<n; i++, ip=ip->next) {
	for (j=n, jp=last->prev; i<j; j--, jp=jp->prev) {
	    if (ascending) {
		if (jp->data->Compare(jp->next->data) > 0)
		    jp->Swap(jp->next);
	    }
	    else {
		if (jp->data->Compare(jp->next->data) < 0)
		    jp->Swap(jp->next);
	    }
	}
    }
    return this;
}

void ListItem::Swap(ListItem* i)
{
    ListElem* temp;

    temp = this->data;
    this->data = i->data;
    i->data = temp;
}

void List::Print()
{
    ListItem* item;

    for (item = first; item; item = item->next)
	item->data->Print();
    printf("\n");
}

ListElem::ListElem() {}

ListElem::~ListElem() {}

int ListElem::Compare(ListElem* e) { return 0; }

int ListElem::Compare(ListElemKey* k) { return 0; }

ListElemKey* ListElem::GetKey() { return null; }

void ListElem::Print() { }

ListItem::ListItem() : data(null), next(null), prev(null) {}

ListItem::~ListItem() {}