/*****************************************************************************/
/*                                                                           */
/*                           OCO SOURCE MATERIALS                            */
/*                             IBM CONFIDENTIAL                              */
/*                                    OR                                     */
/*                        IBM CONFIDENTIAL RESTRICTED                        */
/*            WHEN COMBINED WITH THE AGGREGATED OCO SOURCE MODULES           */
/*                           FOR THIS PROGRAM PRODUCT                        */
/*                                                                           */
/*      VisualAge Generator Server for OS/2, AIX, HP-UX, and Windows NT      */
/*                          Version 3.0  5697-C28                            */
/*                    (C) COPYRIGHT IBM CORP. 1994,1997                      */
/*                                                                           */
/*****************************************************************************/
// List base class

#ifndef FCWLIST_H
#define FCWLIST_H

// ------------------------------------------------------------
// extrace from EFKSVLST.HPP for List processing support
// ------------------------------------------------------------

class sequence;

class seqnode
{
  protected:
     seqnode();

    seqnode * pNext, * pPrev;

    friend class cursor;
    friend class sequence;
};

inline seqnode :: seqnode() :
   pPrev( NULL ),
   pNext( NULL )
{}


class cursor
{
  public:

    seqnode * pCurNode() const;

    cursor (const sequence&);
    cursor (const cursor&);
    seqnode * element();

    int setToFirst();
    int setToLast();
    int setToNext();
    int setToPosition(int);
    int setToPrevious();
    void clearPosition();

    int isFirst() const;
    int isLast() const;
    int isValid() const;

  protected:

    const sequence * const pSeq;
    seqnode * pElement;

  friend class sequence;
};

class sequence
{
  public:

    int numberOfElements()     const;
    int isEmpty()              const;
    int isFirst(const cursor&) const;
    int isLast(const cursor&)  const;

  protected:

    sequence ();

    void addAsFirst (seqnode*);
    void addAsLast (seqnode*);
    void addAsPrevious (seqnode*, seqnode*);
    void addAsNext     (seqnode*, seqnode*);

    seqnode * elementAtPosition(int) const;

    seqnode * lastElement() const;
    seqnode * firstElement() const;

    void unlinkNode(seqnode*);

    int numElements;
    seqnode * pFirst, * pLast;

    friend class cursor;
};

inline sequence::sequence() : numElements(0), pFirst(0), pLast(0)
{
}

inline int sequence::numberOfElements() const
{
  return numElements;
}

inline int sequence::isEmpty() const
{
  return (pFirst == 0) ? 1 : 0;
}

inline int sequence::isFirst(const cursor& c) const
{
  return (pFirst == c.pElement) ? 1 : 0;
}

inline int sequence::isLast(const cursor& c) const
{
  return (pLast == c.pElement) ? 1 : 0;
}

inline seqnode * sequence::lastElement() const
{
  return pLast;
}

inline seqnode * sequence::firstElement() const
{
  return pFirst;
}

inline cursor::cursor (const sequence& L) : pSeq(&L), pElement(pSeq -> pFirst)
{
}

inline cursor::cursor (const cursor& C) : pSeq(C.pSeq), pElement(C.pElement)
{
}

inline seqnode * cursor::pCurNode() const
{
  return pElement;
}

inline seqnode * cursor::element()
{
  return pElement;
}

inline int cursor::setToFirst()
{
  pElement = pSeq -> pFirst;
  return pElement ? 1 : 0;
}

inline int cursor::setToLast()
{
  pElement = pSeq -> pLast;
  return pElement ? 1 : 0;
}

inline int cursor::setToNext()
{
  if (pElement)
    pElement = pElement -> pNext;
  return pElement ? 1 : 0;
}

inline int cursor::setToPrevious()
{
  if (pElement)
    pElement = pElement -> pPrev;

  return pElement ? 1 : 0;
}

inline void cursor::clearPosition()
{
  pElement = 0;
}

inline int cursor::isFirst() const
{
  return (pElement == pSeq -> pFirst) ? 1 : 0;
}

inline int cursor::isLast() const
{
  return (pElement == pSeq -> pLast) ? 1 : 0;
}

inline int cursor::isValid() const
{
  return pElement ? 1 : 0;
}

// ************************************
// template implemenation for Sequence
// ************************************

template <class T> class Sequence;

template <class T>
class Cursor : public cursor
{
  public:
    Cursor (const Sequence<T>&);
    Cursor (const Cursor<T>&);
    T const& element();
};

template <class T>
class SeqNode : public seqnode
{
  private:

    T data;

  public:

    SeqNode (T const&);
    ~SeqNode();

    friend class Sequence<T>;
    friend class Cursor<T>;
};

template <class T>
class Sequence : public sequence
{
  public:

    Sequence();
    Sequence(const Sequence<T>&);
    ~Sequence();

    T const& elementAtPosition(int) const;
    void add(T const&);
    void addAsFirst(T const&);
    void addAsLast(T const&);
    void addAsPrevious(T const&, const Cursor<T>&);
    void addAsNext    (T const&, const Cursor<T>&);

    T const& lastElement() const;
    T const& firstElement() const;

    void replaceAt(Cursor<T>&, T const&);
    void removeAt(Cursor<T>&);

    void clear();
};

template <class T>
inline void Sequence<T>::clear()
{
  // this is quicker than calling removenode for each element

  SeqNode<T> * pNode, * pNextNode;

  for (pNode = (SeqNode<T>*) pFirst; pNode; pNode = (SeqNode<T>*) pNextNode)
  {
    pNextNode = (SeqNode<T>*) pNode->pNext;
    delete pNode;
  }

  pFirst = pLast = 0;
  numElements = 0;
}


template <class T>
inline Cursor<T>::Cursor (const Sequence<T>& L) : cursor(L)
{
}

template <class T>
inline Cursor<T>::Cursor (const Cursor<T>& L) : cursor(L)
{
}

template <class T>
inline T const& Cursor<T>::element()
{
  return ( (SeqNode<T> *) cursor::element() ) -> data;
}

// SeqNode implementations

template <class T>
inline SeqNode<T>::SeqNode (T const& a) : data(a)
{
}

template <class T>
inline SeqNode<T>::~SeqNode ()
{
}

// Sequence implementations

template <class T>
inline Sequence<T>::Sequence () : sequence ()
{
}

template <class T>
inline Sequence<T>::Sequence (const Sequence<T>& seq) : sequence ()
{
  Cursor<T> cur(seq);

  for (cur.setToFirst(); cur.isValid(); cur.setToNext())
    addAsLast(cur.element());
}

template <class T>
inline Sequence<T>::~Sequence ()
{
  clear();
}

template <class T>
inline T const& Sequence<T>::firstElement() const
{
  // possible error here

  return ((SeqNode<T>*) sequence::firstElement()) -> data;
}

template <class T>
inline T const& Sequence<T>::lastElement() const
{
  // possible error here

  return ((SeqNode<T>*) sequence::lastElement()) -> data;
}

template <class T>
inline T const& Sequence<T>::elementAtPosition(int i) const
{
  seqnode * p = sequence::elementAtPosition(i);

  // possible error here

  return ( (SeqNode<T> *) p ) -> data;
}

template <class T>
inline void Sequence<T>::add(T const& a)
{
  sequence :: addAsLast (new SeqNode<T>(a));
}

template <class T>
inline void Sequence<T>::addAsFirst(T const& a)
{
  sequence :: addAsFirst (new SeqNode<T>(a));
}

template <class T>
inline void Sequence<T>::addAsLast (T const& a)
{
  sequence :: addAsLast (new SeqNode<T>(a));
}

template <class T>
inline void Sequence<T>::addAsPrevious (T const& a, const Cursor<T>& c)
{
  sequence :: addAsPrevious (new SeqNode<T>(a), c.pCurNode() );
}

template <class T>
inline void Sequence<T>::addAsNext     (T const& a, const Cursor<T>& c)
{
  sequence :: addAsNext     (new SeqNode<T>(a), c.pCurNode() );
}

template <class T>
inline void Sequence<T>::replaceAt(Cursor<T>& curs, T const& a)
{
  ((SeqNode<T> *) curs.pCurNode()) -> data = a;
}

template <class T>
inline void Sequence<T>::removeAt(Cursor<T>& curs)
{
  if (curs.pCurNode())
  {
    SeqNode<T> * pNode = (SeqNode<T> *) curs.pCurNode();
    sequence::unlinkNode(pNode);
    curs.clearPosition();
    delete pNode;
  }
}

// ************************************
// template implemenation for IESequence
// ************************************

template <class T>
class EqualitySequence : public Sequence<T>
{
  public:

    EqualitySequence();
    EqualitySequence(const EqualitySequence<T>&);

    void addAsFirst(T const&);
    void addAsLast(T const&);
    void addAsPrevious(T const&, const Cursor<T>&);
    void addAsNext    (T const&, const Cursor<T>&);

    int contains(T const&);
};

template <class T>
inline void EqualitySequence<T>::addAsFirst(T const& a)
{
  if (! contains(a))
    Sequence<T> :: addAsFirst (a);
}

template <class T>
inline void EqualitySequence<T>::addAsLast (T const& a)
{
  if (! contains(a))
    Sequence<T> :: addAsLast (a);
}

template <class T>
inline void EqualitySequence<T>::addAsPrevious (T const& a, const Cursor<T>& c)
{
  if (! contains(a))
    Sequence<T> :: addAsPrevious (a, c);
}

template <class T>
inline void EqualitySequence<T>::addAsNext     (T const& a, const Cursor<T>& c)
{
  if (! contains(a))
    Sequence<T> :: addAsNext (a, c);
}

template <class T>
inline int EqualitySequence<T>::contains(T const& el)
{
  Cursor<T> cur(*this);

  for (cur.setToFirst(); cur.isValid(); cur.setToNext())
    if (cur.element() == el)
      return 1;

  return 0;
}

template <class T>
inline EqualitySequence<T>::EqualitySequence () : Sequence<T> ()
{
}

template <class T>
inline EqualitySequence<T>::EqualitySequence (const EqualitySequence<T>& seq) : Sequence<T> (seq)
{
  Cursor<T> cur(seq);

  for (cur.setToFirst(); cur.isValid(); cur.setToNext())
    Sequence<T> :: addAsLast (cur.element());
}

// ************************************
// template implemenation for IESequence
// ************************************

template <class T>
class OrderedSequence : public Sequence<T>
{
  private:

    int (*pCompare) ( T const&, T const&);

    // these add functions are disabled for ordered squences
    void addAsFirst(T const&) {}
    void addAsLast(T const&) {}
    void addAsPrevious(T const&, const Cursor<T>&) {}
    void addAsNext    (T const&, const Cursor<T>&) {}

  public:

    OrderedSequence(int (*) (T const&,T const&));
    OrderedSequence(const OrderedSequence<T>&);

    void add(T const&);
};

template <class T>
inline void OrderedSequence<T>::add (T const& el)
{
  Cursor<T> cur(*this);

  for (cur.setToFirst(); cur.isValid(); cur.setToNext())
  {
    if ( (*pCompare) (el, cur.element()) < 0)
    {
      Sequence<T> :: addAsPrevious (el, cur);
      return;
    }
  }

  Sequence<T> :: addAsLast (el);
}

template <class T>
inline OrderedSequence<T>::OrderedSequence ( int (*pComp) (T const&, T const&))
  : Sequence<T> (), pCompare(pComp)
{
}

template <class T>
inline OrderedSequence<T>::OrderedSequence (const OrderedSequence<T>& seq)
  : Sequence<T> (seq)
{
  pCompare = seq.pCompare;

  Cursor<T> cur(seq);

  for (cur.setToFirst(); cur.isValid(); cur.setToNext())
    Sequence<T> :: addAsLast (cur.element());
}

// *****************************
// stack implementation
// *****************************

class stacknode
{
  protected:
    stacknode();
    stacknode *pNext;

  friend class stack;
};

inline stacknode :: stacknode() :
   pNext( NULL )
{}

class stack
{
  public:

    void  push(stacknode *);
    stacknode *pop();
    stacknode *peek();
    int isEmpty() const;
    void clear();
    int numberOfElements()     const;

  protected:
    stack();
    stacknode *pTop;
};

inline stack::stack() : pTop(0)
{
}

inline int stack::isEmpty() const
{
  return (pTop == 0) ? 1 : 0;
}

// *****************************
// template stack implementation
// *****************************

template <class T> class IStack;

template <class T>
class StackNode : public stacknode
{
  private:

    T data;

  public:

    StackNode(T const&);

    friend IStack<T>;
};

template <class T>
inline StackNode<T>::StackNode(T const& a) :
   data(a)
{
}

template <class T>
class IStack : public stack
{
  protected:

  public:

    IStack();
    IStack(IStack<T>&);
    ~IStack();

    void push(T const&);
    void pop(T&);
    void pop();
    void peek(T&);
    int isEmpty() const;

    void clear();
};

template <class T>
inline void IStack<T>::clear()
{
  StackNode<T> * pNode, * pNextNode;

  for (pNode = (StackNode<T>*) pTop; pNode; pNode = (StackNode<T>*) pNextNode)
  {
    pNextNode = (StackNode<T>*) pNode->pNext;
    delete pNode;
  }
  pTop = 0;
}

template <class T>
inline IStack<T>::IStack() : stack()
{
}

template <class T>
inline IStack<T>::IStack(IStack<T>& stk) : stack()
{
  for (StackNode<T>* pNode = (StackNode<T>*) stk.pTop; pNode; pNode = (StackNode<T>*) pNode->pNext)
    push(pNode->data);
}

template <class T>
inline IStack<T>::~IStack()
{
  clear();
}

template <class T>
inline void IStack<T>::push(T const& a)
{
  stack::push(new StackNode<T>(a));
}

template <class T>
inline void IStack<T>::pop(T& a)
{
  // possible error

  StackNode<T> * p = (StackNode<T>*) stack::pop();

  if (p)
  {
    a = p -> data;
    delete p;
  }
}

template <class T>
inline void IStack<T>::pop()
{
  StackNode<T> * p = (StackNode<T>*) stack::pop();

  if (p)
    delete p;
}

template <class T>
inline void IStack<T>::peek(T& a)
{
  // possible error

  StackNode<T> * p = (StackNode<T>*) stack::peek();

  if (p)
    a = p -> data;
}

template <class T>
inline int IStack<T>::isEmpty() const
{
  return stack::isEmpty();
}

/*****************************************************************************/
/* Provide macro for list/cursor type names                                  */
/*****************************************************************************/
#define LIST(TYPE)  Sequence<TYPE>
#define SLIST(TYPE) OrderedSequence<TYPE>
#define ELIST(TYPE) EqualitySequence<TYPE>
#define STACK(TYPE) IStack<TYPE>

#define CURSOR(TYPE)  Cursor<TYPE>

/*****************************************************************************/
/* Provide easy way to delete objects from list of pointers.                 */
/*****************************************************************************/
#define DELETE_LIST(LIST, PTYPE)                                    \
  {                                                                 \
    PTYPE tempType;                                                 \
    Cursor<PTYPE> cursor(LIST);                                     \
    for (cursor.setToFirst(); cursor.isValid(); cursor.setToNext()) \
    {                                                               \
       tempType = cursor.element();                                 \
       delete tempType;                                             \
    }                                                               \
  }


/*****************************************************************************/
/* Provide easy way to traverse all elements of list.                        */
/*****************************************************************************/
#define FORALL(CURSOR)  for (CURSOR.setToFirst(); \
                             CURSOR.isValid();    \
                             CURSOR.setToNext())

// --------------------------------------------------------
// end if extract
// --------------------------------------------------------

#endif
