// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WMODEL_INDEX_H_
#define WMODEL_INDEX_H_

#include <vector>
#include <set>
#include <boost/any.hpp>

#include <Wt/WDllDefs.h>
#include <Wt/WFlags>

namespace Wt {

class WAbstractItemModel;

/*! \defgroup modelview Model/view system
 *  \brief Classes that implement %Wt's model/view system.
 */

/*! \brief Enumeration that indicates a role for a data item.
 *
 * A single data item can have data associated with it corresponding
 * to different roles. Each role may be used by the corresponding view
 * class in a different way.
 *
 * \sa WModelIndex::data()
 *
 * \ingroup modelview
 */
enum ItemDataRole {
  DisplayRole = 0,      //!< Role for textual representation
  DecorationRole = 1,   //!< Role for the url of an icon
  EditRole = 2,         //!< Role for the edited value
  StyleClassRole = 3,   //!< Role for the style class
  /*! Role that indicates the check state. Is of type <tt>bool</tt>,
   * unless the Wt::ItemIsTristate flag is set, then is of type
   * Wt::CheckState.
   */
  CheckStateRole = 4,   
  ToolTipRole = 5,      //!< Role for a tooltip
  InternalPathRole = 6, //!< Role for an internal path activated when clicked
  UrlRole = 7,          //!< Role for a url activated when clicked
  LevelRole = 8,        //!< Level in aggregation, for header data.
  MarkerPenColorRole = 16,  //!< Marker pen color (for Chart::WCartesianChart)
  MarkerBrushColorRole = 17,//!< Marker brush color (for Chart::WCartesianChart)
  UserRole = 32         //!< First role reserved for user purposes
};

/*! \brief Flags that indicate data item options
 *
 * \sa WModelIndex::flags()
 *
 * \ingroup modelview
 */
enum ItemFlag {
  ItemIsSelectable = 0x1,    //!< Item can be selected
  ItemIsEditable = 0x2,      //!< Item can be edited
  ItemIsUserCheckable = 0x4, //!< Item can be checked
  ItemIsDragEnabled = 0x8,   //!< Item can be dragged
  ItemIsDropEnabled = 0x10,  //!< Item can be a drop target
  /*! Item has tree states. When set, Wt::CheckStateRole data is of type
   * Wt::CheckState
   */
  ItemIsTristate = 0x20,
  ItemIsXHTMLText = 0x40     //!< Item's textual is HTML
};

W_DECLARE_OPERATORS_FOR_FLAGS(ItemFlag)

/*! \brief Enumeration that indicates a sort order.
 *
 * \ingroup modelview
 */
enum SortOrder {
  AscendingOrder,  //!< Ascending sort order
  DescendingOrder  //!< Descending sort order
};

/*! \brief Enumeration that indicates a drop action.
 *
 * \sa WAbstractItemModel::dropEvent()
 *
 * \ingroup modelview
 */
enum DropAction {
  CopyAction = 0x1, //!< Copy the selection
  MoveAction = 0x2  //!< Move the selection (deleting originals)
};

/*! \class WModelIndex Wt/WModelIndex Wt/WModelIndex
 *  \brief An index to a data item in a data model.
 *
 * Indexes are used to indicate a particular item in a
 * WAbstractItemModel. An index points to the item by identifying its
 * row and column location within a parent model index.
 *
 * An index is immutable. The default constructor creates an
 * <i>invalid index</i>, which by convention indicates the parent of
 * top level indexes. Thus, a model that specifies only a list or
 * table of data (but no hierarchical data) would have as valid
 * indexes only indexes that specify the <i>invalid</i> model index as
 * parent.
 *
 * Valid indexes are created by the model, within the protected
 * WAbstractItemModel::createIndex() methods. In this way, models can
 * define an internal pointer or id suitable for identifying items in
 * the model.
 *
 * Upon the model's choice, model indexes for hierarchical models may
 * have an internal Id represented by a int64_t (internalId()), a
 * pointer (internalPointer()).
 *
 * \sa WAbstractItemModel
 *
 * \ingroup modelview
 */
class WT_API WModelIndex
{
public:
  /*! \brief Create an invalid WModelIndex.
   *
   * Returns a model index for which isValid() return \c false.
   */
  WModelIndex();

  /*! \brief Returns the column for this model index.
   *
   * \sa row()
   */
  int column() const { return column_; }

  /*! \brief Returns the row for this model index.
   *
   * \sa column()
   */
  int row() const { return row_; }

  /*! \brief Returns the internal pointer.
   *
   * The internal pointer is used by the model to retrieve the corresponding
   * data.
   *
   * This is only defined when the model created the index using
   * WAbstractItemModel::createIndex(int, int, void *) const.
   *
   * \sa internalId(),
   * \sa WAbstractItemModel::createIndex(int, int, void *) const
   */
  void *internalPointer() const { return reinterpret_cast<void*>(internalId_); }

  /*! \brief Returns the internal id.
   *
   * The internal id is used by the model to retrieve the
   * corresponding data.
   *
   * This is only defined when the model created the index using
   * WAbstractItemModel::createIndex(int, int, uint64_t) const.
   *
   * \sa internalPointer()
   * \sa WAbstractItemModel::createIndex(int, int, uint64_t) const
   */
  uint64_t internalId() const { return internalId_; }

  /*! \brief Returns a model index for a child item.
   *
   * This is a convenience method, and is only defined for indexes
   * that are valid().
   *
   * It has the same function as WAbstractItemModel::index() but is
   * less general because the latter expression may also be used to
   * retrieve top level children, i.e. when \p index is invalid.
   *
   * \sa WAbstractItemModel::index(), isValid()
   */
  WModelIndex child(int row, int column) const;

  /*! \brief Returns an index to the parent.
   *
   * This is a convenience method for WAbstractItemModel::parent().
   *
   * For a top level data item, the parent() is an invalid index (see
   * WModelIndex()).
   *
   * \sa WAbstractItemModel::parent()
   */
  WModelIndex parent() const;

  /*! \brief Returns data in the model at this index.
   *
   * This is a convenience method for WAbstractItemModel::data().
   *
   * \sa WAbstractItemModel::data()
   * \sa ItemDataRole
   */
  boost::any data(int role = DisplayRole) const;

  /*! \brief Returns the flags for this item.
   *
   * This is a convenience method for WAbstractItemModel::flags().
   *
   * \sa WAbstractItemModel::flags()
   * \sa ItemFlag
   */
  WFlags<ItemFlag> flags() const;

  /*! \brief Returns whether the index is a real valid index.
   *
   * Returns \c true when the index points to a valid data item,
   * i.e. at a valid row() and column().
   *
   * An index may be invalid for two reasons:
   *  - an operation requested an index that was out of model bounds,
   *  - or, the index corresponds to the model's top level root item, and is
   *    thus the parent index for top level items.
   */
  bool isValid() const { return model_ != 0; }

  /*! \brief Returns the model to which this (valid) index is bound.
   *
   * This returns the model that created the model index.
   */
  const WAbstractItemModel *model() const { return model_; }

  /*! \brief Comparison operator.
   *
   * Returns \c true only if the indexes point at the same data, in the
   * same model.
   */
  bool operator== (const WModelIndex& other) const;

  /*! \brief Comparison operator.
   *
   * \sa operator==()
   */
  bool operator!= (const WModelIndex& other) const;

  /*! \brief Comparison operator.
   *
   * Returns \c true if the index comes topologically before \p other.
   *
   * Topological order follows the order in which the indexes would be
   * displayed in a tree table view, from top to bottom followed by
   * left to right.
   */
  bool operator< (const WModelIndex& other) const;

  struct UnorderedLess {
    bool operator()(const WModelIndex& i1, const WModelIndex& i2) const;
  };

private:
  const WAbstractItemModel *model_;
  int row_, column_;
  uint64_t internalId_;

  WModelIndex(int row, int column, const WAbstractItemModel *model, void *ptr);
  WModelIndex(int row, int column, const WAbstractItemModel *model,
	      uint64_t id);

  friend class WAbstractItemModel;

  WModelIndex ancestor(int depth) const;
  int depth() const;
};

#ifndef WT_TARGET_JAVA
typedef std::set<WModelIndex> WModelIndexSet;

extern std::size_t hash_value(const Wt::WModelIndex& index);
#else
typedef std::treeset<WModelIndex> WModelIndexSet;
#endif

typedef std::vector<WModelIndex> WModelIndexList;

}

/*! @} */

#endif // WMODEL_INDEX_H_
