//
//  NAME
//    plist.cpp
//
//  DESCRIPTION
//    This file contains the function definitions for the member
//    functions of the plist class and global functions which are
//    related to the plist class.
//
//    For descriptions of the parameters and return values,
//    see plist.h.
//


//
//  Include files.
//

#include <stdlib.h>
#include "bool.h"
#include "person.h"
#include "plist.h"


//
//  NAME
//    plist::element
//
//  DESCRIPTION
//    Structure of an element used in the linked list of people.
//
//  MEMBERS
//    data  - person.
//    next  - pointer to the next element in the linked list.
//

struct plistElem {
   person    * data;
   plistElem * next;
};


//
//  NAME
//    plist::plist()
//
//  DESCRIPTION
//    This is the default constructor for the plist class.
//

plist::plist() {
   head    = NULL;
   current = NULL;
}


//
//  NAME
//    plist::plist(const plist& p)
//
//  DESCRIPTION
//    This is the copy constructor for the plist class.  It
//    uses a local pointer to traverse the source list.
//

plist::plist(const plist& otherList) {
   plistElem * otherCurrPos = otherList.head;
   plistElem * currPos      = NULL;

   //  Clear the list.
   clearList();

   //  Copy the data from the other list.
   while (otherCurrPos != NULL) {
      addToEnd(otherCurrPos->data);
      otherCurrPos = otherCurrPos->next;
      }

   //  Set the current pointer to match that of the other list.
   currPos      = head;
   otherCurrPos = otherList.head;
   while (otherCurrPos != otherList.current) {
      currPos      = currPos->next;
      otherCurrPos = otherCurrPos->next;
      }

   return;
}


//
//  NAME
//    plist::~plist
//
//  DESCRIPTION
//    This is the destructor for the plist class.
//

plist::~plist() {
   clearList();
}


//
//  NAME
//    plist::operator=
//
//  DESCRIPTION
//    This is the assignment operator for the plist class.  It
//    uses a local pointer to traverse the source list.
//

const plist& plist::operator=(const plist& otherList) {
   plistElem * currPos      = NULL;
   plistElem * otherCurrPos = otherList.head;

   if (this != &otherList) {

      //  Clear the list.
      clearList();

      //  Copy the data from the other list.
      while (otherCurrPos != NULL) {
         addToEnd(otherCurrPos->data);
         otherCurrPos = otherCurrPos->next;
         }

      //  Set the current pointer to match that of the other list.
      currPos      = head;
      otherCurrPos = otherList.head;
      while (otherCurrPos != otherList.current) {
         currPos      = currPos->next;
         otherCurrPos = otherCurrPos->next;
         }

      }

   return *this;
}


//
//  NAME
//    plist::addToEnd
//
//  DESCRIPTION
//    This functions adds the given person to the end of the list.
//    It traverses the list from the head to find the end, then adds
//    a new element to the end of the list.
//

void plist::addToEnd(person * p) {
   plistElem * pe = newElem(p);

   if (head == NULL) {
      head = pe;
      current = head;
      return;
      }

   moveToEnd();
   current->next = pe;
   current = pe;
   return;
}


//
//  NAME
//    plist::getFirst
//
//  DESCRIPTION
//    This function gets the first person from the list.  The member
//    variable "current" is set to point to the head of the list, and
//    the person information stored in that element is returned, if such
//    an element exists.
//

person * plist::getFirst() {
   current = head;
   if (current == NULL) {
      return NULL;
      }
   return current->data;
}


//
//  NAME
//    plist::getNext
//
//  DESCRIPTION
//    This function gets the person information for the next person.
//    The "current" pointer is moved ahead one position in the list,
//    and the person information stored in that element is returned,
//    if such an element exists.
//

person * plist::getNext() {
   current = current->next;
   if (current == NULL) {
      return NULL;
      }
   return current->data;
}


//
//  NAME
//    plist::atEnd
//
//  DESCRIPTION
//    This function determines if the list is empty by seeing if the
//    "current" member variable is NULL or not.
//

bool plist::atEnd() const {
   return (current == NULL) ? true : false;
}


//
//  NAME
//    plist::clearList
//
//  DESCRIPTION
//    This function removes all elements from the list by traversing
//    the list from the head and deallocating each element.  The
//    "current" member variable is used to traverse the list, and the
//    local variable "next" points to the next element.  When the
//    list has been empties, the "head" and "current" member variables
//    are set to NULL.
//

void plist::clearList() {
   plistElem * next = NULL;
   current = head;
   while (current != NULL) {
      next = current->next;
      delete current->data;
      delete current;
      current = next;
      }
   head    = NULL;
   current = head;
   return;
}


//
//  NAME
//    operator<<
//
//  DESCRIPTION
//    This function is the output operator for the plist class.
//
//  PARAMETERS
//    os  (in/out) - output stream.
//    pl  (in)     - plist to output.
//
//  RETURNS
//    reference to the output stream.
//

ostream& operator<<(ostream& os, const plist& pl) {
   int         count = 0;
   plistElem * pe    = pl.head;

   while (pe != NULL) {
      pe->data->display();
      count++;
      pe = pe->next;
      }

   cout << endl;
   cout << "There are " << count << " people in the list." << endl;

   return os;
}


//
//  NAME
//    plist::newElemment
//
//  DESCRIPTION
//    This function allocates a new list element and copies the given
//    person information into it.
//
//  PARAMETESRS
//    p  (in) - person information to copy into the new element.
//
//  RETURNS
//    pointer to the newly allocated list element
//

plistElem * plist::newElem(person * p) {
   plistElem * pe = new plistElem;
   pe->data = p->clone();
   pe->next = NULL;
   return pe;
}


//
//  NAME
//    plist::moveToEnd
//
//  DESCRIPTION
//    This function causes the "current" member variable to point to
//    the last element in the list.  This function assumes that the
//    list is not empty.
//
//  PARAMETERS
//    (none)
//
//  RETURNS
//    (none)

void plist::moveToEnd() {
   if (current == NULL) {
      current = head;
      }
   while (current->next != NULL) {
      current = current->next;
      }
   return;
}

//
//  End of file.
//