/* 
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 *
 * 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; version 2 of the
 * License.
 * 
 * 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 St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */
#ifndef __MFORMS_SIMPLEGRIDVIEW_H__
#define __MFORMS_SIMPLEGRIDVIEW_H__

#include <mforms/view.h>
#include <string>
#include <vector>
#include <map>
#include <boost/signals2.hpp>

namespace mforms
{
enum CellType {CellInvalid = 1 << 0, CellText = 1 << 1, CellBool = 1 << 2, CellEnum = 1 << 3, CellHeader = 1 << 4, CellGroupHeader = 1 << 5};
enum CellsAccess {CellsReadable = 0, CellsEditable = 1};
enum Shade {ShadeNone = 0, ShadeFind = 1 << 0, ShadeFilter = 1 << 1};
enum IconVisibility {NotVisible = 0, ShowAlways = 1, ShowOnHover = 2};
enum IconPos {IconLeft = 0, IconRight = 1};

//==============================================================================
//
//==============================================================================
class MFORMS_EXPORT SimpleGridPath
{
  public:
    int size() const {return _indices.size();}

    void append(const int i) {_indices.push_back(i);}

    int index(const int i) {return _indices[i];}
    void set_index(const int i, const int index) {_indices[i] = index;}

    #ifndef SWIG
    int& at(const int i) {return _indices.at(i);}
    const int& at(const int i) const {return _indices[i];}

    int& operator[](const int i) {return _indices.at(i);}
    const int& operator[](const int i) const {return _indices[i];}
    #endif

    bool operator==(const SimpleGridPath& r) {return _indices == r._indices;}
  private:
    std::vector<int>    _indices;
};

struct SimpleGridImplPtrs;

//==============================================================================
//
//==============================================================================
class MFORMS_EXPORT SimpleGrid : public mforms::View
{
  public:
    SimpleGrid();

    typedef SimpleGridPath  Path;

    // signals to notify customers about data change
    //typedef boost::signals2::signal<void, const Path&, const int>     SignalCellValueChanged;// (rowid, column)
    //typedef boost::function<bool (SimpleGrid*, const Path&)>     ProcessRowSlot;

    //typedef boost::function<bool (SimpleGrid*, const Value&)>              ValidationSlot;
    //typedef boost::function<bool (SimpleGrid*, const Value&)>              FindSlot;
    //typedef boost::function<bool (SimpleGrid*, const Path&, const int)>    ValidationHintSlot; // (self*, rowid, col_id)

    int add_column(const std::string& name);
    void clear();

    // rows additions
    // append_header adds a top most row which will be treated in special way. It must be collapsible
    // also it should collapse/expand on double click.
    Path  append_header(const std::string& gid);
    // Appends a new row to the @path's first index. So if I pass a path like [0:1:2], the addition will be
    // done to the 0. Empty path instructs to add to the root.
    Path  append_row(const Path& path);

    bool set_str_value(const Path& rid, const int col_id, const std::string& cv, const bool editable);
    //bool set_value(const Path& rid, const int col_id, const char* cv, const bool editable);
    bool set_bool_value(const Path& rid, const int col_id, bool cv, const bool editable);
    std::string get_value(const Path& rid, const int col_id, mforms::CellType* type);
    // passing @col_id == -1 for set_cell_type applies type for the entire @path row
    void set_cell_type(const Path& path, const int col_id, const mforms::CellType type);

    // set_fg, set_bg, set_underline are not mandatory to implement
    bool set_fg(const Path& rid, const int col_id, const double r, const double g, const double b);
    bool set_bg(const Path& rid, const int col_id, const double r, const double g, const double b);
    bool set_underline(const Path& rid, const int col_id, const bool is_on);

    bool set_enum(const Path& rid, const int col_id, const std::vector<std::string> &list); // for swig & python, Slow!!
    #ifndef SWIG
    // ownership of the vector @list will be passed to the GridCell
    bool set_enum_def(const Path& rid, const int col_id, std::vector<std::string>* list);
    // ownership of the char** @list will not be passed to the GridCell
    bool set_enum_def_c(const Path& rid, const int col_id, const char** const list);
    #endif

    void shade(const Path& rid, const Shade shade, const int col_id = -1);
    void unshade(const Path& rid, const Shade shade, const int col_id = -1);
    bool has_shade(const Path& rid, const int col_id, const Shade s);
    void scroll_to_row(const Path& rid);

    void set_row_tag(const Path& path, const std::string& tag);
    std::string get_row_tag(const Path& path);

    void set_row_caption(const Path& path, const std::string& caption);
    std::string get_row_caption(const Path& path);

    // Specifying empty iconpath removes icon
    void set_action_icon(const Path& rid, const int col, const std::string& iconpath, const IconVisibility visible, const IconPos pos);

    #ifndef SWIG
    boost::signals2::signal<void (const Path&, const int, const IconPos)>*  signal_content_action()
    {
      return &_signal_content_action;
    }
    boost::signals2::signal<void (const Path&, const int)>*  signal_content_edited()
    {
      return &_signal_content_edited;
    }
    boost::signals2::signal<void (const Path&, const int)>*  signal_ro_content_clicked()
    {
      return &_signal_ro_content_clicked;
    }
    #endif

    // set_validator sets callable slot, which verifies cell's value and returns true of false
    //bool set_validator(const Path& rid, const int col_id, ValidationSlot vs = ValidationSlot());
    // set_validator_hinter sets callable slot, which notifies user about correct value or value range
    // exact way of notifying is tbd
    //bool set_validator_hinter(const Path& rid, const int col_id, ValidationHintSlot vs = ValidationHintSlot());

    // filter_rows filters rows according to criteria defined in callable slot. If slot returns true
    // the row must be visible. Order of rows within groups must be preserved, the group header
    // also must stay.
    //void filter_rows(ProcessRowSlot slot);
    //void reset_filter();

    // Function to do lookups within a column and all-columns.
    //Path find_in_column(const Path& start, const int col_id, const Value& v);
    //Path find(const Path& start, FindSlot fslot);
    // Highlighting and unhighlighting rows(col_id == -1) or single cells
    //void highlight(const Path& path, const int col_id = -1);
    //void unhighlight(const Path& path, const int col_id = -1);

    //SignalCellValueChanged& signal_cell_value_changed()
    //{
    //  return _signal_cell_changed;
    //}
  private:
    boost::signals2::signal<void (const Path&, const int)>                      _signal_ro_content_clicked;
    boost::signals2::signal<void (const Path&, const int)>                      _signal_content_edited;
    boost::signals2::signal<void (const Path&, const int, const IconPos)>       _signal_content_action;

  #ifndef DOXYGEN_SHOULD_SKIP_THIS
  #ifndef SWIG
    SimpleGridImplPtrs  *_impl;
  #endif
  #endif
};

#ifndef DOXYGEN_SHOULD_SKIP_THIS
#ifndef SWIG
//==============================================================================
//
//==============================================================================
struct MFORMS_EXPORT SimpleGridImplPtrs
{
  bool (__stdcall *create)(SimpleGrid*);
  int (__stdcall *add_column)(SimpleGrid*, const std::string& name);
  void (__stdcall *clear)(SimpleGrid*);

  // rows additions
  SimpleGridPath (__stdcall *append_header)(SimpleGrid*, const std::string& gid);
  SimpleGridPath (__stdcall *append_row)(SimpleGrid*, const SimpleGridPath& path);

  bool (__stdcall *set_str_value)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, const std::string& cv, const bool editable);
  bool (__stdcall *set_bool_value)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, bool cv, const bool editable);
  std::string (__stdcall *get_value)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, mforms::CellType* type);

  void (__stdcall *set_cell_type)(SimpleGrid*, const SimpleGridPath& path, const int col_id, const mforms::CellType type);

  bool (__stdcall *set_fg)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, const double r, const double g, const double b);
  bool (__stdcall *set_bg)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, const double r, const double g, const double b);
  bool (__stdcall *set_underline)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, const bool is_on);

  // for python code (the impl is inefficient
  bool (__stdcall *set_enum)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, const std::vector<std::string>& list);
  // ownership of the vector @list will be passed to the GridCell
  bool (__stdcall *set_enum_def)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, std::vector<std::string>* list);
  // ownership of the char** @list will not be passed to the GridCell
  bool (__stdcall *set_enum_def_c)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, const char** const list);

  void (__stdcall *shade)(SimpleGrid*, const SimpleGridPath& rid, const Shade shade, const int col_id);
  void (__stdcall *unshade)(SimpleGrid*, const SimpleGridPath& rid, const Shade shade, const int col_id);
  bool (__stdcall *has_shade)(SimpleGrid*, const SimpleGridPath& rid, const int col_id, const Shade s);
  void (__stdcall *scroll_to_row)(SimpleGrid*, const SimpleGridPath& rid);

  void (__stdcall *set_row_tag)(SimpleGrid*, const SimpleGridPath& path, const std::string& tag);
  std::string (__stdcall *get_row_tag)(SimpleGrid*, const SimpleGridPath& path);

  void (__stdcall *set_row_caption)(SimpleGrid*, const SimpleGridPath& path, const std::string& caption);
  std::string (__stdcall *get_row_caption)(SimpleGrid*, const SimpleGridPath& path);

  void (__stdcall *set_action_icon)(SimpleGrid*, const SimpleGridPath& rid, const int col, const std::string& iconpath, const IconVisibility visible, const IconPos pos);
};
#endif
#endif

}

#endif
