// File: genlist3.C
//
// Implementation of the GenList class using templates
// Version 2: use templates
// Version 3: return TYPE values using a reference parameter
//            add iterator class

#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include "genlist3.h"

//========================================================================
// "Local" functions
//

static void CrashOnNULL(void *, char *) ;

static void CrashOnNULL(void *ptr, char *mesg) {
   if (ptr == NULL) {
      cerr << "CrashOnNULL: " << mesg <<endl ;
      exit(1) ;
   }
}


//========================================================================
// Definition of GenList member functions
//


// Constructor.
//
template <class TYPE>
GenList<TYPE>::GenList() {

   last = &dummy ;
   len  = 0 ;
   cache_status = dirty ;
}


// Destructor. Loop through list and delete each cell.
//
template <class TYPE>
GenList<TYPE>::~GenList() {
   ListCell<TYPE> *ptr, *temp ;

   ptr = dummy.next ;
   while (ptr != NULL) {
      temp = ptr->next ;
      delete ptr ;      // destructor for data must do the right thing
      ptr = temp ;
   }
}


// Copy constructor
//
template <class TYPE>
GenList<TYPE>::GenList(GenList& L) {
   *this = L ;
}


// Assignment operator.  Duplicate the list.
//
template <class TYPE>
GenList<TYPE>& GenList<TYPE>::operator=(const GenList<TYPE>& L) {
    ListCell<TYPE> *ptr, *temp ;

    // self assignment?
    if (this == &L) return *this ;

    // delete old host
    ptr = dummy.next ;
    while (ptr != NULL) {
       temp = ptr->next ;
       delete ptr ;
       ptr = temp ;
    }

    cache_status = dirty ;
    last = &dummy ;
    len = 0 ;

    // copy L item by item
    ptr = L.dummy.next ;
    while (ptr != NULL) {
       temp = new ListCell<TYPE>(ptr->data) ;
       CrashOnNULL(temp, "Out of memory in GenList assignment") ;
       last->next = temp ;
       last = temp ;
       len++ ;
       ptr = ptr->next ;
    }

    return *this ;
}


// Add new item to the end of the list
//
template <class TYPE>
void GenList<TYPE>::append(const TYPE& t) {

   ListCell<TYPE> *newitem = new ListCell<TYPE>(t) ;
   CrashOnNULL(newitem, "Out of memory in GenList append") ;

   last->next =  newitem ;
   last = newitem ;
   len++ ;
   cache_status = dirty ;
}


// Add new item to the front of the list
//
template <class TYPE>
void GenList<TYPE>::prepend(const TYPE& t) {

   ListCell<TYPE> *newitem = new ListCell<TYPE>(t) ;
   CrashOnNULL(newitem, "Out of memory in GenList prepend") ;

   newitem->next = dummy.next ;
   dummy.next = newitem ;

   if (last == &dummy) last = newitem ;

   len++ ;
   cache_status = dirty ;
}


// Remove item from the front of the list
//
template <class TYPE>
int GenList<TYPE>::chop(TYPE &result) {
   ListCell<TYPE> *ptr ;

   if (dummy.next == NULL)  return false ;

   ptr = dummy.next ;
   dummy.next = ptr->next ;

   // check if last item is removed
   if (dummy.next == NULL) last = &dummy ;

   // update info
   len-- ;
   cache_status = dirty ;

   result = ptr->data ;   // uses TYPE assignment
   delete ptr ;
   return true ;
}


// Loop through the list and print each item
//
template <class TYPE>
void GenList<TYPE>::print() const {
   ListCell<TYPE> *ptr ;

   ptr = dummy.next ;
   while (ptr != NULL) {
      cout << ptr->data << " " ;
      ptr = ptr->next ;
   }
}


// Remove every occurrence of an item from the list.
// Items are compared using TYPE comparsion operator.
//
template <class TYPE>
void GenList<TYPE>::remove(const TYPE& t) {
   ListCell<TYPE> *ptr, *temp ;

   ptr = &dummy ;

   while (ptr->next != NULL) {
      if (ptr->next->data == t) {
         temp = ptr->next ;
         ptr->next = temp->next ;
         delete temp ;
         len-- ;
         cache_status = dirty ;
      } else {
         ptr = ptr->next ;
      }
   }

   if (len == 0) last = &dummy ;
}


//========================================================================
// Definition of Iterator member functions
//


template <class TYPE>
Iterator<TYPE>::Iterator(GenList<TYPE>& List)

: L(List)  // initialize GenList reference, does not copy

{
   cache_ptr = &L.dummy ;               // point to first item
   L.cache_status = L.clean ;           // check later if list changed
   good = true ;
}


template <class TYPE>
int Iterator<TYPE>::next(TYPE& result) {

   if (cache_ptr == NULL) return 0 ;    // already at end of list

   cache_ptr = cache_ptr->next ;
   if (cache_ptr == NULL) return 0 ;    // end of list

   if (L.cache_status == L.dirty) {     // cache invalid
      good = false ;
      return 0 ;
   }

   result = cache_ptr->data ;           // All OK
   return 1 ;
}


template <class TYPE>
int Iterator<TYPE>::set(const TYPE& t) {

   if (cache_ptr == NULL || L.cache_status == L.dirty) {
      good = false ;  // something went wrong
      return 0 ;
   }

   cache_ptr->data = t ;
   return 1 ;
}
