#include "wb_config.h"
#include "linux_utilities/plugin_editor_base.h"
#include "../backend/mysql_routinegroup_editor.h"
#include "grtdb/db_object_helpers.h"
#include "treemodel_wrapper.h"
#include "sql_editor_fe.h"
#include "errors_list.h"
#include <sstream>
#include "text_list_columns_model.h"

//==============================================================================
//
//==============================================================================
class DbMySQLRoutineGroupEditor : public PluginEditorBase
{
  MySQLRoutineGroupEditorBE                *_be;
  SqlEditorFE                               _code;
  Glib::RefPtr<Gtk::ListStore>              _routines_model;
  Gtk::TreeView                            *_rg_list;
  TextListColumnsModel                     *_routines_columns;
  Gtk::Menu				    _context_menu;
  
  virtual bec::BaseEditor *get_be();
  
  void parse_sql(const std::string& sql);
  void error_selected(const int lineno, const std::string& msg);

  bool process_event(GdkEvent* event);
  void menu_action_on_node(const std::string &item_name, const Gtk::TreePath path);

  void set_group_name(const std::string &);
  
  void set_comment(const std::string& comm)
  {
    _be->set_comment(comm);
  }
  
 public:
  DbMySQLRoutineGroupEditor(grt::Module *m, bec::GRTManager *grtm, const grt::BaseListRef &args);
  
  virtual ~DbMySQLRoutineGroupEditor();
  virtual void do_refresh_form_data();
  virtual std::string get_title();

  void on_routine_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y,
                       const Gtk::SelectionData& selection_data, guint info, guint time);


  bool switch_edited_object(bec::GRTManager *grtm, const grt::BaseListRef &args);
};

//------------------------------------------------------------------------------
DbMySQLRoutineGroupEditor::DbMySQLRoutineGroupEditor(grt::Module *m, bec::GRTManager *grtm, const grt::BaseListRef &args)
    : PluginEditorBase(m, grtm, args, "modules/data/editor_rg.glade")
    , _be(new MySQLRoutineGroupEditorBE(grtm, db_mysql_RoutineGroupRef::cast_from(args[0]), get_rdbms_for_db_object(args[0])))
    , _routines_model(model_from_string_list(std::vector<std::string>(), &_routines_columns))
{
  xml()->get_widget("mysql_rg_editor_notebook", _editor_notebook);

  Gtk::Image *image;
  xml()->get_widget("rg_image", image);
  image->set(ImageCache::get_instance()->image_from_filename("db.RoutineGroup.editor.48x48.png", false));
  
  _be->set_refresh_ui_slot(sigc::mem_fun(this, &DbMySQLRoutineGroupEditor::refresh_form_data));
  
  _editor_notebook->reparent(*this);
  _editor_notebook->show();

  bind_entry_and_be_setter("rg_name", this, &DbMySQLRoutineGroupEditor::set_group_name);
  
  Gtk::TextView* tv;
  xml()->get_widget("rg_comment", tv);
  add_text_change_timer(tv, sigc::mem_fun(this, &DbMySQLRoutineGroupEditor::set_comment));
  
  _code.be(_be->get_sql_editor());

  Gtk::VBox* code_win;
  xml()->get_widget("rg_code_holder", code_win);
  _code.container().set_size_request(-1, 100);
  add_sqleditor_text_change_timer(&_code, sigc::mem_fun(this, &DbMySQLRoutineGroupEditor::parse_sql));
  code_win->add(_code.container());
  code_win->resize_children();
  
  refresh_form_data();
  
  xml()->get_widget("rg_list", _rg_list);
  
  _rg_list->set_model(_routines_model);
  _rg_list->append_column("Routine", _routines_columns->item);
  _rg_list->set_headers_visible(false);

  // Setup DnD
  std::vector<Gtk::TargetEntry> targets;  
  targets.push_back(Gtk::TargetEntry("x-mysql-wb/db.DatabaseObject", Gtk::TARGET_SAME_APP));
  _rg_list->drag_dest_set(targets, Gtk::DEST_DEFAULT_ALL,Gdk::ACTION_COPY);
  _rg_list->signal_drag_data_received().connect(sigc::mem_fun(this, &DbMySQLRoutineGroupEditor::on_routine_drop));
  _rg_list->signal_event().connect(sigc::mem_fun(*this, &DbMySQLRoutineGroupEditor::process_event));

  _code.set_text(_be->get_routines_sql());

  show_all();
}

//------------------------------------------------------------------------------
DbMySQLRoutineGroupEditor::~DbMySQLRoutineGroupEditor()
{
  delete _be;
}

//------------------------------------------------------------------------------
bool DbMySQLRoutineGroupEditor::switch_edited_object(bec::GRTManager *grtm, const grt::BaseListRef &args)
{
  MySQLRoutineGroupEditorBE *old_be = _be;
  
  _be = new MySQLRoutineGroupEditorBE(grtm, db_mysql_RoutineGroupRef::cast_from(args[0]), get_rdbms_for_db_object(args[0]));
  _be->set_refresh_ui_slot(sigc::mem_fun(this, &DbMySQLRoutineGroupEditor::refresh_form_data));

  _code.be(_be->get_sql_editor());
  
  refresh_form_data();
  
  delete old_be;

  return true;
}

//------------------------------------------------------------------------------
std::string DbMySQLRoutineGroupEditor::get_title()
{
  return strfmt(_("Group: %s"), _be->get_name().c_str());
}

//------------------------------------------------------------------------------
void DbMySQLRoutineGroupEditor::set_group_name(const std::string &name)
{
  _be->set_name(name);
  _signal_title_changed.emit(get_title());
}

//------------------------------------------------------------------------------
bec::BaseEditor *DbMySQLRoutineGroupEditor::get_be()
{
  return _be;
}

//------------------------------------------------------------------------------
void DbMySQLRoutineGroupEditor::do_refresh_form_data()
{
  Gtk::Entry* entry(0);
  xml()->get_widget("rg_name", entry);
  if (entry->get_text() != _be->get_name())
  {
    entry->set_text(_be->get_name());
    _signal_title_changed.emit(get_title());
  }
  Gtk::TextView* tv;
  xml()->get_widget("rg_comment", tv);
  tv->get_buffer()->set_text(_be->get_comment());

  _code.check_sql();

  if (_be->get_sql_editor()->is_refresh_enabled())
  {
    _be->get_sql_editor()->is_refresh_enabled(false);
    _code.set_text(_be->get_routines_sql());
  }
  
  recreate_model_from_string_list(_routines_model, _be->get_routines_names());
}

//------------------------------------------------------------------------------
void DbMySQLRoutineGroupEditor::parse_sql(const std::string& sql)
{
  _code.reset_sql_check_state();
  _be->set_routines_sql(sql, false);
  recreate_model_from_string_list(_routines_model, _be->get_routines_names());
}

//------------------------------------------------------------------------------
void DbMySQLRoutineGroupEditor::error_selected(const int lineno, const std::string& msg)
{}

//------------------------------------------------------------------------------
bool DbMySQLRoutineGroupEditor::process_event(GdkEvent* event)
{
  if ( event->type == GDK_BUTTON_PRESS && event->button.button == 3 )
  {
    Gtk::TreeModel::Path   path;
    Gtk::TreeView::Column *column(0);
    int                    cell_x(-1);
    int                    cell_y(-1);
    
    if ( _rg_list->get_path_at_pos((int)event->button.x, (int)event->button.y, path, column, cell_x, cell_y) )
    {
      bec::MenuItemList  menuitems;
      bec::MenuItem      item;
      item.caption = "Remove routine from the group";
      item.name    = "remove_routine_from_the_group";
      menuitems.push_back(item); 
      
      run_popup_menu(menuitems
                ,event->button.time
                ,sigc::bind(sigc::mem_fun(this, &DbMySQLRoutineGroupEditor::menu_action_on_node), path)
                ,&_context_menu);
    }
  }
  return false;
}

//------------------------------------------------------------------------------
void DbMySQLRoutineGroupEditor::menu_action_on_node(const std::string &item_name, const Gtk::TreePath path)
{  
  if ( item_name == "remove_routine_from_the_group" )
  {
    const std::string name = (*(_routines_model->get_iter(path)))[_routines_columns->item];
    _be->delete_routine_with_name(name);
    do_refresh_form_data();
    _code.set_text(_be->get_routines_sql());
  }
}

//------------------------------------------------------------------------------
void DbMySQLRoutineGroupEditor::on_routine_drop(const Glib::RefPtr<Gdk::DragContext>& context
                                               ,int x, int y
                                               , const Gtk::SelectionData& selection_data
                                               , guint info, guint time)
{
  bool dnd_status = false;
  
  if ( selection_data.get_target() == "x-mysql-wb/db.DatabaseObject" )
  {
    std::list<db_DatabaseObjectRef> objects;

    const std::string selection = selection_data.get_data_as_string();

    objects= bec::CatalogHelper::dragdata_to_dbobject_list(_be->get_catalog(), selection);
    
    for (std::list<db_DatabaseObjectRef>::const_iterator obj= objects.begin(); 
         obj != objects.end(); ++obj)
    {
      if (obj->is_instance<db_mysql_Routine>())
      {
        db_mysql_RoutineRef routine = db_mysql_RoutineRef::cast_from(*obj);
        if ( routine.is_valid() )
        {
          _be->append_routine_with_id(routine.id());
          std::string routine_name = _be->get_routine_name(routine.id());
        }
      }
    }

    recreate_model_from_string_list(_routines_model, _be->get_routines_names());
    _code.set_text(_be->get_routines_sql());

    dnd_status = true;
  }
  context->drag_finish(dnd_status, false, time);
}

//------------------------------------------------------------------------------
extern "C" 
{
  GUIPluginBase *createDbMysqlRoutineGroupEditor(grt::Module *m, bec::GRTManager *grtm, const grt::BaseListRef &args)
  {
    return Gtk::manage(new DbMySQLRoutineGroupEditor(m, grtm, args));
  }
};
