/*
 * Copyright (C) 1998-2002 The gtkmm Development Team
 *
 * 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 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
 * 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
 */

#include <vector>

#include <gtk/gtk.h>
#include <glibmm/interface.h>
#include <gtkmm/treeiter.h>
#include <gtkmm/treemodelcolumn.h>

_DEFS(gtkmm,gtk)
_PINCLUDE(glibmm/private/interface_p.h)

namespace Gtk
{

class TreeModelFilter;
class TreeModelSort;
class TreePath;
class TreeRowReference;

_CC_INCLUDE(gtk/gtk.h)
_WRAP_ENUM(TreeModelFlags, GtkTreeModelFlags)

//TODO: Remove any mention of null arguments from the method documentation, by adding overrides in gtk_docs_override.xml.
/** This class defines a generic tree interface for use by the Gtk::TreeView widget.
 * @ingroup TreeView
 *
 * It is is designed to be usable with any appropriate data structure. The
 * programmer just has to implement this interface on their own data type for
 * it to be viewable by a Gtk::TreeView widget.
 *
 * The model is represented as a hierarchical tree of strongly-typed, columned
 * data. In other words, the model can be seen as a tree where every node has
 * different values depending on which column is being queried.  The type of
 * data found in a column is determined by TreeModel::Column<> templates.
 * The types are homogeneous per column across all nodes. It is important to note that this
 * interface only provides a way of examining a model and observing changes.
 * The implementation of each individual model decides how and if changes are
 * made.
 *
 * In order to make life simpler for programmers who do not need to write their
 * own specialized model, two generic models are provided - the Gtk::TreeStore
 * and the Gtk::ListStore. To use these, the developer simply pushes data into
 * these models as necessary. These models provide the data structure as well
 * as all appropriate tree interfaces. As a result, implementing drag and drop,
 * sorting, and storing data is trivial. For the vast majority of trees and
 * lists, these two models are sufficient.
 *
 * Models are accessed on a node/column level of granularity. One can query for
 * the value of a model at a certain node and a certain column on that node.
 * There are two structures used to reference a particular node in a model.
 * They are the @link Gtk::TreePath Path@endlink and the iterator. Most of the interface consists of
 * operations on an @link Gtk::TreeIter iterator@endlink.
 *
 * A @link Gtk::TreePath Gtk::TreeModel::Path@endlink is essentially a potential node. It is a location on a model that may
 * or may not actually correspond to a node on a specific model.
 *
 * By contrast, an @link Gtk::TreeIter Gtk::TreeModel::iterator@endlink  is a reference to a specific node on a specific
 * model. One can convert a path to an @link Gtk::TreeIter iterator@endlink by calling Gtk::TreeModel::get_iter().
 * These iterators are the primary way of accessing a model and are similar to the iterators
 * used by Gtk::TextBuffer. The model interface defines a set of operations
 * using them for navigating the model.
 *
 * The @link Gtk::TreeRowReference RowReference@endlink is also useful, because it remains
 * valid as long as there is an existing row pointed to by it's path. You can convert between RowReferences and iterators and @link Gtk::TreePath Path@endlink s.
 */
class TreeModel : public Glib::Interface
{
  _CLASS_INTERFACE(TreeModel, GtkTreeModel, GTK_TREE_MODEL, GtkTreeModelIface)
  _IGNORE(
      gtk_tree_model_iter_parent, gtk_tree_model_get_iter, gtk_tree_model_get,
      gtk_tree_model_get_iter_from_string, gtk_tree_model_get_string_from_iter,
      gtk_tree_model_iter_nth_child,
      gtk_tree_model_ref_node, gtk_tree_model_get_valist,
      gtk_tree_model_iter_next, gtk_tree_model_iter_previous, gtk_tree_model_iter_has_child,
      gtk_tree_model_unref_node, gtk_tree_model_iter_children,
      gtk_tree_model_iter_n_children, gtk_tree_model_get_iter_first,
      gtk_tree_model_get_value)

public:
  typedef TreeModelColumnRecord ColumnRecord;

  typedef TreeNodeChildren Children;
  typedef TreeNodeConstChildren ConstChildren;
  typedef Children::iterator iterator;
  typedef ConstChildren::const_iterator const_iterator;

  typedef TreeConstRow ConstRow;
  typedef TreeRow Row;
  typedef TreePath Path;
  typedef TreeRowReference RowReference;

  //These are part of GtkTreeModelFilter or GtkTreeModelSort, not GtkTreeModel:
  _IGNORE(gtk_tree_model_filter_new, gtk_tree_model_sort_new_with_model)

  /** Returns a valid iterator pointing to @a path.
   *
   * @param path The @link Gtk::TreePath Gtk::TreeModel::Path@endlink.
   * @result A valid iterator pointing to the path, or an invalid iterator if that is not possible.
   */
  iterator get_iter(const Path& path);

  /** Returns a valid iterator pointing to @a path.
   *
   * @param path The @link Gtk::TreePath Gtk::TreeModel::Path@endlink.
   * @result A valid iterator pointing to the path, or an invalid iterator if that is not possible.
   */
  const_iterator get_iter(const Path& path) const;

  /** Returns a valid iterator pointing to @a path_string.
   *
   * @param path_string The path, as a string representation.
   * @result A valid iterator pointing to the path, or an invalid iterator if that is not possible.
   */
  iterator get_iter(const Glib::ustring& path_string);

  /** Returns a valid iterator pointing to @a path_string.
   *
   * @param path_string The path, as a string representation.
   * @result A valid iterator pointing to the path, or an invalid iterator if that is not possible.
   */
  const_iterator get_iter(const Glib::ustring& path_string) const;

  ///This returns an STL-like container API, for iterating over the rows.
  Children children();

  ///This returns an STL-like container API, for iterating over the rows.
  const ConstChildren children() const;

  _IGNORE(gtk_tree_model_foreach)

  /** For example,
   * void on_foreach(const Gtk::TreeModel::iterator& iter);
   *
   * If the callback function returns true, then the tree ceases to be walked, and foreach_iter() returns.
   */
  typedef sigc::slot<bool(const TreeModel::iterator&)> SlotForeachIter;

  /** Calls a callback slot on each node in the model in a depth-first fashion.
   * If the callback function returns true, then the tree ceases to be walked, and foreach_iter() returns.
   *
   * @param slot The function to call for each selected node.
   */
  void foreach_iter(const SlotForeachIter& slot);

  /** For example,
   * void on_foreach(const Gtk::TreeModel::Path& path);
   *
   * If the callback function returns true, then the tree ceases to be walked, and foreach_path() returns.
   */
  typedef sigc::slot<bool(const TreeModel::Path&)> SlotForeachPath;

  /** Calls a callback slot on each node in the model in a depth-first fashion.
   * If the callback function returns true, then the tree ceases to be walked, and foreach_path() returns.
   *
   * @param slot The function to call for each selected node.
   */
  void foreach_path(const SlotForeachPath& slot);

  /** For example,
   * void on_foreach(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter);
   *
   * If the callback function returns true, then the tree ceases to be walked, and foreach() returns.
   */
  typedef sigc::slot<bool(const TreeModel::Path&, const TreeModel::iterator&)> SlotForeachPathAndIter;

  /** Calls a callback slot on each node in the model in a depth-first fashion.
   * If the callback function returns true, then the tree ceases to be walked, and foreach() returns.
   *
   * @param slot The function to call for each selected node.
   */
  void foreach(const SlotForeachPathAndIter& slot);

  _WRAP_METHOD(TreeModelFlags get_flags() const, gtk_tree_model_get_flags)
  _WRAP_METHOD(int get_n_columns() const, gtk_tree_model_get_n_columns)
  _WRAP_METHOD(GType get_column_type(int index) const, gtk_tree_model_get_column_type)
  //TODO: A C++-type version of get_column_type()?

  _WRAP_METHOD(TreeModel::Path get_path(const const_iterator& iter) const, gtk_tree_model_get_path)

  _WRAP_METHOD(void row_changed(const Path& path, const iterator& iter), gtk_tree_model_row_changed)
  _WRAP_METHOD(void row_inserted(const Path& path, const iterator& iter), gtk_tree_model_row_inserted)
  _WRAP_METHOD(void row_has_child_toggled(const Path& path, const iterator& iter), gtk_tree_model_row_has_child_toggled)
  _WRAP_METHOD(void row_deleted(const Path& path), gtk_tree_model_row_deleted)

 /** Emits the "rows_reordered" signal on the tree model.  This should be called by
  * custom models when their rows have been reordered.
  *
  * @param path A tree path pointing to the tree node whose children have been reordered.
  * @param iter A valid iterator pointing to the node whose children have been reordered. See also, rows_reordered(const Path& path, const std::vector<int>& new_order), if the path has a depth of 0.
  * @param new_order An array of integers mapping the current position of each child
  * to its old position before the re-ordering, i.e. @a new_order<literal>[newpos] = oldpos.
  */
  void rows_reordered(const Path& path, const iterator& iter, const std::vector<int>& new_order);
  _IGNORE(gtk_tree_model_rows_reordered_with_length)

 /** Emits the "rows_reordered" signal on the tree model.  This should be called by
  * custom models when their rows have been reordered. This method overload is for nodes whose
  * path has a depth of 0.
  * @newin{2,10}
  *
  * @param path A tree path pointing to the tree node whose children have been reordered.
  * @param new_order An array of integers mapping the current position of each child
  * to its old position before the re-ordering, i.e. @a new_order<literal>[newpos] = oldpos.
  */
  void rows_reordered(const Path& path, const std::vector<int>& new_order);

  _WRAP_METHOD(void rows_reordered(const Path& path, const iterator& iter, int* new_order), gtk_tree_model_rows_reordered)

  _WRAP_METHOD(Glib::ustring get_string(const iterator& iter) const, gtk_tree_model_get_string_from_iter)

#m4 _CONVERSION(`GtkTreeIter*',`const iterator&',`Gtk::TreeModel::iterator(self, $3)')
#m4 _CONVERSION(`GtkTreeIter*',`const TreeModel::iterator&',`Gtk::TreeModel::iterator(self, $3)')
  _WRAP_SIGNAL(void row_changed(const TreeModel::Path& path, const TreeModel::iterator& iter), "row_changed")
  _WRAP_SIGNAL(void row_inserted(const TreeModel::Path& path, const TreeModel::iterator& iter), "row_inserted")
  _WRAP_SIGNAL(void row_has_child_toggled(const TreeModel::Path& path, const TreeModel::iterator& iter), "row_has_child_toggled")
  _WRAP_SIGNAL(void row_deleted(const TreeModel::Path& path), "row_deleted")
  _WRAP_SIGNAL(void rows_reordered(const TreeModel::Path& path, const TreeModel::iterator& iter, int* new_order), "rows_reordered")

protected:
  _WRAP_VFUNC(TreeModelFlags get_flags() const, get_flags)
  _WRAP_VFUNC(int get_n_columns() const, get_n_columns)
  _WRAP_VFUNC(GType get_column_type(int index) const, get_column_type)

  //These are only for deriving new TreeModels, which isn't very common or easy:

  /** Override and implement this in a derived TreeModel class.
   * Sets @a iter_next to refer to the node following @a iter it at the current level.
   * If there is no next iter, false is returned and iter_next is set to be invalid.
   *
   * @param iter An iterator.
   * @param iter_next An iterator that will be set to refer to the next node, or will be set as invalid.
   * @result true if the operation was possible.
   */
  virtual bool iter_next_vfunc(const iterator& iter, iterator& iter_next) const;

  /** Override and implement this in a derived TreeModel class.
   * Sets @a iter to a valid iterator pointing to @a path
   *
   * @param path An path to a node.
   * @param iter An iterator that will be set to refer to a node to the path, or will be set as invalid.
   * @result true if the operation was possible.
   */
  virtual bool get_iter_vfunc(const Path& path, iterator& iter) const;

  /** Override and implement this in a derived TreeModel class.
   * Sets @a iter to refer to the first child of @a parent. If @a parent has no children,
   * false is returned and @a iter is set to be invalid.
   *
   * @param parent An iterator.
   * @param iter An iterator that will be set to refer to the firt child node, or will be set as invalid.
   * @result true if the operation was possible.
   */
  virtual bool iter_children_vfunc(const iterator& parent, iterator& iter) const;

  /** Override and implement this in a derived TreeModel class.
   * Sets @a iter to be the parent of @a child. If @a child is at the toplevel, and
   * doesn't have a parent, then @a iter is set to an invalid iterator and false
   * is returned.
   *
   * @param child An iterator.
   * @param iter An iterator that will be set to refer to the parent node, or will be set as invalid.
   * @result true if the operation was possible.
   */
  virtual bool iter_parent_vfunc(const iterator& child, iterator& iter) const;

  /** Override and implement this in a derived TreeModel class.
   * Sets @a iter to be the child of @a parent using the given index.  The first
   * index is 0.  If @a n is too big, or @a parent has no children, @a iter is set
   * to an invalid iterator and false is returned.
   * See also iter_nth_root_child_vfunc()
   *
   * @param parent An iterator.
   * @param n The index of the child node to which @a iter should be set.
   * @param iter An iterator that will be set to refer to the nth node, or will be set as invalid.
   * @result true if the operation was possible.
   */
  virtual bool iter_nth_child_vfunc(const iterator& parent, int n, iterator& iter) const;

   /** Override and implement this in a derived TreeModel class.
   * Sets @a iter to be the child of at the root level using the given index.  The first
   * index is 0.  If @a n is too big, or if there are no children, @a iter is set
   * to an invalid iterator and false is returned.
   * See also iter_nth_child_vfunc().
   *
   * @param n The index of the child node to which @a iter should be set.
   * @param iter An iterator that will be set to refer to the nth node, or will be set as invalid.
   * @result true if the operation was possible.
   */
  virtual bool iter_nth_root_child_vfunc(int n, iterator& iter) const;



#m4begin
dnl// We want to hand-code these C vfunc callbacks,
dnl// so that we can do forward them to C++ methods with different parameters and return types.
dnl
  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
    klass->iter_next = &iter_next_vfunc_callback;
    klass->get_iter = &get_iter_vfunc_callback;
    klass->iter_children = &iter_children_vfunc_callback;
    klass->iter_parent = &iter_parent_vfunc_callback;
    klass->iter_nth_child = &iter_nth_child_vfunc_callback;
    klass->iter_n_children = &iter_n_children_vfunc_callback;
  _SECTION(SECTION_PH_VFUNCS)
    static gboolean iter_next_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter);
    static gboolean get_iter_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter, GtkTreePath* path);
    static gboolean iter_children_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter, GtkTreeIter* parent);
    static gboolean iter_parent_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter, GtkTreeIter* child);
    static gboolean iter_nth_child_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter, GtkTreeIter* parent, int n);
    static int iter_n_children_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter);
  _POP()
#m4end

  /** Override and implement this in a derived TreeModel class.
   * Returns true if @a iter has children, false otherwise.
   *
   * @param iter The iterator to test for children.
   * @result true if @a iter has children.
   */
  _WRAP_VFUNC(bool iter_has_child(const iterator& iter) const, iter_has_child)

  /** Override and implement this in a derived TreeModel class.
   * Returns the number of children that @a iter has.
   * See also iter_n_root_children_vfunc().
   *
   * @param iter The iterator to test for children.
   * @result The number of children of @a iter.
   */
  virtual int iter_n_children_vfunc(const iterator& iter) const;

  /** Override and implement this in a derived TreeModel class.
   * Returns the number of toplevel nodes.
   * See also iter_n_children().
   *
   * @result The number of children at the root level.
   */
  virtual int iter_n_root_children_vfunc() const;

  /** Override and implement this in a derived TreeModel class.
   * Lets the tree ref the node.  This is an optional method for models to
   * implement.  To be more specific, models may ignore this call as it exists
   * primarily for performance reasons.
   *
   * This function is primarily meant as a way for views to let caching model know
   * when nodes are being displayed (and hence, whether or not to cache that
   * node.)  For example, a file-system based model would not want to keep the
   * entire file-hierarchy in memory, just the sections that are currently being
   * displayed by every current view.
   *
   * A model should be expected to be able to get an iter independent of its
   * reffed state.
   *
   * @param iter the iterator.
   */
  _WRAP_VFUNC(void ref_node(const iterator& iter) const, ref_node)

  /** Override and implement this in a derived TreeModel class.
   * Lets the tree unref the node.  This is an optional method for models to
   * implement.  To be more specific, models may ignore this call as it exists
   * primarily for performance reasons.
   *
   * For more information on what this means, see unref_node_vfunc().
   * Please note that nodes that are deleted are not unreffed.
   *
   * @param iter the iterator.
   */
  _WRAP_VFUNC(void unref_node(const iterator& iter) const, unref_node)

  /** Override and implement this in a derived TreeModel class.
   * Returns a Path referenced by @a iter.
   *
   * @param iter The iterator.
   * @result The path.
   */
#m4 _CONVERSION(`TreeModel::Path', `GtkTreePath*', `($3).gobj_copy()')
  _WRAP_VFUNC(TreeModel::Path get_path(const iterator& iter) const, get_path)

  /** Override and implement this in a derived TreeModel class.
   * Initializes and sets @a value to that at @a column.
   *
   * @param iter The iterator.
   * @param column The column to lookup the value at.
   * @param value An empty Glib:Value to set.
   */
  _WRAP_VFUNC(void get_value(const iterator& iter, int column, Glib::ValueBase& value) const, get_value)

  //Called by TreeRow, which is a friend class:
  //The comment about row_changed() in the documentation is based on my reading of the source of
  //gtk_list_store_set_value() and gtk_tree_store_set_value(). murrayc
  /** Override and implement this in a derived TreeModel class, so that Row::operator() and
   * Row::set_value() work.
   * Your implementation of set_value_impl() should call row_changed() after changing the value.
   */
  virtual void set_value_impl(const iterator& iter, int column, const Glib::ValueBase& value);

  //This might not need to be virtual, but it's not a big deal. murrayc.
  virtual void get_value_impl(const const_iterator& iter, int column, Glib::ValueBase& value) const;

  friend class Gtk::TreeModelFilter;
  friend class Gtk::TreeModelSort;
  friend class Gtk::TreeConstRow;
  friend class Gtk::TreeRow;
};

} // namespace Gtk
