#ifndef __DB_SQL_EDITOR_VIEW_H__
#define __DB_SQL_EDITOR_VIEW_H__

#include "mforms/toolbar.h"
#include "sqlide/wb_sql_editor_form.h"
#include "sqlide/sql_editor_fe.h"
#include "sqlide/recordset_view.h"
#include "linux_utilities/form_view_base.h"
#include "linux_utilities/notebooks.h"
#include "overview_panel.h"
//#include "gtk_helpers.h"
#include "active_label.h"
#include <glib.h>

class SqlSnippetsView;
class ToolbarManager;
class DbSqlEditorView;

//==============================================================================
//
//==============================================================================
class QueryOutputView
{
  public:
    QueryOutputView(const SqlEditorForm::Ref& be, DbSqlEditorView* db_sql_editor_view);

    Gtk::Widget& get_outer() {return _top_box;}
    void refresh();
    void output_text(const std::string& text, const bool bring_to_front);

  private:
    void mode_change_requested();
    int  on_history_entries_refresh();
    int  on_history_details_refresh();
    void on_history_entries_selection_changed();
    bool on_query_tooltip(int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip);


    void handle_action_output_context_menu(const std::string& action);
    void handle_history_context_menu(const std::string& action);
    void history_context_menu_responder();

    SqlEditorForm::Ref      _be;
    Gtk::VBox               _top_box;
    Gtk::Notebook           _note;
    Gtk::ComboBoxText       _mode;
    Gtk::Menu               _context_menu;

    // Text output part
    Gtk::ScrolledWindow     _text_swnd;
    Gtk::TextView           _text_output;

    // Action output
    GridView                _action_output;
    Gtk::ScrolledWindow     _action_swnd;

    // History output
    Gtk::HPaned             _history_box;
    Gtk::ScrolledWindow     _entries_swnd;
    GridView                _entries_grid;
    Gtk::ScrolledWindow     _details_swnd;
    GridView                _details_grid;

    sigc::connection        _on_history_entries_selection_changed_conn;
    DbSqlEditorView        *_db_sql_editor_view;
};


//==============================================================================
//
//==============================================================================
class QueryView : public sigc::trackable
{
  public:
    QueryView(const int editor_index, DbSqlEditorView* owner);
    ~QueryView();
    Gtk::Widget* get_outer() {return &_top_pane;}

    void update_label(const std::string& label);
    void update_recordset_caption();
    void update_resultsets();
    void close();
    void focus();

    void set_sql(const std::string& sql) {_editor.set_text(sql);}
    std::string get_sql() {return _editor.get_text();}

    void set_linked_label(ActiveLabel* lbl); // Label associated with the view in gtk::notebook
    void update_exec_sql_progress(float progress, const std::string &message);
    void execute_sql(bool current_statement_only);
    int index();

    Sql_editor::Ref     sql_editor_be() {return _editor.be();}

    SqlEditorFE *get_editor_fe() { return &_editor; }

    void save();
    std::string editor_path();

    void reenable_items_in_tab_menus();
    void stop_busy();

  private:
    void tab_reordered(Gtk::Widget*, guint)
    {
      recalc_rstab_indices();
    }
    void recalc_rstab_indices();
    void polish();
    void top_pane_changed();

    void on_sql_editor_selection_change();

    RecordsetView* active_recordset();
    void close_recordset(long long key, bool confirm);
    void close_recordset_by_ptr(RecordsetView *view, const bool confirm);

    void rs_page_switched(GtkNotebookPage *page, guint index);
    void apply_recordset_changes();
    void discard_recordset_changes();
    int process_task_msg(int msgType, const std::string &message, const std::string &detail, RecordsetView *rsv);

    void init_tab_menu(mforms::Menu* menu);
    void tab_menu_handler(const std::string& action, ActiveLabel* sender, RecordsetView* qv);

    DbSqlEditorView         *_owner;
    Gtk::VBox                _editor_box;
    Gtk::VBox                _rs_box;
    Gtk::VPaned              _top_pane;
    SqlEditorFE              _editor;
    ActiveLabel             *_label; // label from the tabswitcher/notebook
    ActionAreaNotebook       _rs_tabs;
    mforms::ToolBar::Ptr    _query_toolbar;
    Gtk::HBox               _btn_box;
    Gtk::Button             _apply_btn;
    Gtk::Button             _cancel_btn;
    Gtk::Label              _editability_label;
    Gtk::Image              _editability_icon;

    sigc::connection        _polish_conn;
    bool                    _query_collapsed;
    bool                    _updating_results;
};


//==============================================================================
//
//==============================================================================
class DbSqlEditorView : public Gtk::VBox, public FormViewBase
{
  public:
    DbSqlEditorView(SqlEditorForm::Ref editor_be);
    static DbSqlEditorView *create(SqlEditorForm::Ref editor_be);
    virtual ~DbSqlEditorView();

    virtual void init();
    virtual bool on_close();
    virtual void dispose();

    virtual bec::BaseEditor* get_be() { return NULL; }
    virtual std::string get_title() { return _be->caption(); }
    virtual bec::UIForm *get_form() const { return _be.get(); }
    virtual Gtk::Widget *get_panel() { return this; }
    //virtual void toggle_sidebar();
    virtual bool show_find(bool replace);

    virtual bool perform_command(const std::string &command);

    SqlEditorForm::Ref be()
    {
      return _be;
    }

    void close_editor_tab(QueryView* qv);
    void output_text(const std::string &text, bool bring_to_front);

    virtual bool close_focused_tab();

    QueryView *active_view();
    std::vector<QueryView*> query_views();

    bec::GRTManager* grt_manager() {return _grtm;}

  protected:
    virtual void plugin_tab_added(PluginEditorBase *plugin);

  private:
    void polish();

    bool validate_explain_sql();
    void explain_sql();

    int  on_exec_sql_progress(float progress, const std::string &message);
    void recordset_list_changed(int editor_index, Recordset::Ref rset, bool added);
    int  on_sql_editor_text_insert(const std::string &text);
    int on_exec_sql_done();

    void update_resultsets(int editor_index, Recordset::Ref rset, bool added);
    void update_resultsets_from_main();
    std::deque<sigc::slot<void> >  _update_resultset_slots; // Slot will have editor index, resultset attached
    GMutex                        *_update_resultset_slots_lock;

    int  add_editor_tab(int active_sql_editor_index);
    void editor_page_switched(GtkNotebookPage *page, guint index);
    void editor_page_reordered(Gtk::Widget *page, guint index) {recalc_tab_indices();}

    void partial_refresh_ui(const int what);

    QueryView *find_view_by_index(const int index);
    void recalc_tab_indices();

    void init_tab_menu(mforms::Menu* menu);
    void tab_menu_handler(const std::string& action, ActiveLabel* sender, QueryView* qv);
    void reenable_items_in_tab_menus();

    SqlEditorForm::Ref    _be;
    Gtk::HPaned           _top_pane;
    Gtk::HPaned           _top_right_pane;
    Gtk::VPaned           _main_pane;
    QueryOutputView       _output;
    Gtk::Widget          *_side_palette;

    sigc::connection      _polish_conn;


    Glib::Dispatcher      _dispatch_rset_update;
    sigc::connection      _dispatch_rset_update_conn;
    bec::GRTManager      *_grtm;
    const bool            _right_aligned;
};


#endif // __DB_SQL_EDITOR_VIEW_H__
