#ifndef _LF_GRTTREEVIEW_H_
#define _LF_GRTTREEVIEW_H_

#include <mforms/mforms.h>

#include "lf_view.h"

#include "linux_utilities/treemodel_wrapper.h"

namespace mforms {
namespace gtk {


class GRTTreeViewImpl : public ViewImpl
{
private:
  struct ColumnSpec
  {
    GRTTreeColumnType type;
    int column;
    std::string name;
    bool editable;
  };
  
  Gtk::ScrolledWindow *_swin;
  Gtk::TreeView *_tree;

  Glib::RefPtr<TreeModelWrapper> _store;
  std::vector<ColumnSpec> _columns;

  virtual Gtk::Widget *get_outer() const { return _swin; }
  virtual Gtk::Widget *get_inner() const { return _tree; }


  GRTTreeViewImpl(GRTTreeView *self)
    : ViewImpl(self)
  {
    _swin= Gtk::manage(new Gtk::ScrolledWindow());
    _swin->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
    _swin->set_shadow_type(Gtk::SHADOW_IN);
    _tree= Gtk::manage(new Gtk::TreeView());
    _tree->show();
    
    _tree->signal_row_activated().connect(sigc::bind(sigc::mem_fun(this, &GRTTreeViewImpl::row_activated), self));

    _swin->add(*_tree);

    _tree->set_headers_visible(true);
  }

  
  void row_activated(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column, GRTTreeView *tree)
  {
    std::list<Gtk::TreeViewColumn*> columns= _tree->get_columns();
    int c= 0;

    for (std::list<Gtk::TreeViewColumn*>::const_iterator iter= columns.begin();
         iter != columns.end(); ++iter)
    {
      if (*iter == column)
        break;
      c++;
    }

    tree->row_activate_callback(_store->get_node_for_path(path), _columns[c].column);

    _store->row_changed(path, _store->get_iter(path));
  }
  
  
  void set_model(bec::TreeModel *model)
  {
    _store= TreeModelWrapper::create(model, _tree, "mforms");
    _tree->set_model(_store);

    _tree->remove_all_columns();
    for (size_t column= 0; column < _columns.size(); column++)
    {
      switch (_columns[column].type)
      {
      case StringGRTColumnType:
        _store->model().append_string_column(_columns[column].column, _columns[column].name, _columns[column].editable ? EDITABLE : RO);
        break;
      case IconStringGRTColumnType:
        _store->model().append_string_column(_columns[column].column, _columns[column].name, _columns[column].editable ? EDITABLE : RO, WITH_ICON);
        break;
      case IntegerGRTColumnType:
        break;
      case CheckGRTColumnType:
        break;
      case IconGRTColumnType:
        _store->model().append_string_column(_columns[column].column, _columns[column].name, _columns[column].editable ? EDITABLE : RO, WITH_ICON);
        break;
      }
      _tree->get_column(column)->set_resizable(true);
    }
  }

  void set_column_width(int model_column, int width)
  {
    for (size_t column= 0; column < _columns.size(); column++)
    {
      if (_columns[column].column == model_column)
      {
        Gtk::TreeViewColumn *c= _tree->get_column(column);
        
        c->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED);
        c->set_resizable(true);
        c->set_fixed_width(width);
        break;
      }
    }
  }

  int add_column(GRTTreeColumnType type, int model_column, const std::string &name, bool editable)
  {
    ColumnSpec c;
    c.type= type;
    c.column= model_column;
    c.name= name;
    c.editable= editable;
    _columns.push_back(c);
    
    return _columns.size()-1;
  }
  

  void refresh(const bec::NodeId &node)
  {
    _tree->unset_model();
    _tree->set_model(_store);
  }



  static bool create(GRTTreeView *self, bool bordered)
  {
    return new GRTTreeViewImpl(self) != 0;
  }
  
  static void set_model(GRTTreeView *self, bec::TreeModel *model)
  {
    GRTTreeViewImpl* tree = self->get_data<GRTTreeViewImpl>();
    
    tree->set_model(model);
  }

  static int add_column(GRTTreeView *self, GRTTreeColumnType type, int model_column, const std::string &name)
  {
    GRTTreeViewImpl* tree = self->get_data<GRTTreeViewImpl>();

    return tree->add_column(type, model_column, name, false);
  }

  static int add_column_editable(GRTTreeView *self, GRTTreeColumnType type, int model_column, const std::string &name)
  {
    GRTTreeViewImpl* tree = self->get_data<GRTTreeViewImpl>();

    return tree->add_column(type, model_column, name, true);
  }

  static void refresh(GRTTreeView *self, const bec::NodeId &node)
  {
    GRTTreeViewImpl* tree = self->get_data<GRTTreeViewImpl>();
    
    tree->refresh(node);
  }
  
  static void set_column_width(GRTTreeView *self, int model_column, int width)
  {
    GRTTreeViewImpl* tree = self->get_data<GRTTreeViewImpl>();
    
    tree->set_column_width(model_column, width);
  }
 

  static bool get_selected_node(GRTTreeView *self, bec::NodeId &node)
  {
    GRTTreeViewImpl* tree = self->get_data<GRTTreeViewImpl>();
    Gtk::TreeIter iter= tree->_tree->get_selection()->get_selected();
    if (iter)
    {
      node= tree->_store->get_node_for_path(tree->_store->get_path(iter));
      return true;
    }
    return false;
  }   


  static int get_selection(GRTTreeView *self, std::vector<bec::NodeId> &nodes)
  {
    GRTTreeViewImpl* tree = self->get_data<GRTTreeViewImpl>();
    std::list<Gtk::TreePath> selection= tree->_tree->get_selection()->get_selected_rows();
    nodes.clear();
    for (std::list<Gtk::TreePath>::const_iterator iter= selection.begin(); iter != selection.end(); ++iter)
    {
      nodes.push_back(tree->_store->get_node_for_path(*iter));
    }
    return nodes.size();
  }


  static void set_allow_multi_selection(GRTTreeView *self, bool flag)
  {
    GRTTreeViewImpl* tree = self->get_data<GRTTreeViewImpl>();
    tree->_tree->get_selection()->set_mode(flag ? Gtk::SELECTION_MULTIPLE : Gtk::SELECTION_SINGLE);
  }

public:
  static void init()
  {
    ::mforms::ControlFactory *f = ::mforms::ControlFactory::get_instance();

    f->_grttreeview_impl.create= &GRTTreeViewImpl::create;
    f->_grttreeview_impl.set_model= &GRTTreeViewImpl::set_model;
    f->_grttreeview_impl.add_column= &GRTTreeViewImpl::add_column;
    f->_grttreeview_impl.add_column_editable= &GRTTreeViewImpl::add_column_editable;
    f->_grttreeview_impl.refresh= &GRTTreeViewImpl::refresh;
    f->_grttreeview_impl.set_column_width= &GRTTreeViewImpl::set_column_width;
    f->_grttreeview_impl.set_allow_multi_selection= &GRTTreeViewImpl::set_allow_multi_selection;
    f->_grttreeview_impl.get_selected_node= &GRTTreeViewImpl::get_selected_node;
    f->_grttreeview_impl.get_selection= &GRTTreeViewImpl::get_selection;
  }
};

  
}
}

#endif
