//----------------------------------------------------------------------
//  IMPLEMENTATION FILE (genlist.cpp)
//  This module exports a generic list ADT.  Each item in the list is
//  a pointer to an actual data item.
//  List representation: a singly linked list of dynamic nodes.
//----------------------------------------------------------------------
#include "genlist.h"
#include <string.h>     // For strlen() and strcpy()
#include <stddef.h>     // For NULL
#include <alloc.h>      // For coreleft()   (This function is nonportable)

typedef NodeType* NodePtr;

struct NodeType {           // Linked list node type
    void*   data;     // Data member (a pointer to actual data)
    NodePtr link;     // Pointer to next node
};

NodePtr PtrToClone( NodePtr );         // Prototypes for
NodePtr PrevPtr( NodePtr, NodePtr );   // auxiliary functions

// Private members of class:
//     NodeType* head;       // Head pointer to linked list (NULL if empty)
//     NodeType* currPtr;    // Pointer to current item
//
// CLASSINV:
//     (head != NULL) --> head points to front of list
//  && (head == NULL) --> list is empty
//  && (currPtr != NULL) --> currPtr points to currently accessed node
//  && (currPtr == NULL) --> list cursor is beyond end of list

GenList::GenList()
    //..................................................................
    // POST: head == NULL  &&  currPtr == NULL
    //..................................................................
{
    head = currPtr = NULL;
}

GenList::GenList( const GenList& otherList )
    //..................................................................
    // POST: A clone of otherList's linked list is on free store
    //    && head points to this new list (or == NULL)
    //    && currPtr == NULL
    //..................................................................
{
    head = PtrToClone(otherList.head);
    currPtr = NULL;
}

GenList::~GenList()
    //..................................................................
    // POST: All free store for list has been deallocated
    //..................................................................
{
    currPtr = head;
    while ( !EndOfList() )
        Delete();
}

Boolean GenList::IsEmpty() const
    //..................................................................
    // POST: FCTVAL == (head == NULL)
    //..................................................................
{
    return (head == NULL);
}

Boolean GenList::IsFull() const
    //..................................................................
    // POST: FCTVAL == (there is no room on the free store for
    //                  another NodeType object)
    //..................................................................
{
    return (coreleft() < sizeof(NodeType));
}

void GenList::Reset()
    //..................................................................
    // PRE:  head != NULL
    // POST: currPtr == head
    //..................................................................
{
    currPtr = head;
}

Boolean GenList::EndOfList() const
    //..................................................................
    // POST: FCTVAL == (currPtr == NULL)
    //..................................................................
{
    return (currPtr == NULL);
}

void GenList::Advance()
    //..................................................................
    // PRE:  head != NULL  &&  currPtr != NULL
    // POST: currPtr == (currPtr<entry>)->link
    //..................................................................
{
    currPtr = currPtr->link;
}

void* GenList::CurrentItem() const
    //..............................................................
    // PRE:  head != NULL  &&  currPtr != NULL
    // POST: FCTVAL == currPtr->data
    //..................................................................
{
    return currPtr->data;
}

void GenList::InsertBefore( /* in */ void* somePtr )
    //..................................................................
    // PRE:  Assigned(somePtr)  &&  NOT IsFull()
    // POST: (currPtr<entry> == NULL) --> New node is at end of list
    //    && (currPtr<entry> != NULL) --> New node inserted before
    //                                          *(currPtr<entry>)
    //    && currPtr == pointer to new node
    //..................................................................
{
    NodePtr newPtr = new NodeType;
    newPtr->data = somePtr;
    newPtr->link = currPtr;
    if (currPtr == head)
        head = newPtr;
    else {
        NodePtr p = PrevPtr(currPtr, head);
        p->link = newPtr;
    }
    currPtr = newPtr;
}

void GenList::InsertAfter( /* in */ void* somePtr )
    //..................................................................
    // PRE:  Assigned(somePtr)  &&  NOT IsFull()
    //    && head != NULL  &&  currPtr != NULL
    // POST: New node inserted after *(currPtr<entry>)
    //    && currPtr == pointer to new node
    //..................................................................
{
    NodePtr newPtr = new NodeType;
    newPtr->data = somePtr;
    newPtr->link = currPtr->link;
    currPtr->link = newPtr;
    currPtr = newPtr;
}

void GenList::Delete()
    //..................................................................
    // PRE:  head != NULL  &&  currPtr != NULL
    // POST: *(currPtr<entry>) deleted from list
    //    && currPtr points to node after deleted node
    //       (or == NULL if last node was deleted)
    //..................................................................
{
    NodePtr temp = currPtr;
    if (currPtr == head)
        head = currPtr = head->link;
    else {
        NodePtr p = PrevPtr(currPtr, head);
        p->link = currPtr = currPtr->link;
    }
    delete temp;
}

NodePtr PrevPtr( /* in */ NodePtr aPtr,
                 /* in */ NodePtr head )
    //..................................................................
    // PRE:  aPtr != head
    // POST: FCTVAL == pointer to node before *aPtr
    //..................................................................
{
    NodePtr p = head;
    while (p->link != aPtr)  // INV (prior to test):
                             //    *p is a node before *aPtr
        p = p->link;
    return p;
}

NodePtr PtrToClone( /* in */ NodePtr aPtr )
    //..................................................................
    // PRE:  Assigned(aPtr)
    // POST: A clone of sublist starting with *aPtr is on free store
    //    && FCTVAL == pointer to front of this sublist
    //..................................................................
{
    NodePtr newPtr = NULL;
    if (aPtr != NULL) {
        newPtr = new NodeType;
        newPtr->data = aPtr->data;
        newPtr->link = PtrToClone(aPtr->link);
    }
    return newPtr;
}


