// -*- c++ -*-
// Generated by gtkmmproc -- DO NOT MODIFY!
#ifndef _GLIBMM_TREE_H
#define _GLIBMM_TREE_H


/* Copyright (C) 2007 Levi Bard
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include <map>
#include <stack>
#include <deque>

#include <glibmm/refptr.h>
#include <glibmm/ustring.h>
#include <glibmm/error.h>
#include <glibmm/arrayhandle.h>
#include <glib/gnode.h>
#include <glib/gtree.h>

namespace Glib
{

/** @addtogroup glibmmEnums Enums and Flags */

/**
 * @ingroup glibmmEnums
 * @par Bitwise operators:
 * <tt>%TraverseFlags operator|(TraverseFlags, TraverseFlags)</tt><br>
 * <tt>%TraverseFlags operator&(TraverseFlags, TraverseFlags)</tt><br>
 * <tt>%TraverseFlags operator^(TraverseFlags, TraverseFlags)</tt><br>
 * <tt>%TraverseFlags operator~(TraverseFlags)</tt><br>
 * <tt>%TraverseFlags& operator|=(TraverseFlags&, TraverseFlags)</tt><br>
 * <tt>%TraverseFlags& operator&=(TraverseFlags&, TraverseFlags)</tt><br>
 * <tt>%TraverseFlags& operator^=(TraverseFlags&, TraverseFlags)</tt><br>
 */
enum TraverseFlags
{
  TRAVERSE_LEAVES = 1 << 0,
  TRAVERSE_NON_LEAVES = 1 << 1,
  TRAVERSE_ALL = 0x1,
  TRAVERSE_MASK = 0x03,
  TRAVERSE_LEAFS = 0x1,
  TRAVERSE_NON_LEAFS = 0x2
};

/** @ingroup glibmmEnums */
inline TraverseFlags operator|(TraverseFlags lhs, TraverseFlags rhs)
  { return static_cast<TraverseFlags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs)); }

/** @ingroup glibmmEnums */
inline TraverseFlags operator&(TraverseFlags lhs, TraverseFlags rhs)
  { return static_cast<TraverseFlags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs)); }

/** @ingroup glibmmEnums */
inline TraverseFlags operator^(TraverseFlags lhs, TraverseFlags rhs)
  { return static_cast<TraverseFlags>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs)); }

/** @ingroup glibmmEnums */
inline TraverseFlags operator~(TraverseFlags flags)
  { return static_cast<TraverseFlags>(~static_cast<unsigned>(flags)); }

/** @ingroup glibmmEnums */
inline TraverseFlags& operator|=(TraverseFlags& lhs, TraverseFlags rhs)
  { return (lhs = static_cast<TraverseFlags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs))); }

/** @ingroup glibmmEnums */
inline TraverseFlags& operator&=(TraverseFlags& lhs, TraverseFlags rhs)
  { return (lhs = static_cast<TraverseFlags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs))); }

/** @ingroup glibmmEnums */
inline TraverseFlags& operator^=(TraverseFlags& lhs, TraverseFlags rhs)
  { return (lhs = static_cast<TraverseFlags>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs))); }


/**
 * @ingroup glibmmEnums
 */
enum TraverseType
{
  IN_ORDER,
  PRE_ORDER,
  POST_ORDER,
  LEVEL_ORDER
};


/** N-ary Trees — trees of data with any number of branches
 * The Tree class and its associated functions provide an N-ary tree data structure, in which nodes in the tree can contain arbitrary data.
 * 
 * To insert a node into a tree use insert(), insert_before(), append() or prepend().
 * 
 * To create a new node and insert it into a tree use insert_data(), insert_data_before(), append_data() and prepend_data().
 * 
 * To reverse the children of a node use reverse_children().
 * 
 * To find a node use root(), find(), find_child(), index_of(), position_of(), first_child(), last_child(), nth_child(), first_sibling(), prev_sibling(), next_sibling() or last_sibling().
 * 
 * To get information about a node or tree use is_leaf(), is_root(), depth(), node_count(), child_count(), is_ancestor() or max_height().
 * 
 * To traverse a tree, calling a function for each node visited in the traversal, use traverse() or foreach().
 * 
 * To remove a node or subtree from a tree use unlink().
 *
 * @newin2p18
 */
template <typename T> 
class Tree
{
  public:
#ifndef DOXYGEN_SHOULD_SKIP_THIS
  typedef Tree CppObjectType;
  typedef GNode BaseObjectType;
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

private:

public:
  typedef gpointer iterator;
  typedef sigc::slot<bool, T&>* TraverseFunc;
  typedef sigc::slot<void, T&>* ForeachFunc;
  typedef std::map<gpointer, Tree<T>*> NodeMap;

  /** Creates a new Tree containing the given data. 
   * Used to create the first node in a tree.
   */
  Tree()
  : gobject_ (0),
    owns_gobject_(false),
    parent_(this)
  {
  }

  explicit Tree(T& data)
  {
    T* tmp = new T();
    *tmp = data;

    gobject_ = g_node_new(reinterpret_cast<gpointer>(tmp));
    owns_gobject_ = true;
    parent_ = this;
  }

  
  /** Removes the instance and its children from the tree,
   * freeing any memory allocated.
   */
  ~Tree()
  {
    if(this != parent_)
    {
      parent_->unlink(*this);
    }

    for(typename NodeMap::iterator i = children_.begin();
      i != children_.end(); ++i)
    {
      delete i->second;
    }
  
    if(owns_gobject_)
    {
      delete reinterpret_cast<T*>(gobject_->data);
      g_node_destroy(gobject_);
    }
  }
  

  /** Inserts a Tree beneath the parent at the given position.
   *
   * @param position the position to place node at, with respect to its siblings 
   * If position is -1, node is inserted as the last child of parent
   * @param node the Tree to insert
   * @return the inserted Tree
   */
  Tree<T>& insert(int position, Tree<T>& node)
  {
    children_[node.gobj()] = &node;
    g_node_insert(gobject_, position, node.gobj());
    node.parent(this);
    return node;
  }
  

  /** Inserts a Tree beneath the parent before the given sibling.
   *
   * @param sibling the sibling Tree to place node before.
   * @param node the Tree to insert
   * @return the inserted Tree
   */
  Tree<T>& insert_before(Tree<T>& sibling, Tree<T>& node)
  {
    children_[node.gobj()] = &node;
    g_node_insert_before(gobject_, sibling.gobj(), node.gobj());
    node.parent(this);
    return node;
  }
  

  /** Inserts a Tree beneath the parent after the given sibling.
   *
   * @param sibling the sibling Tree to place node after.
   * @param node the Tree to insert
   * @return the inserted Tree
   */
  Tree<T>& insert_after(Tree<T>& sibling, Tree<T>& node)
  {
    children_[node.gobj()] = &node;
    g_node_insert_after(gobject_, sibling.gobj(), node.gobj());
    node.parent(this);
    return node;
  }
  

  /** Inserts a Tree as the last child.
   *
   * @param node the Tree to append
   * @return the new Tree
   */
  Tree<T>& append(Tree<T>& node)
  {
    children_[node.gobj()] = &node;
    g_node_append(gobject_, node.gobj());
    node.parent(this);
    return node;
  }
  

  /** Inserts a Tree as the first child.
   *
   * @param data the data for the Tree
   * @return the Tree
   */
  Tree<T>& prepend(Tree<T>& node)
  {
    children_[node.gobj()] = &node;
    g_node_prepend(gobject_, node.gobj());
    node.parent(this);
    return node;
  }
  

  /** Inserts a new Tree at the given position.
   *
   * @param position the position to place the new Tree at. 
   * If position is -1, the new Tree is inserted as the last child of parent
   * @param data the data for the new Tree
   * @return the new Tree
   */
  Tree<T>* insert_data(int position, T& data)
  {
    Tree<T> *node = new Tree<T>(data);
    insert(position, *node);
    return node;
  }
  

  /** Inserts a new Tree before the given sibling.
   *
   * @param sibling the sibling Tree to place node before. 
   * @param data the data for the new Tree
   * @return the new Tree
   */
  Tree<T>* insert_data_before(Tree<T>& sibling, T& data)
  {
    Tree<T> *node = new Tree<T>(data);
    insert_before(sibling, *node);
    return node;
  }
  

  /** Inserts a new Tree as the last child.
   *
   * @param data the data for the new Tree
   * @return the new Tree
   */
  Tree<T>* append_data(T& data)
  {
    Tree<T> *node = new Tree<T>(data);
    append(*node);
    return node;
  }
  

  /** Inserts a new Tree as the first child.
   *
   * @param data the data for the new Tree
   * @return the new Tree
   */
  Tree<T>* prepend_data(T& data)
  {
    Tree<T>* node = new Tree<T>(data);
    prepend(*node);
    return node;
  }
  

  /** Reverses the order of the children.
   */
  void reverse_children()
  {
    g_node_reverse_children(gobject_);
  }
  

  /** Returns a pointer to the root of the tree.
   *
   * @return A pointer to the root of the tree.
   */
  Tree<T>* root() const
  {
    return (this == parent_)? parent_: parent_->root();
  }
  

  /** Traverses a tree starting at the current node.
   * It calls the given function for each node visited. 
   * The traversal can be halted at any point by returning true from @a func.
   *
   * @param order The order in which nodes are visited: TRAVERSE_IN_ORDER, TRAVERSE_PRE_ORDER, TRAVERSE_POST_ORDER, or TRAVERSE_LEVEL_ORDER.
   * @param flags Which types of children are to be visited: One of TRAVERSE_ALL, TRAVERSE_LEAVES and TRAVERSE_NON_LEAVES.
   * @param max_depth The maximum depth of the traversal. 
   * Nodes below this depth will not be visited. 
   * If max_depth is -1 all nodes in the tree are visited.
   * If max_depth is 1, only the root is visited.
   * If max_depth is 2, the root and its children are visited. And so on.
   * @param func the slot to invoke for each visited child
   */
  void traverse(TraverseType order, TraverseFlags flags, int max_depth, TraverseFunc func)
  {
    g_node_traverse(gobject_, (GTraverseType)order, (GTraverseFlags)flags, max_depth, wrap_traverse_slot, reinterpret_cast<gpointer>(func));
  }
  ;

  /** Calls a function for each of the children of a Tree.
   * Note that it doesn't descend beneath the child nodes.
   *
   * @param flags Wwhich types of children are to be visited: One of TRAVERSE_ALL, TRAVERSE_LEAVES and TRAVERSE_NON_LEAVES.
   * @param func The slot to invoke for each visited node.
   */
  void foreach(TraverseFlags flags, ForeachFunc func)
  {
    g_node_children_foreach(gobject_, (GTraverseFlags)flags, wrap_foreach_slot, reinterpret_cast<gpointer>(func));
  }
  

  /** Finds the first child of a Tree with the given data.
   *
   * @param flags Which types of children are to be visited, one of TRAVERSE_ALL, TRAVERSE_LEAVES and TRAVERSE_NON_LEAVES.
   * @param data The data for which to search
   * @return the found child, or 0 if the data is not found
   */
  Tree<T>* find_child(TraverseFlags flags, const T& data) const
  {
    sigc::slot<void, GNode*, const T&, GNode*> real_slot = sigc::ptr_fun(on_compare_child);

    GNode* child = 0;
    type_foreach_gnode_slot bound_slot = sigc::bind(real_slot, data, child);

    g_node_children_foreach(gobject_, (GTraverseFlags)flags, on_wrap_compare_child, reinterpret_cast<gpointer>(&bound_slot));
    
    return lookup(child);
  }
  

  /** Finds a node in a tree.
   *
   * @param order The order in which nodes are visited: 
   * TRAVERSE_IN_ORDER, TRAVERSE_PRE_ORDER, TRAVERSE_POST_ORDER, or TRAVERSE_LEVEL_ORDER
   * @param flags Which types of children are to be visited: one of TRAVERSE_ALL, TRAVERSE_LEAVES and TRAVERSE_NON_LEAVES.
   * @return The found node, or 0 if the data is not found.
   */
  Tree<T>* find(TraverseType order, TraverseFlags flags, const T& data) const
  {
    //We use a sigc::slot for the C callback, so we can bind some extra data.
    sigc::slot<gboolean, GNode*, const T&, GNode**> real_slot = sigc::ptr_fun(on_compare_node);

    GNode* child = 0;
    type_traverse_gnode_slot bound_slot = sigc::bind(real_slot, data, &child);
    
    g_node_traverse(gobject_, (GTraverseType)order, (GTraverseFlags)flags, -1, on_wrap_compare_node, reinterpret_cast<gpointer>(&bound_slot));

    if(0 == child)
      return 0;
  
    GNode* cursor = child;
    unsigned int depth = g_node_depth(cursor) - g_node_depth(gobject_);
    std::stack<iterator, std::deque<iterator> > stack;
    Tree<T>* treecursor = const_cast<Tree<T>*>(this);
  
    for(unsigned int i = 0; i < depth; ++i)
    {
      stack.push(cursor);
      cursor = cursor->parent;
    }
  
    for(;!stack.empty();stack.pop())
    {
      treecursor = treecursor->lookup(stack.top());
      if(0 == treecursor)
        return 0;
    }
  
    return treecursor;
  }
  

  /** Gets the position of the first child which contains the given data.
   *
   * @param data The data to find.
   * @return The index of the child which contains data, 
   * or -1 if the data is not found.
   */
  int index_of(const T& data) const
  {
    int index = 0;
    for(Tree<T>* i = nth_child(index);
      i != 0; i = nth_child(++index))
    {
      if((i->data()) == data)
      {
        return index;
      }
    }
    return -1;
  }
  

  /** Gets the position with respect to its siblings. 
   * child must be a child of node.
   * The first child is numbered 0, the second 1, and so on.
   *
   * @param child A child
   * @return The position of @a child with respect to its siblings.
   */
  int position_of(const Tree<T>& child) const
  {
    return g_node_child_position(gobject_, const_cast<GNode*>(child.gobj()));
  }
  

  /** Gets the first child.
   *
   * @return The first child, or 0 if the node has no children. 
   */
  Tree<T>* first_child() const
  {
    return lookup(g_node_first_child(gobject_));
  }
  

  /** Gets the last child.
   *
   * @return The last child, or 0 if the node has no children.
   */
  Tree<T>* last_child() const
  {
    return lookup(g_node_last_child(gobject_));
  }
  

  /** Gets the nth child.
   *
   * @return The nth child, or 0 if n is too large.
   */
  Tree<T>* nth_child(int n) const
  {
    return lookup(g_node_nth_child(gobject_, n));
  }
  

  /** Gets the first sibling
   * @return The first sibling, or 0 if the node has no siblings.
   */
  Tree<T>* first_sibling() const
  {
    return parent_->lookup(g_node_first_sibling(gobject_));
  }
  

  /** Gets the previous sibling.
   *
   * @return The previous sibling, or 0 if the node has no siblings.
   */
  Tree<T>* prev_sibling() const
  {
    return parent_->lookup(g_node_prev_sibling(gobject_));
  }
  

  /** Gets the next sibling
   *
   * @return The next sibling, or 0 if the node has no siblings.
   */
  Tree<T>* next_sibling() const
  {
    return parent_->lookup(g_node_next_sibling(gobject_));
  }
  

  /** Gets the last sibling.
   *
   * @return The last sibling, or 0 if the node has no siblings.
   */
  Tree<T>* last_sibling() const
  {
    return parent_->lookup(g_node_last_sibling(gobject_));
  }
  

  /** Returns true if this is a leaf node.
   *
   * @return true if this is a leaf node.
   */
  bool is_leaf() const
  {
    return G_NODE_IS_LEAF(gobject_);
  }

  /** Returns true if this is the root node.
   *
   * @return true if this is the root node.
   */
  bool is_root() const
  {
    return G_NODE_IS_ROOT(gobject_);
  }

  /** Gets the depth of this node.
   * The root node has a depth of 1.
   * For the children of the root node the depth is 2. And so on.
   *
   * @return the depth of this node
   */
  unsigned int depth() const
  {
    return g_node_depth(gobject_);
  }
  

  /** Gets the number of nodes in a tree.
   *
   * @param flags Which types of children are to be counted: one of TRAVERSE_ALL, TRAVERSE_LEAVES and TRAVERSE_NON_LEAVES
   * @return The number of nodes in the tree.
   */
  unsigned int node_count(TraverseFlags flags) const
  {
    return g_node_n_nodes(gobject_, (GTraverseFlags)flags);
  }
  

  /** Gets the number children.
   *
   * @return The number of children.
   */
  unsigned int child_count() const
  {
    return g_node_n_children(gobject_);
  }
  

  /** Returns true if this is an ancestor of @a descendant.
   * This is true if this is the parent of @a descendant,
   * or if this is the grandparent of @a descendant etc.
   *
   * @param descendant A node.
   * @return true if this is an ancestor of descendant.
   */
  bool is_ancestor(const Tree<T>& descendant) const
  {
    return g_node_is_ancestor(gobject_, const_cast<GNode*>(descendant.gobj()));
  }
  

  /** Gets the maximum height of all branches beneath this node.
   * This is the maximum distance from the node to all leaf nodes.
   * If root has no children, 1 is returned. If root has children, 2 is returned. And so on.
   *
   * @return The maximum height of all branches.
   */
  unsigned int max_height() const
  {
    return g_node_max_height(gobject_);
  }
  

  /** Unlinks a node from a tree, resulting in two separate trees.
   */
  void unlink(Tree<T>& child)
  {
    children_.erase(child.gobj());
    child.parent(&child);
    g_node_unlink(child.gobj());
  }
  

  /// Accessor for this node's iterator
  iterator iter() const
  {
    return gobject_;
  }

  /// Accessor for this node's data
  T& data() const
  {
    return *(reinterpret_cast<T*>(gobject_->data));
  }

  /** Lookup a child by its iterator.
   *
   * @param child The iterator of the desired child.
   * @return The child if found, else 0.
   */
  Tree<T>* lookup(const iterator child) const
  {
    typename NodeMap::const_iterator i = children_.find(child);
    return (children_.end() == i)? 0: i->second;
  }

  // For auto-wrapping
  GNode*       gobj()       { return gobject_; }
  const GNode* gobj() const { return gobject_; }

  // Leaving these unimplemented for now
  
  
protected:

  /** Accessor for this node's parent.
   *
   * @param newparent Provides a new parent for this node. Use 0 to get the current parent.
   * @return The node's parent.
   */
  Tree<T>* parent(Tree<T> *newparent = 0)
  {
    return (0 == newparent) ? parent_: (parent_ = newparent);
  }

  /// Wrapper for invoking a TraverseFunc.
  static gboolean wrap_traverse_slot(GNode* node, gpointer slot)
  {
    TraverseFunc tf = reinterpret_cast<TraverseFunc>(slot);
    if(tf)
      return ((*tf)(*(reinterpret_cast<T*>(node->data)))) ? TRUE : FALSE;
    else
      return FALSE;
  }

  /// Wrapper for invoking a ForeachFunc.
  static void wrap_foreach_slot(GNode* node, gpointer slot)
  {
    ForeachFunc ff = reinterpret_cast<ForeachFunc>(slot);
    if(ff)
      (*ff)(*(reinterpret_cast<T*>(node->data)));
  }

  /// Method for comparing a single child (Internal use).
  static void on_compare_child(GNode* node, const T& needle, GNode* result)
  {
    if((0 != result) && ((*(reinterpret_cast<T*>(node->data))) == needle))
    {
      result = node;
    }
  }

  /// Wrapper for invoking a sigc::slot<void,GNode*> (Internal use).
  static void on_wrap_compare_child(GNode* node, gpointer data)
  {
    type_foreach_gnode_slot* slot = reinterpret_cast<type_foreach_gnode_slot*>(data);
    (*slot)(node);
  }

  /// Method for comparing a single node (Internal use).
  static gboolean on_compare_node(GNode* node, const T& needle, GNode** result)
  {
    if((*(reinterpret_cast<T*>(node->data))) == needle)
    {
      *result = node;
      return TRUE;
    }

    return FALSE;
  }

  /// Wrapper for invoking a sigc::slot<gboolean,GNode*> (Internal use).
  static gboolean on_wrap_compare_node(GNode* node, gpointer data)
  {
    type_traverse_gnode_slot* slot = reinterpret_cast<type_traverse_gnode_slot*>(data);
    return (*slot)(node);
  }

  typedef sigc::slot<gboolean, GNode*> type_traverse_gnode_slot;
  typedef sigc::slot<void, GNode*> type_foreach_gnode_slot;

  GNode* gobject_;
  bool owns_gobject_;

  // Some metadata must be stored.
  NodeMap children_;
  Tree<T>* parent_;


};

} // namespace Glib


#endif /* _GLIBMM_TREE_H */

