/***************************************************************************
 *   Copyright (C) 2004 by Hans Oischinger                                 *
 *   hans.oischinger@kdemail.net                                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.             *
 ***************************************************************************/
#include "elementtreeiterator.h"

#include "elements/useelement.h"

ElementTreeIterator::ElementTreeIterator( ElementNode* root, bool includeUseClones )
    : m_includeUseClones(includeUseClones),
    m_level(0)
{
  m_rootNode = root;
  start();
}


ElementTreeIterator::~ElementTreeIterator()
{}


ElementNode* ElementTreeIterator::start()
{
  m_prevNode = m_nextNode = 0;
  m_currentNode = m_rootNode;
  m_level = 0;
  return m_currentNode;
}

ElementNode* ElementTreeIterator::prev()
{
  ElementNode* prev = 0;

  // for current Node = NULL
  if (!m_currentNode)
  {
    if (m_prevNode)
      return m_prevNode;
    else
      return prev;
  }

  if (m_currentNode->getPrev())
  {
    prev = m_currentNode->getPrev();
    if ( m_includeUseClones || !::qt_cast<UseElement*>(prev) )
    {
      ElementNode* currNode = prev->getLastChild();
      ++m_level;
      while (currNode)
      {
        if (!( m_includeUseClones || !::qt_cast<UseElement*>(currNode) ))
          break;
        prev = currNode;
        currNode = currNode->getLastChild();
        ++m_level;
      }
    }
  }
  else if (m_currentNode->getParent())
  {
    prev = m_currentNode->getParent();
    --m_level;
  }
  // Set all member nodes
  m_prevNode = 0;
  m_nextNode = m_nextNode;
  m_currentNode = prev;
  return m_currentNode;
}

ElementNode* ElementTreeIterator::next()
{
  ElementNode* next = 0;

  // for current Node = NULL
  if (!m_currentNode)
  {
    if (m_nextNode)
      return m_nextNode;
    else
      return next;
  }

  // Get child if exists
  if ( m_currentNode->getFirstChild() && ( m_includeUseClones || !::qt_cast<UseElement*>(m_currentNode) ) )
  {
    next = m_currentNode->getFirstChild();
    ++m_level;
  }
  else
  {
    // Are we beyond m_rootNode?
    if (m_currentNode == m_rootNode)
      next = 0;
    else
    {
      // No, get next() if exists
      if (m_currentNode->getNext())
        next = m_currentNode->getNext();
      else
      {
        // Find parent's neighbour
        ElementNode *parent = m_currentNode->getParent();
        ElementNode *n;
        while(!next && parent)
        {
          --m_level;
          // are we beyond m_rootNode?
          if ( parent == m_rootNode )
          {
            next = 0;
            break;
          }

          // is Parent's neighbour valid?
          n = parent->getNext();
          if(n != NULL)
          {
            next = n;
            break;
          }

          // else try parent's parent
          parent = parent->getParent();
        }
      }
    }
  }


  // Set all member nodes
  m_prevNode = m_currentNode;
  m_nextNode = 0;
  m_currentNode = next;
  return m_currentNode;
}

ElementNode* ElementTreeIterator::current()
{
  return m_currentNode;
}



















ElementTreeConstIterator::ElementTreeConstIterator( ElementNode* root )
{
  m_rootNode = root;
  start();
}


ElementTreeConstIterator::~ElementTreeConstIterator()
{}


const ElementNode* ElementTreeConstIterator::start()
{
  m_prevNode = m_nextNode = 0;
  m_currentNode = m_rootNode;

  return m_currentNode;
}

const ElementNode* ElementTreeConstIterator::prev()
{
  ElementNode* prev = 0;

  // for current Node = NULL
  if (!m_currentNode)
  {
    if (m_prevNode)
      return m_prevNode;
    else
      return prev;
  }

  if (m_currentNode->getParent())
    prev = m_currentNode->getParent();
  else if (m_currentNode->getPrev())
    prev = m_currentNode->getPrev();

  ElementNode *parent = m_currentNode->getParent();
  ElementNode *n;
  while(!prev && parent != NULL)
  {
    n = parent->getNext();
    if(n != NULL)
    {
      prev = n;
      break;
    }

    if(m_rootNode == parent)
      break;

    parent = parent->getParent();
  }

  // Set all member nodes
  m_prevNode = 0;
  m_nextNode = m_nextNode;
  m_currentNode = prev;
  return m_currentNode;
}

const ElementNode* ElementTreeConstIterator::next()
{
  ElementNode* next = 0;

  // for current Node = NULL
  if (!m_currentNode)
  {
    if (m_nextNode)
      return m_nextNode;
    else
      return next;
  }

  if (m_currentNode->getFirstChild())
    next = m_currentNode->getFirstChild();
  else if (m_currentNode->getNext())
    next = m_currentNode->getNext();

  ElementNode *parent = m_currentNode->getParent();
  ElementNode *n;
  while(!next && parent != NULL)
  {
    n = parent->getNext();
    if(n != NULL)
    {
      next = n;
      break;
    }

    if(m_rootNode == parent)
      break;

    parent = parent->getParent();
  }

  // Set all member nodes
  m_prevNode = m_currentNode;
  m_nextNode = 0;
  m_currentNode = next;
  return m_currentNode;
}

const ElementNode* ElementTreeConstIterator::current()
{
  return m_currentNode;
}


