/***************************************************************************
 *   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 "elementnode.h"

// KDE
#include <kdebug.h>

ElementNode::ElementNode(const QString & name, unsigned int state)
    : Element( name, state ),
    parent(0),
    prev(0),
    next(0),
    first(0),
    last(0)
{}


ElementNode::~ElementNode()
{}


ElementNode::ElementNode( const ElementNode &other )
    : Element(), parent(0),
    prev(0),
    next(0),
    first(0),
    last(0)
{
  (*this) = other;
}

ElementNode& ElementNode::operator=(const ElementNode &other)
{
  Element::operator=(other);
  /*  parent = other.getParent();
    prev = other.getPrev();
    next = other.getNext();
    first = other.getFirstChild();
    last = other.getLastChild();*/
  //TODO: when cloning should we copy the original's neighbour refs???
  return *this;
}


ElementNode* ElementNode::insertBefore( ElementNode* newChild, ElementNode* refChild )
{
  // Error checks
  if ( !newChild )
    return 0;
  if ( newChild == refChild )
    return 0;
  if ( refChild && refChild->getParent() != this )
    return 0;

  // Everything seems to be OK... here we go
  // Remove newChilds Parent if it exists
  if ( newChild->getParent() )
    newChild->getParent()->removeChild( newChild );

  newChild->parent = this;

  if ( !refChild )
  {
    if ( first )
      first->prev = newChild;
    newChild->next = first;
    if ( !last )
      last = newChild;
    first = newChild;
    return newChild;
  }

  if ( refChild->prev == 0 )
  {
    if ( first )
      first->prev = newChild;
    newChild->next = first;
    if ( !last )
      last = newChild;
    first = newChild;
    return newChild;
  }

  // Set all neighbours
  newChild->next = refChild;
  newChild->prev = refChild->prev;
  refChild->prev->next = newChild;
  refChild->prev = newChild;

  if ( !newChild->prev )
    first = newChild;
  if ( !newChild->next )
    last = newChild;

  return newChild;
}

ElementNode* ElementNode::insertAfter( ElementNode* newChild, ElementNode* refChild )
{
  // Error checks
  if ( !newChild )
    return 0;
  if ( newChild == refChild )
    return 0;
  if ( refChild && refChild->getParent() != this )
    return 0;

  // Everything seems to be OK... here we go
  // Remove newChilds Parent if it exists
  if ( newChild->getParent() )
    newChild->getParent()->removeChild( newChild );

  newChild->parent = this;

  // Insert at the end
  if ( !refChild )
  {
    if ( last )
      last->next = newChild;
    newChild->prev = last;
    if ( !first )
      first = newChild;
    last = newChild;
    return newChild;
  }

  if ( refChild->next == 0 )
  {
    if ( last )
      last->next = newChild;
    newChild->prev = last;
    if ( !first )
      first = newChild;
    last = newChild;
    return newChild;
  }

  // Set all neighbours
  newChild->next = refChild->next;
  newChild->prev = refChild;
  refChild->next->prev = newChild;
  refChild->next = newChild;

  if ( !newChild->prev )
    first = newChild;
  if ( !newChild->next )
    last = newChild;

  return newChild;
}

ElementNode* ElementNode::removeChild( ElementNode* oldChild )
{
  // Error check
  if ( oldChild->getParent() != this )
    return 0;

  if ( oldChild->next )
    oldChild->next->prev = oldChild->prev;
  if ( oldChild->prev )
    oldChild->prev->next = oldChild->next;

  if ( last == oldChild )
    last = oldChild->prev;
  if ( first == oldChild )
    first = oldChild->next;

  oldChild->parent = 0;
  oldChild->next = 0;
  oldChild->prev = 0;

  return oldChild;
}

ElementNode* ElementNode::appendChild( ElementNode* newChild )
{
  // No reference manipulation needed. Done in insertAfter.
  return insertAfter( newChild, 0 );
}

bool ElementNode::hasChildNodes() const
{
  if (first)
    return true;
  else
    return false;
}

void ElementNode::deleteSubTree()
{
  ElementNode* deleteme = first;
  ElementNode* deletemenext = first;

  while (deleteme)
  {
    deletemenext = deleteme->next;
    deleteme->deleteSubTree();
    deleteme = deletemenext;
  }

  delete this;
}

ElementNode* ElementNode::cloneSubTree()
{
//   kdDebug() << "ElementNode::cloneSubTree() - Cloning first node... of type " << this->className() << endl;
  ElementNode* thisCloned = clone();
  ElementNode* cloneme = first;
  ElementNode* clonemenext = 0;

  while (cloneme)
  {
//     kdDebug() << "Cloning child... of type " << cloneme->className() << endl;
    clonemenext = cloneme->next;
    ElementNode* clonedSubTree = cloneme->cloneSubTree();
    thisCloned->appendChild( clonedSubTree );
    cloneme = clonemenext;
  }

  return thisCloned;
}

/**
 * Overloaded State fkt.
 * Returns the parents state if available
 */
unsigned int ElementNode::getState()
{
  if (m_state==Element::undefined)
  {
    ElementNode *current = parent;
    while(current)
    {
      if (current->getState() != Element::undefined)
        return current->getState();
      current = current->getParent();
    }
    return Element::normal;
  }
  else
    return Element::getState();
}
