//!
//! \addtogroup linuxui Linux UI
//! @{
//! 

#ifndef _PLUGIN_EDITOR_BASE_H_
#define _PLUGIN_EDITOR_BASE_H_

#include "gtk_helpers.h"
#include "grt/grt_manager.h"
#include "grtui/gui_plugin_base.h"
#include <gtkmm/frame.h>
#include <gtkmm/notebook.h>
#include <gtkmm/progressbar.h>
#include <gtkmm/textview.h>
#include <gtkmm/entry.h>
#include <gtkmm/paned.h>
#include <gtkmm/builder.h>
#include "base/string_utilities.h"

using base::strfmt;

namespace Gtk
{
class TextView;
}

class SqlEditorFE;

class PluginEditorBase : public Gtk::Frame, public GUIPluginBase
{
public:
  PluginEditorBase(grt::Module *module, bec::GRTManager *grtm, const grt::BaseListRef &args, const char* glade_xml = 0);
  virtual ~PluginEditorBase();

  Gtk::Notebook * editor_notebook() { return _editor_notebook; }

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

  void load_glade(const char* glade_xml_filename);

  bool is_editing_live_object();
  bool should_close_on_delete_of(const std::string &oid);
  void refresh_form_data();
  void commit_text_changes();
  void close_live_object_editor();

  virtual void show() { Gtk::Frame::show(); }
  virtual void hide() { Gtk::Frame::hide(); }
  virtual std::string get_title()= 0;

  virtual bool can_close() { return true; }

  sigc::signal<void, std::string> signal_title_changed() { return _signal_title_changed; }

  virtual sigc::connection add_entry_change_timer(Gtk::Entry *entry, const sigc::slot<void,std::string> &setter);
  virtual sigc::connection add_text_change_timer(Gtk::TextView *text, const sigc::slot<void,std::string> &setter);
  virtual sigc::connection add_sqleditor_text_change_timer(SqlEditorFE *text, const sigc::slot<void,std::string> &setter);

  // Warning! before using these functions make sure that _xml field was created in ctor by passign xml file name
  //service functions
  template <typename Be, typename Setter>
  inline sigc::connection bind_entry_and_be_setter(const char* glade_entry_name, Be *be, const Setter& setter)
  {
    Gtk::Entry* entry(0);
    _xml->get_widget(glade_entry_name, entry);
    return entry ? add_entry_change_timer(entry, sigc::mem_fun(be, setter)) : sigc::connection();
  }

  template <typename Be, typename Setter>
  inline sigc::connection bind_text_and_be_setter(const char* glade_text_name, Be *be, const Setter& setter)
  {
    Gtk::TextView* entry(0);
    _xml->get_widget(glade_text_name, entry);
    return entry ? add_text_change_timer(entry, sigc::mem_fun(be, setter)) : sigc::connection();
  }

protected:
  struct TextChangeTimer
  {
    sigc::connection conn;
    sigc::slot<bool> commit;
    sigc::slot<void,std::string> setter;
  };

  std::map<Gtk::Widget*,TextChangeTimer> _timers;
  sigc::signal<void, std::string> _signal_title_changed;

  bool _refreshing;

  virtual void add_option_combo_change_handler(Gtk::ComboBox *combo, const std::string &option, const sigc::slot<void,std::string,std::string> &setter);

  virtual void do_refresh_form_data() {}

  virtual bec::BaseEditor *get_be()= 0;

  Glib::RefPtr<Gtk::Builder> xml() const {return _xml;}
  Gtk::Box*  decorator_control() {return _live_object_editor_decorator_control;}

  Gtk::Notebook                     *_editor_notebook;
  virtual void decorate_object_editor();
private:
  bec::GRTManager                   *_grtm;
  Glib::RefPtr<Gtk::Builder>         _xml;

  Glib::RefPtr<Gtk::Builder>         _live_object_editor_decorator_xml;
  Gtk::Box                          *_live_object_editor_decorator_control;
  Gtk::Container                    *_live_editor_placeholder;
  void apply_changes_to_live_object();
  void revert_changes_to_live_object();

  virtual void execute() {} // doesn't do anything, just need to implement this from GUIPluginBase

  bool entry_timeout(Gtk::Entry *entry);
  bool text_timeout(Gtk::TextView *text);
  bool sqleditor_text_timeout(SqlEditorFE *text);

  void entry_changed(Gtk::Entry *entry);
  void text_changed(Gtk::TextView *text);
  void sqleditor_text_changed(SqlEditorFE *text);

  // TODO: Remove this code 
  void combo_changed(Gtk::ComboBox *combo, const std::string &option, const sigc::slot<void,std::string,std::string> &setter);
};

#endif /* _PLUGIN_EDITOR_BASE_H_ */

//!
//! @}
//!
