//----------------------------------------------------------------------
//  IMPLEMENTATION FILE (person.cpp)
//  This module exports a record type for personal data and a class
//  for maintaining lists of such records
//  List representation: a singly linked list of dynamic nodes.
//----------------------------------------------------------------------
#include "person.h"
#include <string.h>     // For strlen() and strcpy()
#include <stddef.h>     // For NULL
#include <alloc.h>      // For coreleft()  (This function is nonportable)

typedef PersonNode* NodePtr;
struct PersonNode {
    char*   name;        // Pointer to person's name
    int     age;         // Person's age
    NodePtr link;        // Pointer to next node
};

// Private members of class:
//    NodePtr head;
//    NodePtr currPtr;
//
// 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

NodePtr PrevPtr( NodePtr, NodePtr ); // Prototype for auxiliary function

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

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

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

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

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

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

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

PersonRec PersonList::CurrentRec() const
    //..............................................................
    // PRE:  head != NULL  &&  currPtr != NULL
    // POST: FCTVAL.name == currPtr->name
    //    && FCTVAL.age == currPtr->age
    //..................................................................
{
    PersonRec rec;

    rec.name = currPtr->name;
    rec.age = currPtr->age;
    return rec;
}

void PersonList::InsertBefore( /* in */ PersonRec someRec )
    //..................................................................
    // PRE:  Assigned(someRec)
    // 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 PersonNode;
    // ASSERT: Storage for node is now on free store and
    //         its base address is in newPtr

    newPtr->name = new char[strlen(someRec.name)+1];
    // ASSERT: Storage for string array is now on free store and
    //         its base address is in newPtr->name

    strcpy(newPtr->name, someRec.name);
    // ASSERT: Person's name has been copied to free store

    newPtr->age = someRec.age;
    newPtr->link = currPtr;
    if (currPtr == head)
        head = newPtr;
    else {
        NodePtr p = PrevPtr(currPtr, head);
        p->link = newPtr;
    }
    currPtr = newPtr;
}

void PersonList::InsertAfter( /* in */ PersonRec someRec )
    //..................................................................
    // PRE:  Assigned(someRec)  &&  head != NULL  &&  currPtr != NULL
    // POST: New node inserted after *(currPtr<entry>)
    //    && currPtr == pointer to new node
    //..................................................................
{
    NodePtr newPtr = new PersonNode;
    newPtr->name = new char[strlen(someRec.name)+1];
    strcpy(newPtr->name, someRec.name);
    newPtr->age = someRec.age;

    newPtr->link = currPtr->link;
    currPtr->link = newPtr;
    currPtr = newPtr;
}

void PersonList::Delete()
    //..................................................................
    // PRE:  head != NULL  &&  currPtr != NULL
    // POST: *(currPtr<entry>) deleted from list (and name string
    //       deleted from free store)
    //    && currPtr points to node after deleted node (or == NULL if
    //       last node was deleted)
    //..................................................................
{
    delete currPtr->name;
    // ASSERT: Free store for name string deallocated
    NodePtr temp = currPtr;
    if (currPtr == head)
        head = currPtr = head->link;
    else {
        NodePtr p = PrevPtr(currPtr, head);
        p->link = currPtr = currPtr->link;
    }
    delete temp;
    // ASSERT: Free store for node deallocated
}

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

