// list.h -- Declarations for the list library
 
#ifndef List2_Include
#define List2_Include

#include <stdlib.h> 
#include <iostream.h>
#include <fstream.h>

#define TRUE 1
#define FALSE 0 

#ifdef GRRMUD
extern void log(const char* msg);
#endif

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 

template <class T> class Cell;
 
template <class T> class List
{
   friend class Cell<T>;
      //
      // Cell is a safe pointer to a list node
   
   struct Node {
      Node *Prev;
      Node *Next;
      T     Item; // Node holds an item of parameterized type T
   };//Node


   Node *Header;

public:

   List  (const List<T> &L) {
      Cell<T> cll(L); 
      T ptr;
      Header = new Node;

      if (!Header) {
#ifdef GRRMUD
         log("ERROR:  out of Memory: List2 constructor, exiting!\n");
#endif
         exit (1);
      }//if

      Header->Item = (T)(NULL);
      Header->Next = Header;
      Header->Prev = Header;
  
      while (ptr = Next(cll)) { 
         Put(ptr, *this);
      }//while
    } // copy constructor


    List  (const T &Nil) {
       Header = new Node;
       if (!Header) { 
#ifdef GRRMUD
          log("ERROR:  out of mem, list constructor, exiting!\n");
#endif
          exit (1);
       }//if
       Header->Item = Nil;
       Header->Next = Header;
       Header->Prev = Header;
    } // constructor


    List  () {
       Header = new Node;
       if (!Header) { 
#ifdef GRRMUD
          log("ERROR:  out of mem, list constructor, exiting!\n");
#endif
          exit (1);
       }//if
       Header->Item = (T)(NULL);
       Header->Next = Header;
       Header->Prev = Header;
    } // constructor


   // Destructor for List<T> -- Destroy the list, linear
   // DOES NOT delete the items it points too.
   ~List () { 
      this->Clear();
      delete Header;
   } //destructor
 

   
   List<T> &operator= (const List &L) {
 
      if (this != &L) { // Don't copy yourself
         this->Clear();       

         Cell<T> cll(L);
         T datum; 

         while (datum = Next(cll)) {
            Put(datum, *this);
         }//for
      }//if
      return *this;
   }//assignment operator

                 /* functions */

   void Clear();
 
   
   friend void    InsertBefore (const T, const Cell<T> &);
   friend void    InsertAfter  (const T, const Cell<T> &);
   friend void    DeleteArray  (List<T> &); 
   friend void    LoseData     (const T, List<T> &); 
   friend short   SubstituteData(const T targ, const T source, List<T>& L,
                  int j);
   friend short   HaveData     (const T, List<T> &); 
   friend int     DataCount    (const T, List<T> &); 
   friend void    Eject        (const Cell<T> &);
   friend void    Inject       (const Cell<T> &);
 
   friend void    Push   (const T, List<T> &);     // on front
   friend void    Put    (const T, List<T> &);     // on back
   friend void    GainData    (const T &, List<T> &);     
   friend T       Pull  (List<T> &);  //gets data off front
   friend T       Drag  (List<T> &);  //gets data off rear
   friend T       Rear  (const List<T> &);  //returns data on rear
   friend T       Top   (const List<T> &L);  //returns data on front
   
   friend Cell<T> Head  (const List<T> &);
   friend T       Next (Cell<T> &);                //
   friend T       Prev (Cell<T> &);                //
   friend T       Item (const Cell<T> &);          //
   friend T       Lose (Cell<T> &); //moves to Next, deletes Prev, returns
                                    //data of the Next cell

   friend void        clear_ptr_list(List<T> &);  //DOES delete the data
   friend short       IsEmpty     (const List<T> &);
   friend int         Size        (const List<T> &);
};
 
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
template <class T> class Cell {
   friend class List<T>;
   
   List<T>::Node *Node;
   
public:
   
   // Constructors
   //
   Cell () { Node = NULL; }
   Cell (const List<T>& L) { Node = L.Header; }
   Assign(const T data) {
      if (!Node || !data) {
#ifdef GRRMUD
         log("ERROR:  Node or data is NULL.\n");
#endif
         exit(2);
      }//if
      Node->Item = data;
   }//Assign

   // Global friend functions
   //

   friend void    InsertBefore (const T, const Cell<T> &);
   friend void    InsertAfter  (const T, const Cell<T> &);
   friend void    DeleteArray  (List<T> &); 
   friend void    LoseData     (const T, List<T> &); 
   friend short   SubstituteData(const T targ, const T source, List<T>& L,
                  int j);
   friend short   HaveData     (const T, List<T> &); 
   friend int     DataCount    (const T, List<T> &); 
   friend void    Eject        (const Cell<T> &);
   friend void    Inject       (const Cell<T> &);
 
   friend void    Push   (const T, List<T> &);     // on front
   friend void    Put    (const T, List<T> &);     // on back
   friend void    GainData    (const T &, List<T> &);     
   friend T       Pull  (List<T> &);  //gets data off front
   friend T       Drag  (List<T> &);  //gets data off rear
   friend T       Rear  (const List<T> &);  //returns data on rear
   friend T       Top   (const List<T> &L);  //returns data on front
   
   friend Cell<T> Head  (const List<T> &);
   friend T       Next (Cell<T> &);                //
   friend T       Prev (Cell<T> &);                //
   friend T       Item (const Cell<T> &);          //
   friend T       Lose (Cell<T> &); //moves to Next, deletes Prev, returns
                                    //data of the Next cell

   friend short       IsEmpty     (const List<T> &);
   friend int         Size        (const List<T> &);
};
 
 
/*  Ugly, but necessary for some older compilers. */

#include "list2.cc"

#endif
