// -*- C++ -*-
/*
   File: TDPList.hh

   Template based Double linked Pointer List

   By Alex Th. de Jong
   March 1995
*/

#pragma interface

#ifndef __TDPList_hh__
#define __TDPList_hh__

// Error codes:
#define E_TDP_NOERROR     0
#define E_TDP_OUTOFRANGE  1
#define E_TDP_NULL        2


/* 
   Template item class which is a placeholder for the 
   pointer to the actual item stored in the list
*/

template<class TDPItem>
class TDPListItem {
 protected:
  friend class TDPList<TDPItem>;
  friend class TDPListIter<TDPItem>;

  TDPItem* item;
  TDPListItem<TDPItem>* next;
  TDPListItem<TDPItem>* prev; 
  TDPListItem(TDPItem* ti){ item=ti, next=0, prev=0; }
  ~TDPListItem(){ delete item; }
};


/* 
   Template for a list iterator
*/

template <class TDPItem>
class TDPListIter {
 protected:
  const TDPList<TDPItem>* ptl;
  TDPListItem<TDPItem>* pti;
  int dn;
 public:
  TDPListIter(const TDPList<TDPItem>& tl){ ptl=&tl; pti=ptl->head; dn=(pti==0) ? 1 : 0; }
  TDPListIter(){ ptl=0, pti=0, dn=0; }
  int set(const TDPList<TDPItem>& tl){ ptl=&tl; pti=ptl->head; return (dn=(pti==0) ? 1 :0); }
  int reset() { pti=(ptl!=0) ? ptl->head : 0;  return (dn=(pti==0) ? 1 :0); }
  int resetToTail() { pti=(ptl!=0) ? ptl->tail : 0; return (dn=(pti==0) ? 1 :0); }
  int done(){ return dn; }
  TDPListIter& operator++(){ if ((pti=pti->next)==0) dn=1; return *this; }  // prefix
  TDPListIter& operator--(){ if ((pti=pti->prev)==0) dn=1; return *this; }
  TDPListIter& operator++(int){ if ((pti=pti->next)==0) dn=1; return *this; }  // postfix
  TDPListIter& operator--(int){ if ((pti=pti->prev)==0) dn=1; return *this; }
  TDPItem* value(){ return pti->item; }
};


/* 
   Template list
   
   N.B. An iterator should be used to access list items
*/

template<class TDPItem>
class TDPList {
 protected:
  friend class TDPListIter<TDPItem>;

  TDPListItem<TDPItem>* head;
  TDPListItem<TDPItem>* tail;
  int size;
 public:
// Default constructor
  TDPList() { size=0, head=0, tail=0; }
// Constructor that takes the first item for the list
  TDPList(TDPItem* ti) { head=tail=new TDPListItem<TDPItem>(ti); size=1; }
// Destructor
  ~TDPList() { clear(); }
// Inserts an item in the list before the item at the given index
  int insert(int, TDPItem*);
// Appends an item after the item at the given index
  int append(int, TDPItem*);
// Appends an item to the end of the list
  int append(TDPItem*);
// Removes the item at the given index
  int remove(int);
// Removes the item at tail
  int removeTail();
// Removes the item with the corresponding item pointer
  int remove(TDPItem*);
// Return the number of items in list
  int length() const { return size; }
// Clears the list and resets its members
  void clear(); 
};


/* 
   Implementation of template list member functions

   N.B. these functions should be placed here in order
   for the compiler to generate code when templates are
   initiated. 
*/

#ifdef TEMPLATE_IMPL

template <class TDPItem>
int TDPList<TDPItem>::remove(int index){
  if (index>=0 && index<size){
    TDPListItem<TDPItem>* tli=head;
    for (int i=0; i<index; i++) tli=tli->next;
    if (tli!=0){
      if (tli->prev!=0) tli->prev->next=tli->next;
      else head=tli->next;
      if (tli->next!=0) tli->next->prev=tli->prev;
      else tail=tli->prev;
      delete tli;
      size--;
      return E_TDP_NOERROR;
    }
  }
  return E_TDP_OUTOFRANGE;
}


template <class TDPItem>
int TDPList<TDPItem>::removeTail(){
  if (tail){
    TDPListItem<TDPItem>* tli=tail;
    tail=tail->prev;
    if (tail) tail->next=0;
    else head=0;
    tli->prev=0;
    delete tli;
    size--;
    return E_TDP_NOERROR;
  }
  return E_TDP_OUTOFRANGE;
}


template <class TDPItem>
int TDPList<TDPItem>::remove(TDPItem* ti){
  if (ti==0) return E_TDP_NULL;
  else {
    TDPListItem<TDPItem>* tli=head;
    while (tli!=0){
      if (tli->item==ti){
        if (tli->prev!=0) tli->prev->next=tli->next;
        else head=tli->next;
        if (tli->next!=0) tli->next->prev=tli->prev;
        else tail=tli->prev;
        delete tli;
        size--;
        return E_TDP_NOERROR;
      }
      tli=tli->next;
    }
  }
  return E_TDP_OUTOFRANGE;
}


template <class TDPItem>
int TDPList<TDPItem>::insert(int index, TDPItem* ti){
  if (ti==0) return E_TDP_NULL; 
  if ((index>0)&&(index<size)){
    TDPListItem<TDPItem>* tli=head;
    TDPListItem<TDPItem>* tliNew=new TDPListItem<TDPItem>(ti);

    for (int i=0; i<index; i++) tli=tli->next;
    if (tli->prev!=0) tli->prev->next=tliNew;
    else head=tliNew;
    tliNew->prev=tli->prev;
    tliNew->next=tli;
    tli->prev = tliNew;
    size++;
    return E_TDP_NOERROR;
  }
  return E_TDP_OUTOFRANGE;
}


template <class TDPItem>
int TDPList<TDPItem>::append(int index, TDPItem* ti){
  if (ti==0) return E_TDP_NULL; 
  if ((index>=0)&&(index<size)){
    TDPListItem<TDPItem>* tli=head;
    TDPListItem<TDPItem>* tliNew=new TDPListItem<TDPItem>(ti);

    for (int i=0; i<index; i++) tli=tli->next;
    if (tli->next!=0) tli->next->prev=tliNew;
    else tail=tliNew;
    tliNew->next=tli->next;
    tliNew->prev=tli;
    tli->next=tliNew;
    size++;
    return E_TDP_NOERROR;
  }
  if (index==size) return append(ti);
  return E_TDP_OUTOFRANGE;
}


template <class TDPItem>
int TDPList<TDPItem>::append(TDPItem* ti){
  if (ti==0) return E_TDP_NULL; 
  TDPListItem<TDPItem>* tli=new TDPListItem<TDPItem>(ti);
  if (tail!=0){
    tail->next=tli;
    tli->prev=tail;
    tail=tail->next;
  }
  else head=tail=tli;
  size++;  
  return E_TDP_NOERROR;
}


template <class TDPItem>
void TDPList<TDPItem>::clear(){
  for (TDPListItem<TDPItem>* tli=tail; tli!=0; tli=tli->prev) delete tli->next;
  delete head;
  head=tail=0;
  size=0;
}

#endif

#endif
