// Copyright 1994 Brad Pitzel
//
// Feel free to use/distribute/modify as long as credit/copyrights for myself 
// are included.



// This linked list stores POINTERS to the objects in the list..
// Deleting an object from the list using the 'remove' or 'removeAll'
// member functions will remove the linked list entry and delete the object
// pointed to.

#ifndef  __PtrList__
#define  __PtrList__

#include "stdlib.h"
#include "stdio.h"


template <class Type2> class  ItPtrList;
template <class Type3> class  PtrList;


template <class Type1>
class  PtrNode {

       private:
       Type1 *it;
       
       PtrNode<Type1> *next;

       friend class ItPtrList<Type1>;
       friend class PtrList<Type1>;
       };
       



// iterator provides a way to traverse the list of objects safely.
// And - more than one iterator can be active for the same list..
// at the same time..
template <class Type2>
class  ItPtrList {

       private:

       
       // current node in list (to allow iteration thru list)
       PtrNode<Type2>  *currPtr;

       // the one before the current
       PtrNode<Type2>  *prevPtr;

       // head of the list
       PtrNode<Type2>  *headPtr;

       public:

       ItPtrList( PtrList<Type2> & );

       // iteration functions.. allows to to access first, next or
       // last node in list
       Type2 *gotoFirst()  { currPtr=headPtr; prevPtr = NULL; return current(); }
       Type2 *gotoNext();

       // get pointer to current Ptr in list
       Type2 *current();

       };
       
// the Ptrect linked list class
template <class Type3>
class PtrList {
       
       private:
       
       // number of Ptrs in list
       int    size;
       
       // current node in list (to allow iteration thru list)
       PtrNode<Type3>  *currPtr;

       // the one before the current
       PtrNode<Type3>  *prevPtr;

       // head of the list
       PtrNode<Type3>  *headPtr;
       
       // tail of the list
       PtrNode<Type3>  *tailPtr;
      
      
       public:
       
       // construct and destructor
       PtrList();
       ~PtrList();

       // iteration functions.. allows to to access first, next or
       // last node in list
       Type3 *gotoFirst()  { currPtr=headPtr; prevPtr = NULL; return current(); }
       // Type *gotoLast()   { currPtr=tailPtr; prevPtr = ???; return current(); }
       Type3 *gotoNext();

       // get pointer to current Ptr in list
       Type3 *current();
    
       // add a Ptr to the list
       void   add( Type3 * );
       
       // remove current Ptr in list
       void   remove();
       
       void   remove( Type3 * );
       
       
       // remove all Ptrs in list
       void   removeAll();
       
       
       // get size of list
       int    getSize()  { return size; }

       friend class ItPtrList<Type3>;       
       };


//////////////////////// PtrList ////////////////////
template <class Type3> PtrList<Type3>::PtrList()
{
size = 0;

currPtr = NULL;
prevPtr = NULL;
headPtr = NULL;
tailPtr = NULL;
}


/////////////////////// ~PtrList ////////////////////
template <class Type3> PtrList<Type3>::~PtrList()
{
removeAll();
}


/////////////////////// gotoNext /////////////////////
template <class Type3> 
inline Type3 *PtrList<Type3>::gotoNext()
{

// goto next Type3 in list
if (currPtr != NULL ) {
          prevPtr = currPtr;
          currPtr = currPtr->next;
          }
return current();
}


////////////////////// current ///////////////////////
template <class Type3> 
inline Type3 *PtrList<Type3>::current()
{
if (currPtr == NULL) return NULL;

return currPtr->it;
}


//////////////////////  add  /////////////////////////
// Adds a Type3 to the end of the Type3 list
template <class Type3> void PtrList<Type3>::add( Type3 *newPtr )
{

// create the new node in the list

PtrNode<Type3> *newNode = new PtrNode<Type3>;

if (newNode == NULL ) {
        fputs("PtrList::add  Unable to 'new' a PtrNode. \n", stderr );
        }
else    {

        newNode->it   = newPtr;
        newNode->next = NULL;

        // counter for # of nodes in list
        size++;

        // now add the node to the END of the list
        // currPtr (the current node) is preserved

        if (tailPtr==NULL)
             {
             // first one in list
             headPtr = newNode;
             prevPtr = NULL;
             tailPtr = newNode;
             currPtr = newNode;
             }
        else
             {
             tailPtr->next = newNode;
             tailPtr = newNode;
             }

        }
 
}


/////////////////////// remove ///////////////////////
// remove current Type in list
template <class Type3> void PtrList<Type3>::remove()
{

if (headPtr==NULL) fputs("PtrList::remove | Trying to remove in an empty list.\n", stderr );
else
if (currPtr==NULL) fputs("PtrList::remove | Trying to remove with no current Type.\n", stderr );
else {

     // decrement size of list
     size--;


     // Change tail if we are deleting the last object
     if (currPtr==tailPtr)
     		tailPtr = prevPtr;


     if (currPtr==headPtr)
        {
        // deleting from head of list
        headPtr = currPtr->next;

        delete currPtr->it;
        delete currPtr;

        currPtr = headPtr;
        prevPtr = NULL;
	}
     else
        {
        prevPtr->next = currPtr->next;

        delete currPtr->it;
        delete currPtr;

        currPtr = prevPtr->next;
        }

     }

}

/////////////////////// removeAll ////////////////////
template <class Type3> void PtrList<Type3>::removeAll()
{

// iterate thru list, remove each Type
gotoFirst();

while ( current()!=NULL ) {
      remove();
      }

}




//////////////////////// ItPtrList ////////////////////
template <class Type2> ItPtrList<Type2>::ItPtrList( PtrList<Type2> &list)
{
currPtr = NULL;
prevPtr = NULL;
headPtr = list.headPtr;
}

/////////////////////// gotoNext /////////////////////
template <class Type2> Type2 *ItPtrList<Type2>::gotoNext()
{

// goto next Type3 in list
if (currPtr != NULL ) {
          prevPtr = currPtr;
          currPtr = currPtr->next;
          }
return current();
}


////////////////////// current ///////////////////////
template <class Type2> Type2 *ItPtrList<Type2>::current()
{
if (currPtr == NULL) return NULL;

return currPtr->it;
}




///////////////////// removePtr ///////////////////////
template <class Type3> void PtrList<Type3>::remove( Type3 *obj)
{
  gotoFirst();
  while( current() )
    if( current() == obj )
      {
	remove();
	break;
      }
  else
    gotoNext();
}


#endif
