/***************************************************************************
**
**  This file is part of QGpCoreTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2011-05-16
**  Copyright: 2011-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "TreeContainer.h"
#include "CoreApplication.h"

namespace QGpCoreTools {

  /*!
    \class TreeContainer TreeContainer.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  /*!
    \fn TreeContainer::TreeContainer(TreeContainer * parent)
    Default constructor.
  */

  /*!
    Deletes all children.
  */
  TreeContainer::~TreeContainer()
  {
    qDeleteAll(_children);
  }

  /*!
    Removes \a child from list of children. If \a child is not found,
    a warning is issued and false is returned.
  */
  bool TreeContainer::takeChild(TreeItem * item)
  {
    int i=_children.indexOf(item);
    if(i>-1) {
      _children.removeAt(i);
      return true;
    } else {
      App::log(tr("TreeContainer::takeChild: unknown child.\n") );
      return false;
    }
  }

  /*!
    Returns true if this container can take ownership of all children from \a o
    without circular references.
  */
  bool TreeContainer::canTakeChildren(const TreeContainer * o) const
  {
    for(const_iterator it=o->_children.begin(); it!=o->_children.end(); ++it) {
      if(!(*it)->isValidParent(this)) {
        return false;
      }
    }
    return true;
  }

  /*!
    This container takes ownership of all children from \a o.
  */
  void TreeContainer::takeChildren(TreeContainer * o)
  {
    // Makes a copy of children list because setParent() modifies children lists
    // and may corrupt iterators
    QList<TreeItem *> list=o->_children;
    for(iterator it=list.begin(); it!=list.end(); ++it) {
      (*it)->setParent(this);
    }
  }

  /*!
    Saves all children to an XML structure.
  */
  void TreeContainer::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
  {
    Q_UNUSED(context)
    for(const_iterator it=begin(); it!=end(); ++it) {
      (*it)->xml_save(s, context);
    }
  }

  /*!
    Sets rank of child at rank \a oldr to \a newr.
    Only TreeItem::setRank() can call this function.
    \internal
  */
  void TreeContainer::setRank(int oldr, int newr)
  {
    // The next condition is supposed to be always true
    // because only TreeItem::setRank() can call this function.
    ASSERT(oldr>=0 && oldr<_children.count());
    if(newr<0) newr=0;
    else if(newr>=_children.count()) newr=_children.count()-1;
    _children.move(oldr, newr);
  }

  /*!
    Counts the number of children that are containers.

    \sa containerAt(), indexOfContainer(()
  */
  int TreeContainer::containerCount() const
  {
    TRACE;
    int n=0;
    for(const_iterator it=begin(); it!=end(); ++it) {
      if((*it)->isContainer()) n++;
    }
    return n;
  }

  /*!
    Return the child container at position \a index.

    \sa containerCount(), containerIndex(()
  */
  TreeContainer * TreeContainer::containerAt(int index) const
  {
    TRACE;
    int i=0;
    for(const_iterator it=begin(); it!=end(); ++it) {
      if((*it)->isContainer()) {
        if(i==index) {
          return static_cast<TreeContainer *>(*it);
        }
        i++;
      }
    }
    return 0;
  }

  /*!
    Return the index of child container \a item.

    \sa containerCount(), containerAt()
  */
  int TreeContainer::containerIndex() const
  {
    TRACE;
    if(!parent()) return 0;
    int i=0;
    for(const_iterator it=parent()->begin(); it!=parent()->end(); ++it) {
      if((*it)->isContainer()) {
        if(*it==static_cast<const TreeItem *>(this)) {
          return i;
        }
        i++;
      }
    }
    // Tree is corrupted if this container cannot be found in children list of its parent.
    ASSERT(false);
    return 0;
  }

} // namespace QGpCoreTools
