/***************************************************************************
 *                          Zanoza Modeler v2.x                            *
 *      This is unpublished propietary source code of Zanoza Software.     *
 *      The copyright notice does not evidence any actual or intended      *
 *                    publication of such source code.                     *
 *                                                                         *
 *                   Copyright (c) 2002 Zanoza Software.                   *
 *                                                                         *
 *                        All rights reserved.                             *
 ***************************************************************************
 *--------------------------------------------------------------------------
 * @author:   Oleg M.
 *--------------------------------------------------------------------------
 * @purpose:  ZModeler 2.x collection template
 *--------------------------------------------------------------------------
 * @histroy: 24.09.2002. Created
 * @histroy: 10.02.2006. VS8 upgrade
 */
#ifndef zcollection_h_included
#define zcollection_h_included

template <class T>
class /*DLL_LINKAGE*/ ZCollection
{
public:
  typedef T tNodeKind;
protected:
  typedef struct tNode
  {
    tNodeKind       m_info;
    struct tNode*   m_pNext;
  }tNode, *lpNode;

  lpNode            m_pHead, m_pPtr;
  ZSequence<lpNode> m_stack; //for push/pop states
  long              m_nLength;
public:
  //default constructor:
  ZCollection()
  {
    m_pHead = m_pPtr = NULL;
    m_nLength  = 0;
  }

  //destructor
  virtual ~ZCollection()
  {
    clear();
  }

  inline lpNode     head() const    { return m_pHead; } //head node.
  inline bool       isLast() const  { return NULL == m_pPtr || NULL == m_pPtr->m_pNext; }
  inline bool       isFirst() const { return m_pHead == m_pPtr; }

  //adds first element
  virtual ZRESULT addFirst(tNodeKind& info)
  {
    lpNode  ptr = m_pHead;
    m_pHead = new tNode();
    m_pHead->m_info  = info;
    m_pHead->m_pNext = ptr;
    m_nLength++;
    reset();
    return ZRESULT_OK;
  }

  //adds last element
  virtual ZRESULT addLast(tNodeKind& info)
  {
    lpNode  ptr = m_pHead;
    if (ptr == NULL)
      return addFirst(info);
    while (ptr->m_pNext)
      ptr = ptr->m_pNext;
    ptr->m_pNext = new tNode();
    ptr->m_pNext->m_info  = info;
    ptr->m_pNext->m_pNext = NULL;
    m_nLength++;
    return ZRESULT_OK;
  }

  //provides length
  virtual long length() const
  {
    return m_nLength;
  }

  //appends sequence to the end of this sequence
  virtual ZRESULT append(const ZCollection<tNodeKind>& src)
  {
    lpNode  ptr = m_pHead;
    if (ptr != NULL)
      while (ptr->m_pNext)
        ptr = ptr->m_pNext;
    lpNode  ptr2 = src.head();
    while (ptr2)
    {
      if (ptr)
      {
        ptr->m_pNext = new tNode();
        ptr = ptr->m_pNext;
      }
      else
      {
        m_pHead = new tNode();
        ptr = m_pHead;
      }
      ptr->m_info  = ptr2->m_info;
      ptr->m_pNext = NULL;
      m_nLength++;
      ptr2 = ptr2->m_pNext;
    }
    return ZRESULT_OK;
  }

  //resets iterator
  virtual ZRESULT reset()
  {
    m_pPtr = m_pHead;
    return ZRESULT_OK;
  }

  //reverse-resets iterator
  virtual ZRESULT revreset()
  {
    m_pPtr = (m_pHead && m_pHead->m_pNext) ? NULL : m_pHead;
    return ZRESULT_OK;
  }

  //skips [several] node(s)
  virtual ZRESULT skip(long num = 1)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;
    while (m_pPtr && (num > 0))
    {
      m_pPtr = m_pPtr->m_pNext;
      num--;
    }
    return (num > 0) ? ZRESULT_OUT_OF_RANGE : ZRESULT_OK;
  }

  //provides interface to current node's info and moves iterator
  virtual ZRESULT next(tNodeKind* pInfo = NULL)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;
    if (!m_pPtr)
      return ZRESULT_OUT_OF_RANGE;
    if (pInfo == NULL)
    {
      m_pPtr = m_pPtr->m_pNext;
      return ZRESULT_OK;
    }
    *pInfo = m_pPtr->m_info;
    m_pPtr = m_pPtr->m_pNext;
    return ZRESULT_OK;
  }

  //provides interface to the node, preciding the current
  virtual ZRESULT prev(tNodeKind* pInfo = NULL)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;
    if (m_pPtr == m_pHead)
      return ZRESULT_FALSE;
    //move one step back
    lpNode ptr = m_pHead;
    while (ptr && (ptr->m_pNext != m_pPtr))
      ptr = ptr->m_pNext;
    if (ptr)
    {
      m_pPtr = ptr;
      if (pInfo != NULL)
        *pInfo = m_pPtr->m_info;
    }
    return ZRESULT_OK;
  }

  //reverses the order of items in collection
  virtual void reverseOrder()
  {
    ZSequence<tNodeKind> seqItems;
    seqItems.length(m_nLength);
    int i = 1;
    lpNode ptr = m_pHead;
    //save in reverse order
    while (ptr)
    {
      seqItems[m_nLength-i] = ptr->m_info;
      i++;
      ptr = ptr->m_pNext;
    }
    ptr = m_pHead;
    i = 0;
    //load in direct order
    while (ptr)
    {
      ptr->m_info = seqItems[i];
      i++;
      ptr = ptr->m_pNext;
    }
  }


  //saves state interator
  virtual void pushState()
  {
    m_stack.add(m_pPtr);
  }

  //restores state interator. if you are not sure whether restored
  //state still valid, then make a reset() call.
  virtual void popState()
  {
    if (m_stack.length())
    {
      m_pPtr = m_stack[m_stack.length()-1];
      m_stack.length(m_stack.length()-1);
    }
    else
      m_pPtr = NULL;
  }

  //removes first (head) node
  virtual ZRESULT removeFirst()
  {
    if (!m_pHead)
      return ZRESULT_FALSE;
    lpNode  ptr   = m_pHead->m_pNext;
    if (m_pPtr == m_pHead)
      m_pPtr = ptr;
    eraseFromStack(m_pHead);
    delete m_pHead;
    m_nLength--;
    m_pHead = ptr;
    return ZRESULT_OK;
  }

  //removes last (tail) node
  virtual ZRESULT removeLast()
  {
    if (!m_pHead)
      return ZRESULT_FALSE;
    if (!m_pHead->m_pNext)
      return removeFirst();
    lpNode  ptr  = m_pHead;
    while (ptr->m_pNext)
    {
      if (!ptr->m_pNext->m_pNext)
      {
        if (m_pPtr == ptr->m_pNext)
          m_pPtr = NULL;
        eraseFromStack(ptr->m_pNext);
        delete ptr->m_pNext;
        ptr->m_pNext = NULL;
        break;
      }
      ptr = ptr->m_pNext;
    }
    m_nLength--;
    return ZRESULT_OK;
  }

  //removes supplied interace(s)
  virtual ZRESULT erase(const tNodeKind info)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;

    pushState();
    while ((m_pHead != NULL) && (info == m_pHead->m_info))
      removeFirst();
    lpNode  ptr2  = m_pHead;
    lpNode  ptr   = m_pHead;
    if (ptr2 != NULL)
      while (ptr2->m_pNext)
      {
        if (ptr2->m_pNext->m_info == info)
        {//remove node;
          ptr = ptr2->m_pNext->m_pNext;
          if (m_pPtr == ptr2->m_pNext)
            m_pPtr = ptr;
          eraseFromStack(ptr2->m_pNext);
          delete ptr2->m_pNext;
          ptr2->m_pNext = ptr;
          m_nLength--;
        }
        else
          ptr2 = ptr2->m_pNext;
        ptr = ptr2;
      }
    popState();
    return ZRESULT_OK;
  }

  //provides zero-based index of element. returns -1 if not found
  virtual long indexOf(const tNodeKind info)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;

    lpNode  ptr   = m_pHead;
    long nIndex = 0;
    while (ptr)
      if (ptr->m_info == info)
        return nIndex;
      else
      {
        nIndex++;
        ptr = ptr->m_pNext;
      }
    return -1;
  }

  //removes current node
  virtual ZRESULT erase()
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;
    if (!m_pPtr)
      return removeLast();
    if (m_pHead->m_pNext == m_pPtr)
      return removeFirst();

    lpNode  ptr   = m_pHead;
    lpNode  ptr2  = m_pHead;
    while (ptr2->m_pNext)
      if (ptr2->m_pNext == m_pPtr)
      {//remove node;
        eraseFromStack(ptr2);
        delete ptr2;
        ptr->m_pNext = m_pPtr;
        m_nLength--;
        return ZRESULT_OK;
      }
      else
      {
        ptr = ptr2;
        ptr2 = ptr2->m_pNext;
      }
    return ZRESULT_FALSE;
  }

  //inserts node at supplied position
  virtual ZRESULT insert(tNodeKind& info, long index=-1)
  {
    if (index > (long)m_nLength)
      return ZRESULT_OUT_OF_RANGE;
    if (!m_pHead || (m_pPtr == m_pHead) || 0==index)
      return addFirst(info);
    if (index == (long)m_nLength)
      return addLast(info);
    lpNode  ptr   = m_pHead;
    if (-1 == index)
    {//insert before current
      if (m_pPtr == m_pHead)
        return addFirst(info);
      while (ptr->m_pNext != m_pPtr)
        ptr = ptr->m_pNext;
    }
    else
    {
      long pos = 0;
      while (ptr && (++pos < index))
        ptr = ptr->m_pNext;
    }
    lpNode  ptr2 = ptr->m_pNext;
    ptr->m_pNext = new tNode();
    ptr->m_pNext->m_info  = info;
    ptr->m_pNext->m_pNext = ptr2;
    m_nLength++;
    return ZRESULT_OK;
  }

  //clears controlled sequence
  virtual void clear()
  {
    lpNode  ptr = m_pHead;
    while (ptr)
    {
      m_pHead = m_pHead->m_pNext;
      delete ptr;
      ptr = m_pHead;
    }
    m_stack.length(0);
    m_pHead = m_pPtr = NULL;
    m_nLength = 0;
  }

  //tells whether controlled sequence contains supplied interface
  virtual bool contains(const tNodeKind& info)
  {
    lpNode  ptr = m_pHead;
    while (ptr)
    {
      if (info == ptr->m_info)
        return true;
      ptr = ptr->m_pNext;
    }
    return false;
  }

  //navigates iterator to supplied element
  virtual bool navigateTo(const tNodeKind& info)
  {
    lpNode  ptr = m_pHead;
    while (ptr)
    {
      if (info == ptr->m_info)
        break;
      ptr = ptr->m_pNext;
    }
    m_pPtr = ptr;
    return (ptr != NULL);
  }
  //erases node from push/pop stack
  virtual void eraseFromStack(const lpNode node)
  {
    for (long i = 0; i < m_stack.length(); i++)
      if (m_stack[i] == node)
        m_stack[i] = NULL;
  }
  //manual chain-changes have been made
  virtual void invalidate()
  {
    m_stack.length(0);
    m_nLength = 0;
    lpNode  ptr = m_pHead;
    while (ptr)
    {
      m_nLength++;
      ptr = ptr->m_pNext;
    }
  }
};


//----------------------------------------------
// Collection template for interface nodes
//----------------------------------------------
template <class T>
class /*DLL_LINKAGE*/ ZIntrCollection
{
public:
  typedef T tNodeKind;
  typedef struct tNode
  {
    ZPtr<tNodeKind> m_pIntr;
    struct tNode*   m_pNext;
  }tNode, *lpNode;

protected:
  lpNode            m_pHead, m_pPtr;
  ZSequence<lpNode> m_stack;
  long              m_nLength;
public:
  //default constructor:
  ZIntrCollection()
  {
    m_pHead = m_pPtr = NULL;
    m_nLength  = 0;
  }

  inline tNodeKind* current() { return m_pPtr ? m_pPtr->m_pIntr : NULL; }
  inline lpNode&    head()    { return m_pHead; } //head node.
  inline bool       isLast()  { return NULL == m_pPtr || NULL == m_pPtr->m_pNext; }
  inline bool       isFirst() { return m_pHead == m_pPtr; }

  /*copy constructor
  ZIntrCollection(const ZCollection<tNodeKind>& copy)
  {
    m_pHead = m_pPtr = NULL;
    lpNode  ptr = copy.head();
    while (ptr)
    {
      lpNode  ptr2 = m_pHead;
      m_pHead = new tNode();
      m_pHead->m_pIntr = ptr->m_pIntr;
      m_pHead->m_pNext = ptr2;
      ptr = ptr->m_pNext;
    }
    m_nLength  = copy.length();
  }
  */

  //destructor
  virtual ~ZIntrCollection()
  {
    clear();
  }

  //adds first element
  virtual ZRESULT addFirst(tNodeKind* pIntr)
  {
    lpNode  ptr = m_pHead;
    m_pHead = new tNode();
    m_pHead->m_pIntr = pIntr;
    m_pHead->m_pNext = ptr;
    m_nLength++;
    reset();
    return ZRESULT_OK;
  }

  //adds last element
  virtual ZRESULT addLast(tNodeKind* pIntr)
  {
    lpNode  ptr = m_pHead;
    if (ptr == NULL)
      return addFirst(pIntr);
    while (ptr->m_pNext)
      ptr = ptr->m_pNext;
    ptr->m_pNext = new tNode();
    ptr->m_pNext->m_pIntr = pIntr;
    ptr->m_pNext->m_pNext = NULL;
    m_nLength++;
    return ZRESULT_OK;
  }

  //provides head element
  virtual lpNode head() const
  {
    return m_pHead;
  }

  //provides length
  virtual long length() const
  {
    return m_nLength;
  }

  //appends sequence to the end of this sequence
  virtual ZRESULT append(const ZIntrCollection<tNodeKind>& src)
  {
    lpNode  ptr = m_pHead;
    if (ptr != NULL)
      while (ptr->m_pNext)
        ptr = ptr->m_pNext;
    lpNode  ptr2 = src.head();
    while (ptr2)
    {
      if (ptr)
      {
        ptr->m_pNext = new tNode();
        ptr = ptr->m_pNext;
      }
      else
      {
        m_pHead = new tNode();
        ptr = m_pHead;
      }
      ptr->m_pIntr = ptr2->m_pIntr;
      ptr->m_pNext = NULL;
      m_nLength++;
      ptr2 = ptr2->m_pNext;
    }
    return ZRESULT_OK;
  }

  //resets iterator
  virtual ZRESULT reset()
  {
    m_pPtr = m_pHead;
    return ZRESULT_OK;
  }

  //reverse-resets iterator
  virtual ZRESULT revreset()
  {
    m_pPtr = m_pHead;
    while (m_pPtr)
      m_pPtr = m_pPtr->m_pNext;
    return ZRESULT_OK;
  }

  //skips [several] node(s)
  virtual ZRESULT skip(long num = 1)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;
    while (m_pPtr && (num > 0))
    {
      m_pPtr = m_pPtr->m_pNext;
      num--;
    }
    return (num > 0) ? ZRESULT_OUT_OF_RANGE : ZRESULT_OK;
  }

  //provides interface to current node's interface and moves iterator
  virtual ZRESULT next(tNodeKind** ppInter = NULL)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;
    if (!m_pPtr)
      return ZRESULT_OUT_OF_RANGE;
    if (ppInter == NULL)
    {
      m_pPtr = m_pPtr->m_pNext;
      return ZRESULT_OK;
    }
    m_pPtr->m_pIntr.CopyTo(ppInter);
    m_pPtr = m_pPtr->m_pNext;
    return ZRESULT_OK;
  }

  //provides interface to the node, preciding the current
  virtual ZRESULT prev(tNodeKind** ppInter = NULL)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;
    if (m_pPtr == m_pHead)
      return ZRESULT_FALSE;
    //move one step back
    lpNode ptr = m_pHead;
    while (ptr && (ptr->m_pNext != m_pPtr))
      ptr = ptr->m_pNext;
    if (ptr)
    {
      m_pPtr = ptr;
      if (ppInter != NULL)
        m_pPtr->m_pIntr.CopyTo(ppInter);
    }
    return ZRESULT_OK;
  }

  //reverses the order of items in collection
  virtual void reverseOrder()
  {
    ZSequence< ZPtr<tNodeKind> > seqItems;
    seqItems.length(m_nLength);
    int i = 1;
    lpNode ptr = m_pHead;
    //save in reverse order
    while (ptr)
    {
      seqItems[m_nLength-i] = ptr->m_pIntr;
      i++;
      ptr = ptr->m_pNext;
    }
    ptr = m_pHead;
    i = 0;
    //load in direct order
    while (ptr)
    {
      ptr->m_pIntr = seqItems[i];
      i++;
      ptr = ptr->m_pNext;
    }
  }

  //saves state interator
  virtual void pushState()
  {
    m_stack.add(m_pPtr);
  }

  //restores state interator. if you are not sure whether restored
  //state still valid, then make a reset() call.
  virtual void popState()
  {
    int l = m_stack.length();
    if (l > 0)
    {
      m_pPtr = m_stack[l-1];
      m_stack.length(l-1);
    }
    else
      m_pPtr = NULL;
  }

  //removes first (head) node
  virtual ZRESULT removeFirst()
  {
    if (!m_pHead)
      return ZRESULT_FALSE;
    lpNode  ptr   = m_pHead->m_pNext;
    if (m_pPtr == m_pHead)
      m_pPtr = ptr;
    eraseFromStack(m_pHead);
    delete m_pHead;
    m_nLength--;
    m_pHead = ptr;
    return ZRESULT_OK;
  }

  //removes last (tail) node
  virtual ZRESULT removeLast()
  {
    if (!m_pHead)
      return ZRESULT_FALSE;
    if (!m_pHead->m_pNext)
      return removeFirst();
    lpNode  ptr  = m_pHead;
    while (ptr->m_pNext)
    {
      if (!ptr->m_pNext->m_pNext)
      {
        if (m_pPtr == ptr->m_pNext)
          m_pPtr = NULL;
        eraseFromStack(ptr->m_pNext);
        delete ptr->m_pNext;
        ptr->m_pNext = NULL;
        break;
      }
      ptr = ptr->m_pNext;
    }
    m_nLength--;
    return ZRESULT_OK;
  }

  //removes supplied interace(s)
  virtual ZRESULT erase(const tNodeKind* pInter)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;

    while ((m_pHead != NULL) && (pInter == m_pHead->m_pIntr))
      removeFirst();
    lpNode  ptr2  = m_pHead;
    lpNode  ptr   = m_pHead;
    if (ptr2 != NULL)
      while (ptr2->m_pNext)
      {
        if (ptr2->m_pNext->m_pIntr == pInter)
        {//remove node;
          ptr = ptr2->m_pNext->m_pNext;
          if (m_pPtr == ptr2->m_pNext)
            m_pPtr = ptr;
          eraseFromStack(ptr2->m_pNext);
          delete ptr2->m_pNext;
          ptr2->m_pNext = ptr;
          m_nLength--;
        }
        else
          ptr2 = ptr2->m_pNext;
        ptr = ptr2;
      }
    return ZRESULT_OK;
  }

  //removes current node
  virtual ZRESULT erase()
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;
    if (!m_pPtr)
      return removeLast();
    if (m_pHead->m_pNext == m_pPtr)
      return removeFirst();

    lpNode  ptr   = m_pHead;
    lpNode  ptr2  = m_pHead;
    while (ptr2->m_pNext)
      if (ptr2->m_pNext == m_pPtr)
      {//remove node;
        eraseFromStack(ptr2);
        delete ptr2;
        ptr->m_pNext = m_pPtr;
        m_nLength--;
        return ZRESULT_OK;
      }
      else
      {
        ptr = ptr2;
        ptr2 = ptr2->m_pNext;
      }
    return ZRESULT_FALSE;
  }

  //provides zero-based index of element. returns -1 if not found
  virtual long indexOf(const tNodeKind* pInter)
  {
    if (!m_pHead)
      return ZRESULT_EMPTY;

    lpNode  ptr   = m_pHead;
    long nIndex = 0;
    while (ptr)
      if (ptr->m_pIntr == pInter)
        return nIndex;
      else
      {
        nIndex++;
        ptr = ptr->m_pNext;
      }
    return -1;
  }

  //inserts node at supplied position
  virtual ZRESULT insert(tNodeKind* pInter, long index=-1)
  {
    if (index > (long)m_nLength)
      return ZRESULT_OUT_OF_RANGE;
    if (!m_pHead || (m_pPtr == m_pHead) || 0==index)
      return addFirst(pInter);
    if (index == (long)m_nLength)
      return addLast(pInter);
    lpNode  ptr   = m_pHead;
    if (-1 == index)
    {//insert before current
      if (m_pPtr == m_pHead)
        return addFirst(pInter);
      while (ptr->m_pNext != m_pPtr)
        ptr = ptr->m_pNext;
    }
    else
    {
      long pos = 0;
      while (ptr && (++pos < index))
        ptr = ptr->m_pNext;
    }
    lpNode  ptr2 = ptr->m_pNext;
    ptr->m_pNext = new tNode();
    ptr->m_pNext->m_pIntr = pInter;
    ptr->m_pNext->m_pNext = ptr2;
    m_nLength++;
    return ZRESULT_OK;
  }

  //clears controlled sequence
  virtual void clear()
  {
    lpNode  ptr = m_pHead;
    while (ptr)
    {
      m_pHead = m_pHead->m_pNext;
      delete ptr;
      ptr = m_pHead;
    }
    m_pHead = m_pPtr = NULL;
    m_stack.length(0);
    m_nLength = 0;
  }

  //tells whether controlled sequence contains supplied interface
  virtual bool contains(const tNodeKind* pIntr)
  {
    lpNode  ptr = m_pHead;
    while (ptr)
    {
      if (pIntr == ptr->m_pIntr)
        return true;
      ptr = ptr->m_pNext;
    }
    return false;
  }

  //navigates iterator to supplied element
  virtual bool navigateTo(const tNodeKind* pIntr)
  {
    lpNode  ptr = m_pHead;
    while (ptr)
    {
      if (pIntr == ptr->m_pIntr)
        break;
      ptr = ptr->m_pNext;
    }
    m_pPtr = ptr;
    return (ptr != NULL);
  }
  //erases node from push/pop stack
  virtual void eraseFromStack(const lpNode node)
  {
    for (long i = 0; i < m_stack.length(); i++)
      if (m_stack[i] == node)
        m_stack[i] = NULL;
  }
  //manual chain-changes have been made
  virtual void invalidate()
  {
    m_stack.length(0);
    m_nLength = 0;
    lpNode  ptr = m_pHead;
    while (ptr)
    {
      m_nLength++;
      ptr = ptr->m_pNext;
    }
  }
};

#endif //zcollection_h_included
