// list2.cc -- Declarations for the list2 library
//  Coded by Ben Greear.
//  Everyone is welcome to use this class, free of all charges, just
//  leave my name here. :)


//  This templated list works only on pointers right now, it could, however
//  be changed to include ALL items easily.  There may be a few bugs left,
//  so be careful.  If you have any questions, write me at:  
//  greear@cs.uga.edu
//  Happy coding, Ben Greear
//  Also, see my web page at:  http://www.cs.uga.edu/~greear

 
#include "list2.h"

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

#define TRUE 1
#define FALSE 0 

#ifdef GRRMUD
extern void log(const char* msg);
extern int do_shutdown; //grrmud.cc, kinda a hack
#endif

/*  FRONT--
    Returns the Item contained at the BEGINNING of the list, it
    DOES NOT delete the item from the list.  */

template <class T> T Front (const List<T> &L) {
   return L.Header->Next->Item; 
}//front


/*  PULL--
    Returns the Item contained at the BEGINNING of the list, it
    DOES delete the item from the list.  */

template <class T> T Pull (List<T> &L) {
   Cell<T> cll(L);
   T ret = Next(cll);
   
   if (ret) {
      Lose(cll);
   }//if
   return ret;
}//Pull
 

/*  DRAG--
    Returns the Item contained at the END of the list, it
    DOES delete the item from the list.  */

template <class T> T Drag (List<T> &L) {
   Cell<T> cll(L);
   T ret = Prev(cll);
   if (ret) {
      Lose(cll);
   }//if
   return ret;
}//Drag


/*  REAR--  Returns the Item contained at the END of the list, it
    DOES NOT delete the item from the list.  */

template <class T> T Rear (const List<T> &L) {
   return L.Header->Prev->Item; 
}//rear
 

/*  TOP--  Same as "Front", returns the FIRST Item, List is unchanged. */

template <class T> T Top (const List<T> &L) {
   return L.Header->Next->Item; 
}//top
 

/*  NEXT--  Next(cell)  
    This function sets "cell" equal to the next cell in the list and
    returns this cell's Item.  */

template <class T> T Next (Cell<T> &P) {
   P.Node = P.Node->Next;
   return P.Node->Item;
}//next

 
/*  HEAD--  Returns cell pointing to the Header of the List. */

template <class T> Cell<T> Head(const List<T> &Lst) {
   Cell<T> C;
   C.Node = Lst.Header;
   return C;
}//head


/*  PREV--   Prev(cell)  
    This function sets "cell" equal to the previous cell in the list
    and returns the new cell's Item.  */

template <class T> T Prev (Cell<T> &P) {
   P.Node = P.Node->Prev;
   return P.Node->Item;
}//prev
 

/*  ITEM-- returns the data stored in the target cell, the cell
    is NOT changed. */

template <class T> T Item (const Cell<T> &P) {
   return P.Node->Item;
}//Item
 
 
/*  CLEAR--   deletes every node in a List (except the header node
    of course), DOES NOT delete data pointed to */

template <class T> void  List<T>::Clear() {
   Cell<T> cll(*this);
   T ptr = Next(cll);
   while (ptr) {
      ptr = Lose(cll);
   }//while
   if (!Header) {
#ifdef GRRMUD 
      log("ERROR:  HEADER NULL in Clear.\n");
#endif
      ;
   }//if
}// clear


template <class T> void clear_ptr_list(List<T>& L) {
   Cell<T> cll(L);
   T tmp = Next(cll);
   while (tmp) {
      delete tmp;
      tmp = Lose(cll);
   }//while
}//


/*  LOSE   Deletes a node, sets cell equal to Next cell,  
           returns what the new cell contains.  */

template <class T> T  Lose (Cell<T> &P) {
   class List<T>::Node* node_ptr = P.Node;    
   
   P.Node->Prev->Next = P.Node->Next;
   P.Node->Next->Prev = P.Node->Prev;
   
   P.Node = P.Node->Next;
   if (node_ptr->Item)
      delete node_ptr;
   return P.Node->Item;      
}// Lose


/*  LOSEDATA  finds and cuts the node with the specified data in it out 
    of the list.  Only cuts ONE instance, not multiple, if they exist. */

template <class T> void LoseData(const T data, List<T> &L) {
   Cell<T> cell(L);
   T ldata;
   if (!data) {
#ifdef GRRMUD
      log("ERROR:  Tried to delete NULL from list.\n"); 
#endif
      return;
   }//if

   ldata = Next(cell);
   while (ldata) {
      if (ldata == data) {
         Lose(cell);  //this WILL NOT delete the item pointed to.
         return;
      }//if
      ldata = Next(cell);
   }//while
}//LoseData   


// HAVE_DATA //

template <class T> short HaveData(const T data, List<T> &L) {
   Cell<T> cell(L);
   T ldata;

   while (ldata = Next(cell)) 
      if (ldata == data) {
         return TRUE;
      }//if
   return FALSE;
}//HaveData   


// Substitute_Data //
/* If it doesn't find the target data, it will insert anyway 
   (at the beginning).  It returns FALSE if no substitution was made,
   TRUE otherwise. */
   
template <class T> short SubstituteData(const T targ, const T source, 
         List<T> &L, int j) {
   Cell<T> cell(L);
   T ldata;
   int count = 0;

   while (ldata = Next(cell)) { 
      if (ldata == targ) {
         count++;
         if (count == j) {
            cell.Node->Item = source;
            return TRUE;
         }//if
      }//if
   }//while
   Put(source, L);
   return FALSE; //no substitution
}//SubstituteData   


// DATA_COUNT //

template <class T> int DataCount(const T data, List<T> &L) {
   Cell<T> cell(L);
   T ldata;
   int retval = 0;

   while (ldata = Next(cell)) 
      if (ldata == data) {
         retval++;
      }//if
   return retval;
}//DataCount   



// WARNING:  this deletes the arrays pointed too, mainly for char*'s
// DELETE_ARRAY:  only call this on arrays of things!!!
// This kills the entire list, basically a destructor.

template <class T> void DeleteArray(List<T> &L) {
   class List<T>::Node* node_ptr;
   while (L.Header->Next != L.Header) {
      node_ptr = L.Header->Prev;
      L.Header->Prev = L.Header->Prev->Prev;
      L.Header->Prev->Prev->Next = L.Header;        
      delete[] node_ptr->Item;
      delete node_ptr;
   }//while
   delete L;
}//DeleteArray   


/*  ISEMPTY--   Returns 1 if List is empy, 0 if not.  */

template <class T> short IsEmpty     (const List<T> &L) {
   if (!L.Header) {
#ifdef GRRMUD
      log("ERROR:  L.Header is NULL, isempty\n");
#endif
      return TRUE;  //not a good solution..but keeps it running a bit longer
   }//if
   return (L.Header->Next == L.Header);
}//IsEmpty


// INSERTBEFORE -- Insert an item into a list before a given cell

template <class T> void InsertBefore (const T I, const Cell<T> &P) {
   List<T>::Node *N = new List<T>::Node; 
   if (!N) {
#ifdef GRRMUD
      log("ERROR, out of Memory trying to allocate a cell.\n");
#endif
      exit (1);
   }//if
   N->Item = I;
   N->Prev = P.Node->Prev;
   N->Next = P.Node;
   P.Node->Prev->Next = N;
   P.Node->Prev = N;
}// insert before
 


/*  INSTERT_AFTER-- Insert an item into a list after a given cell. */

template <class T> void InsertAfter (const T I, const Cell<T> &P) {
   List<T>::Node *N = new List<T>::Node; 
   N->Item = I;
   N->Prev = P.Node;
   N->Next = P.Node->Next;
   P.Node->Next = N;
   N->Next->Prev = N;
}// insert after
 
 

/* WARNING: the following two functions can cause memory leaks 
   if used wrongly.  */

/*  EJECT--   logically deletes the cell from its list, but it
    does so in a way which is extremely cheap and easy to reverse
    with its alter-ego "Inject".    */

template <class T> void Eject (const Cell<T> &P) {
   P.Node->Prev->Next = P.Node->Next;
   P.Node->Next->Prev = P.Node->Prev;
}// Eject
 
 
/*  INJECT  --takes its target and re-inserts it into its list,
    for this to work, the target must have been previously "Eject"ed from
    the list.   */

template <class T> void Inject (const Cell<T> &P) {
   P.Node->Prev->Next = P.Node;
   P.Node->Next->Prev = P.Node;
}// Inject
 

 
// Put -- Put an item onto the rear of a list

template <class T> void Put (const T I, List<T> &L) {
   Cell<T> C(L);
   if (!I) {
#ifdef GRRMUD
      log("ERROR:  Null trying to be PUT, exiting.\n");
      do_shutdown = TRUE;
#endif
      exit(2);
   }//if
   else {
      InsertBefore(I, C);
   }//else
}//put


// This will ONLY insert the data if it is not already in the list.

template <class T> void GainData (const T I, List<T> &L) {
   
   if (!HaveData(I, L)) {
      Push(I, L);
   }//if
}//GainData



/*  PUSH    
 *   This function adds an Item onto the FRONT of the list.  */

template <class T> void Push (const T I, List<T> &L) {
   Cell<T> C(L);
   if (!I) {
#ifdef GRRMUD
      log("ERROR:  NULL trying to be PUSHED, exiting.\n");
      do_shutdown = TRUE;
#endif
      exit(2);
   }//if
   InsertAfter(I, C);
}//push
 
 
/*  SIZE--  Returns the number of cells contained in a List.  */

template <class T> int   Size (const List<T> &L) {
   class List<T>::Node* node_ptr = L.Header->Next;
   int count = 0;
   
   while (node_ptr != L.Header) {
      count++;
      node_ptr = node_ptr->Next;
   }//while
   return count;
}//size

