/*
 *  Copyright (C)  2000-2001 Marc Wandschneider <mw@kiltdown.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation.
 *
 *  For more information look at the file COPYRIGHT in this package
 *
 */
#include <sanity.h>

/**
 * This is a little list template C++ class.  Very cool, very useful, this 
 * class is a linked list that supports adding (O(1)), removing (O(n)), and
 * iterating (O(1)), using the firstElement() and nextElement() methods.
 */


/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::LinkList
 *=------------------------------------------------------------------------=
 * Our Constructor.  Nulls out a few pointers and that's about it. 
 */
template <class Type>
LinkList<Type>::LinkList()
{
    front = end = last = NULL;
}
  
/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::LinkList [copy constructor
 *=------------------------------------------------------------------------=
 * A copy constructor that will successfully copy over the list given 
 * another list.
 *
 * Parameters:
 *      LinkList &          - [in] source object to copy
 */
template <class Type>
LinkList<Type>::LinkList
(
    LinkList<Type> &source
)
{
    copyList(source);
}

/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::operator=
 *=------------------------------------------------------------------------=
 * implements a full copy operator for the this linked list class.
 *
 * Parameters:
 *      LinkList<Type>  &       - [in] source object to copy
 */
template <class Type>
void LinkList<Type>::operator=
(
    LinkList<Type> &source
)
{
    /**
     * First, clear out the existing list.
     */
    emptyList();

    /**
     * Now copy over the new list
     */
    copyList(source);
}


/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::~LinkList
 *=------------------------------------------------------------------------=
 * Simple destructor that cleans up everything.
 */
template <class Type>
LinkList<Type>::~LinkList()
{
    LLNode<Type> *next;

    /**
     * Loop through the list nuking Nodes, but doing nothing to the data 
     * they hold.
     */
    while (front != NULL) {
        next = front->next;
        delete front;
        front = next;
    }

    // that's all folks!
}

/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::addElement
 *=------------------------------------------------------------------------=
 * We always add to the end of the list.  We can still do this O(1)
 *
 * Parameters:
 *      Type            - [in] element to add to the list.
 *
 * Output:
 *      ERRCODE         - result.
 */
template <class Type>
ERRCODE LinkList<Type>::addElement
(
    Type element
)
{
    LLNode<Type> *nd = new LLNode<Type>;

    if (nd == NULL) return E_OUTOFMEMORY;

    nd->item = element;
    nd->next = NULL;

    if (front == NULL) {
        front = nd;
        end = front;
    } else {
        end->next = nd;
        end = nd;
    }

    return S_OK;
}



/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::copyList
 *=------------------------------------------------------------------------=
 * copies the given list into this list, duplicating the nodes as we go
 * along.
 *
 * Parameters:
 *      LinkList<Type> &            - [in] source list to copy
 */
template <class Type>
void LinkList<Type>::copyList
(
    LinkList<Type> &source
)
{
    LLNode<Type> *node, *iterate, *prev;

    front = last = NULL;

    /**
     * While the source has data, copy it over, and see if this is the
     * last ptr as well!!
     */
    iterate = source.front;
    prev = NULL;
    while (iterate != NULL) {

        /**
         * Create a new node for the data.
         */
        node = new LLNode<Type>();
        if (!node) {
            this->front = this->end = this->last = NULL;
            return;
        }

        /**
         * Set the data and update the chain.
         */
        node->item = iterate->item;
        node->next = NULL;
        if (prev == NULL) {
            this->front = node;
            prev = node;
        } else {
            prev->next = node;
            prev = node;
        }

        if (source.last == iterate)
            this->last = node;
        if (source.end == iterate)
            this->end = node;

        iterate = iterate->next;
    }
}




/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::countElements
 *=------------------------------------------------------------------------=
 * counts the number of elements in this linked list.
 *
 * Output:
 *      int                 - the number of items in this list.
 */
template <class Type>
int LinkList<Type>::countElements()
{
    LLNode<Type> *nd = front;
    int count = 0;

    while (nd) {
        count++;
        nd = nd->next;
    }

    return count;
}


/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::elementAt
 *=------------------------------------------------------------------------=
 * Returns the element at the given index.  This is O(n) on average, of 
 * course.  Use sparingly, and consider firstElement()/nextElement() instead
 * 
 * Parameters:
 *      int             - [in]  index of the element to return.
 *      Type *          - [out] the element to be returned.
 *
 * Output:
 *      ERRCODE
 */
template <class Type>
ERRCODE LinkList<Type>::elementAt
(
    int index,
    Type *pelement
)
{
    LLNode<Type> *node = front;

    if (pelement == NULL)
        return E_PARAM;

    /**
     * Zip through until we've found the element, making sure to stay in the
     * loop
     */
    for (int i = 0; i < index; i++) {
        if (node == NULL) break;
        node = node->next;
    }

    if (node == NULL) return E_PARAM;
    *pelement = node->item;
    return S_OK;
}

/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::emptyList
 *=------------------------------------------------------------------------=
 * clears out the linked list.
 */
template <class Type>
void LinkList<Type>::emptyList()
{
    LLNode<Type> *node = front, *next;

    while (node) {
        next = node->next;
        delete node;
        node = next;
    }

    front = end = last = NULL;
}


/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::firstElement
 *=------------------------------------------------------------------------=
 * Starts an iteration over all the elements in the list.  You then call
 * nextElement successively to see all the elements.  Note that we don't
 * try to guarantee a consistent list, etc ... if you add or remove while
 * iterating, expect wacky stuff.
 *
 * Parameters:
 *      Type *          - [out] The First Element in the LIST.
 *
 * Output:
 *      ERRCODE
 */
template <class Type>
ERRCODE LinkList<Type>::firstElement
(
    Type *pelement
)
{
    if (pelement == NULL) return E_PARAM;

    /**
     * If there are no items in the list, this is easy.
     */
    if (front == NULL) return S_NODATA;

    *pelement = front->item;
    last = front->next;
    return S_OK;
}

/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::nextElement
 *=------------------------------------------------------------------------=
 * continues the iteration over the list.  you continue to call this until
 * you get S_EOF, meaning there is no more data.  Please see the comments
 * for firstElement() regarding consistency.
 *
 * Parameters:
 *      Type *          - [out] next element to be retreived.
 *
 * Output:
 *      ERRCODE
 */
template <class Type>
ERRCODE LinkList<Type>::nextElement
(
    Type *pelement
)
{
    if (pelement == NULL) return E_PARAM;

    if (last != NULL) {
        *pelement = last->item;
        last = last->next;
        return S_OK;
    } else
        return S_NODATA;
}

/**
 *=------------------------------------------------------------------------=
 * LinkList<Type>::removeElement
 *=------------------------------------------------------------------------=
 * Removes the given element from the list.  Not terribly efficient, but
 * we don't really care right now !!
 *
 * Parameters:
 *      Type            - [in] the element to remove.
 *
 * Output:
 *      ERRCODE
 */
template <class Type>
ERRCODE LinkList<Type>::removeElement
(
    Type element
)
{
    LLNode<Type> *nd = front;
    LLNode<Type> *prev = NULL;

    /**
     * loop through looking for this element.
     */
    while (nd != NULL) {

        if (nd->item == element) {

            if (prev) {
                prev->next = nd->next;
                if (nd == end) end = prev;
            } else {
                front = nd->next;
                if (nd == end) end = front;
            }
            delete nd;
            break;
        }
        
        prev = nd;
        nd = nd->next;
    }

    return (nd == NULL) ? S_NOTFOUND : S_OK;
}



syntax highlighted by Code2HTML, v. 0.9.1