#include "catalog_tree.h"
#include "treemodel_wrapper.h"
#include "gtk_helpers.h"
#include "base/string_utilities.h"

#include "grtdb/db_object_helpers.h"
#include "model/wb_component_physical.h"


CatalogTree::CatalogTree(wb::WBContextUI *wbui)
  : _wbui(wbui)
{
  set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  _tree.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
  add(_tree);
  set_shadow_type(Gtk::SHADOW_IN);
  _tree.set_headers_visible(false);

  fix_broken_gtk_selection_handling(&_tree);

  std::vector<Gtk::TargetEntry> drag_types;
  drag_types.push_back(Gtk::TargetEntry(WB_DBOBJECT_DRAG_TYPE, Gtk::TARGET_SAME_APP));
  
  _tree.enable_model_drag_source(drag_types, Gdk::MODIFIER_MASK, Gdk::ACTION_COPY);
  //_tree.enable_drag_source_set(drag_types);
  _tree.signal_drag_begin().connect(sigc::mem_fun(this, &CatalogTree::drag_begin));
  _tree.signal_drag_data_get().connect(sigc::mem_fun(this, &CatalogTree::drag_data_get));
  
  show_all();
}


void CatalogTree::refresh()
{
  Gtk::TreePath first_row, last_row;
  std::list<Gtk::TreePath> selected;

  freeze_notify();
  _tree.freeze_notify();

  if (!_model)
  {
    _model= TreeModelWrapper::create(_wbui->get_catalog_tree(), &_tree, "CatalogTree", bec::NodeId(0));
    _model->model().append_string_column(bec::ValueTreeBE::Name, _("Name"), RO, WITH_ICON);
    _model->model().append_string_column(1, "", RO, NO_ICON);
    _tree.set_model(_model);
    _model->set_expanded_rows_storage(&_expanded_rows);
    _model->set_fe_menu_handler(sigc::mem_fun(this, &CatalogTree::handle_menu));
    
    scoped_connect(_wbui->get_catalog_tree()->tree_changed_signal(),sigc::mem_fun(this, &CatalogTree::tree_changed));
  }
  else
  {
    _tree.get_visible_range(first_row, last_row);
    selected = _tree.get_selection()->get_selected_rows();

    bec::ListModel* m = _model->get_be_model();
    _model->set_be_model(0);
    _tree.unset_model();
    _tree.set_model(_model);

    _model->set_be_model(m);
    _tree.unset_model();
    _model->refresh();
    //_wbui->get_catalog_tree()->refresh();
    _tree.set_model(_model);
  }
  
  reexpand_nodes();

  if (!first_row.empty())
    _tree.scroll_to_row(first_row);

  for (std::list<Gtk::TreePath>::const_iterator path = selected.begin(); path != selected.end(); ++path)
    _tree.get_selection()->select(*path);

  _tree.thaw_notify();
  thaw_notify();
}


void CatalogTree::tree_changed(const bec::NodeId &node, int old_count)
{
  refresh();
}


void CatalogTree::reexpand_nodes()
{
  expand_tree_nodes_as_in_be(_model, &_tree);
}



void CatalogTree::drag_begin(const Glib::RefPtr<Gdk::DragContext> &context)
{
  
}


void CatalogTree::drag_data_get(const Glib::RefPtr<Gdk::DragContext> &context,
                                Gtk::SelectionData &selection, guint , guint)
{ 
  std::string data;
  std::list<db_DatabaseObjectRef> objects;
  
  
  std::list<Gtk::TreePath> rows(_tree.get_selection()->get_selected_rows());

  if (rows.size() > 0)
  {
    for (std::list<Gtk::TreePath>::const_iterator iter= rows.begin(); iter != rows.end(); ++iter)
    {
      bec::NodeId node(_model->node_for_iter(_model->get_iter(*iter)));

      grt::ValueRef value(_wbui->get_catalog_tree()->get_node_value(node));

      if (value.is_valid() && db_DatabaseObjectRef::can_wrap(value))
        objects.push_back(db_DatabaseObjectRef::cast_from(value));
    }
  
    if (!objects.empty())
    {
      std::string data= bec::CatalogHelper::dbobject_list_to_dragdata(objects);
      selection.set(selection.get_target(), data);
    }
  }
}


void CatalogTree::handle_menu(const std::string& name, const std::vector<bec::NodeId>& nodes)
{
  if (name == "refreshCatalog")
    refresh();
  else if (name == "renameItem")
  {
    Gtk::TreeModel::Path  path;
    Gtk::TreeViewColumn  *col(0);
    
    _tree.get_cursor(path, col);
  
    if (!path.empty() && col)
      _tree.set_cursor(path, *col, true);
  }
}

