/*
 * ===========================
 * VDK Visual Develeopment Kit
 * Version 0.4
 * October 1998
 * ===========================
 *
 * Copyright (C) 1998, Mario Motta
 * Developed by Mario Motta <mmotta@guest.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#ifndef DLIST_H
#define DLIST_H
// just a cosmetic capitalizing (suggestion by Ionutz Borcoman)
#define VDKListIterator VDKListiterator

/*
  ============
  VDKItem class
  ============
  */
template <class T> class VDKItem 
{

 public:
  T* x;
  VDKItem* next,*prev;
  VDKItem(T* x): x(x), next((VDKItem<T>*) 0),prev((VDKItem<T>*)0) 
    {
    }
~VDKItem() 
  {
  }
};
/*!
  \class VDKList
  \brief Provides a reference semantic double linked list

  VDKList has a reference semantic, all managed objects are pointers to
  their original values. This calls is widely used for vdk internals.
  \par Implementation notes
  I suggest to use typedef like this:
  \code
  typedef VDKList<someClass> SomeClassList;
  typedef VDKListIterator<someClass> SomeClassListIterator;
  \endcode
*/

template <class T> class VDKList 
{
  
  VDKItem<T>* head,* tail;
  int count;
  
  // append to list
  void addToTail(VDKItem<T>* i) 
    {
      if(! head) head = tail = i;
      else { tail->next = i; i->prev=tail; tail = i; }
      count++;
    }
  // over head loading
  void addToHead(VDKItem<T>* i) 
    {
      if(! head) head = tail = i;
      else { head->prev = i; i->next = head; head = i; }
      count++;
    }
  // insert at pos
  void insertVDKItem(VDKItem<T>* i, int pos);
  
  // fetch an VDKItem at <n> position
  VDKItem<T>* fetch(int n);  
  
  // assign VDKItems to container
  void assign(VDKList& l);
  // on reference semantic copy-assign is prohibited 
  VDKList(VDKList& c) 
    {
      count = 0;
      head = tail = (VDKItem<T>* ) 0;
      assign(c);
    }
  
  VDKList& operator=(VDKList<T>& l) 
    {
      // avoid l = l;
      if(this != &l) { flush(); assign(l); }
      return *this;
    }

  /* class interface methods */
 public:
  /*!
    Constructor, makes an empty lis
  */
  VDKList() : head(0),tail(0),count(0) {}  
  /*!
    Destructor. VDKList does not owns object pointed thus not provide 
    to their destruction. Destruction of pointed objects must be explicit.
    \code
    // delete pointed objects
    SomeClassListIterator li(list);
    for(li;li++)
    delete li.current();
    \endcode
   */
  ~VDKList() { flush(); } 
  /*!
    Appends a pointer to type T to the list. To mantain
    reference integrity no same pointer will be added twice.
    \param t type T pointer
  */
  void add(T* t) 
    { 
      if(!find(t))
	 addToTail(new VDKItem<T>(t)); 
    
  /*!
    Prepends a pointer to type T to the list. To mantain
    reference integrity no same pointer will be added twice.
    \param t type T pointer
  */}
  void addH(T* t) 
    { 
      if(! find(t))
	addToHead(new VDKItem<T>(t)); 
    }
  /*!
    Insert a pointer to type T to the list. To mantain
    reference integrity no same pointer will be added twice.
    \param t type T pointer
    \param pos ordinal position
  */
  void insertAt(T* t, int pos)
    { 
      if(!find(t))
	insertVDKItem(new VDKItem<T>(t),pos); 
    }
  /*!
    Membership operator, return NULL if not found
    \param x address to be searched for
   */
  T* find(T* x);
  /*!
    \internal
   */
  T* listhead() { return fetch(0)->x; }
  /*! 
    find position of type<T> object, returns ordinal position, -1 on failure
    \param x address to be searched for
  */
  int at(T* x);
  /*!
    Ordinal access operator
   */
  T* operator[](int n) { return fetch(n)->x; }
  /*!
    Remove a pointer from list
    \param x address to be removed
   */
  int  remove(T* x);
  /*!
    Returns list size
   */
  int size() { return count; }
  /*!
    Flushes list
   */
  void flush();
  /*!
    \internal
   */
  VDKItem<T>* Head() { return head; }
  /*!
    \internal
   */
  VDKItem<T>* Tail() { return tail; }
};

/*!
  \class VDKListiterator
  \brief Provides a VDKList iterator
*/
template <class T> class VDKListiterator 
{

  VDKItem<T> *head,*tail,*p;
 public:
  /*!
    Constructor
    \param a VDKList reference
   */
  VDKListiterator(VDKList<T>& c) { p = head = c.Head(); tail = c.Tail(); }
  /*!
    Destructor
   */
  virtual ~VDKListiterator() {}
  /*!
    Incremental operator (postfix)
  */
  void operator++() { p = p->next; }
  /*!
    Incremental operator (infix)
  */
  void operator++(int) { p = p->next; }
  /*!
    Decremental operator (postfix)
  */
  void operator--() { p = p->prev; }
  /*!
    Decremental operator (infix)
  */
  void operator--(int) { p = p->prev; }
    /*!
    Goes to list head
   */
  void first() { p = head; }
  /*!
    Goes to list tail
   */
  void last() { p = tail; }
  /*!
    Return 0 at the list end
   */
  operator int() { return p != (VDKItem<T>*) 0; }
  /*!
    Returns currently pointed object
   */
  T* current() { return p->x; }
  /*!
    \internal
   */
  VDKItem<T>* Next(VDKItem<T> *t) { return t->next;}
  /*!
    \internal
   */
  VDKItem<T>* Head() { return head; }
  /*!
    \internal
   */
  T* Now(VDKItem<T> * t) { return t->x; } 
  /*!
    Rewind iterator
  */
  void restart() { p = head; }
};
//	 								
//NON-INLINE MEMBER FUNCTIONS
/*=======================
  PRIVATE:
  assign VDKItems copyng them
  from another list
  =======================*/
template <class T>
void VDKList<T>::assign(VDKList<T>& l) 
{
  VDKListiterator<T> ci(l);
  while(ci) { add(ci.current()); ci++; }
}

/*==========================
  PRIVATE:
  fetch VDKItem<T> at n position
  ===========================*/
template <class T>
VDKItem<T>* VDKList<T>::fetch(int n) {
  int t = 0;
  if(n >= count || n < 0) return (VDKItem<T>*) 0;
  VDKItem<T>* p = head;
  for( ;p && (t < n) ; t++, p = p->next);
  return p;
}
/*================================
  PRIVATE:
  find ordinal position of VDKItem
  containing a type<T> object,
  return -1 if not found
  ================================*/
template <class T>
int VDKList<T>::at(T* x) {
  register int t = 0;
  VDKItem<T>* p = head;
  for(; p && (p->x != x);p = p->next,t++) ;
  return p ? t : -1;
}
/*===========
  flushes list
  ============*/
template <class T>
void VDKList<T>::flush() 
{
  VDKItem<T>*p = head;
  VDKItem<T>*p1;
  while(p) {
    p1 = p->next;
    delete p;
    p = p1;
  }
  head = tail = 0;
  count = 0;
}
/*
  ============================
  find(type<T>) , iterate
  over container to find
  an object. 
  hint: compare pointers only..
  so is good only for identities.. 
  ============================
*/
template <class T>
T* VDKList<T>::find(T* x) {
  VDKItem<T>* p;
  for(p = head; p && (p->x != x); p = p->next) ;
return p ? p->x : (T*) 0;
}

/*
============================
remove a type<T>.
Return a 1 or 0 (not removed)
==============================
*/
template <class T>
int VDKList<T>::remove(T* x) 
{
  VDKItem<T>* cur;
  int n = at(x);
  // object not found
       if(n < 0) return 0;
       else cur = fetch(n);
  // removing head
       if(cur == head) {
	 head = cur->next;
	 // one element list
	      if(head != (VDKItem<T>*) 0) head->prev = (VDKItem<T>*) 0;
	      else tail = (VDKItem<T>*) 0;
       }
       else { // remove tail or intermediate element
		   cur->prev->next = cur->next;
       if(cur != tail) cur->next->prev = cur->prev;
       // remove tail
	    else tail = cur->prev;
       }
  delete cur;
  count--;
  return 1;
}
/*
insert an item a <t> position
*/
template <class T>
void VDKList<T>::insertVDKItem(VDKItem<T>* i, int pos)
{
int t = 0;
VDKItem<T>* p = NULL;
for(p = head; p && t < pos; p=p->next,t++)
    ;
if(!p)
 addToTail(i);
else if(p->prev)
    {
    p->prev->next = i;
    i->prev = p->prev;
    p->prev = i;
    i->next = p;
    count++;
    }
else
    addToHead(i);
}

#endif





