/* 
 * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#ifndef _ADVANCED_SIDEBAR_H_
#define _ADVANCED_SIDEBAR_H_

#include "mforms/task_sidebar.h"
#include "mforms/drawbox.h"
#include "mforms/treenodeview.h"
#include "mforms/menu.h"
#include "mforms/textentry.h"
#include "mforms/button.h"
#include "mforms/label.h"

#include "sqlide/wb_live_schema_tree.h"

/**
 * Implementation of a sidebar in iTunes look and feel that can optionally show the content of a 
 * database.
 */

namespace wb {

  class AdvancedSidebar;

  /**
    * The SidebarEntry class is a lean wrapper for an icon/label combination which can be used
    * to trigger an action. It needs a container to be useful (here the class SidebarEntry).
    */
  class SidebarEntry
  {
  private:
    std::string _title;
    cairo_surface_t* _icon;
    std::string _command;
    mforms::TaskEntryType _type;
  public:
    SidebarEntry(const std::string& title, const std::string& icon, const std::string& command, mforms::TaskEntryType type);
    ~SidebarEntry();
    
    void set_title(const std::string &title, const std::string &icon);

    void paint(cairo_t* cr, base::Rect bounds, bool hot, bool active, const base::Color& selection_color);
    bool contains(double x, double y);

    std::string title() { return _title; };
    std::string command() { return _command; };
    mforms::TaskEntryType type() { return _type; };

  };

  class SidebarSection : public mforms::DrawBox
  {
  private:
    std::string _title;
    std::vector<SidebarEntry*> _entries;
    int _layout_width;
    int _layout_height;
    bool _expand_text_visible;
    int _expand_text_width;
    bool _expanded;
    bool _expand_text_active;
    bool _expandable;
    bool _refresh_hot;
    bool _refresh_down;
    bool _show_busy;
    cairo_surface_t* _refresh_icon; // TODO: make this managed by the icon manager.
    cairo_surface_t* _busy_icon;    // ditto

    SidebarEntry* _selected_entry;
    SidebarEntry* _hot_entry;
    boost::signals2::signal<void (SidebarSection*)> _expanded_changed;

    AdvancedSidebar* _owner;
  protected:
    void set_selected(SidebarEntry* entry);
    void layout(cairo_t* cr);
    SidebarEntry* entry_from_point(double x, double y);
    int find_entry(const std::string& title);

  public:
    SidebarSection(AdvancedSidebar* owner, const std::string& title, bool expandable, bool refreshable);
    ~SidebarSection();

    int add_entry(const std::string& title, const std::string& icon, const std::string& command,
                  mforms::TaskEntryType type);
    void set_entry_text(int index, const std::string& title, const std::string& icon);
    void mark_busy(bool busy);
    void remove_entry(const std::string& entry);
    int entry_count() { return (int)_entries.size(); }

    void clear();
    bool select(int index);
    bool select(const std::string& title);
    //void set_selection_color(const base::Color color) {};

    SidebarEntry* selected() { return _selected_entry; };
    bool expanded() { return _expanded; };
    void toggle_expand();

    std::string title() { return _title; };

    virtual void repaint(cairo_t* cr, int areax, int areay, int areaw, int areah);
    virtual void mouse_leave();
    virtual void mouse_move(int x, int y);
    virtual void mouse_down(int button, int x, int y);
    virtual void mouse_click(int button, int x, int y);
    virtual void mouse_up(int button, int x, int y);
    virtual void get_layout_size(int* w, int* h);

    void clear_selection();

    boost::signals2::signal<void (SidebarSection*)>* expanded_changed() { return &_expanded_changed; }

  };

  class AdvancedSidebar : public mforms::TaskSidebar
  {
  private:
    //db_mgmt_ConnectionRef _connection;
    typedef boost::signals2::signal<void (const std::string&)> SearchBoxChangedSignal;
    typedef boost::signals2::signal<void (void)> TreeNodeSelected;
    std::vector<SidebarSection*> _sections;
    SidebarSection* _schema_tree_heading;
    mforms::TreeNodeView _new_schema_tree;
    mforms::TreeNodeView _filtered_schema_tree;
    mforms::Menu _tree_context_menu;
    mforms::Box _schema_search_box;
    mforms::TextEntry _schema_search_text;
    bool _remote_search_enabled;
    mforms::Label _schema_search_warning;
    mforms::Button _remote_search;
    wb::LiveSchemaTree* _schema_model;
    wb::LiveSchemaTree* _base_model;
    wb::LiveSchemaTree* _filtered_schema_model;
    boost::signals2::scoped_connection _activate_conn;
    SearchBoxChangedSignal _search_box_changed_signal;
    TreeNodeSelected _tree_node_selected;
    bool _is_model_owner;                   // True if the sidebar is the owner of the model.

    mforms::Box _schema_box; // Container for schema section and tree so we can hide it as a block.

    AdvancedSidebar(); // Create the sidebar via its mforms alter ego TaskSidebar::create()
    base::Color _selection_color;
  protected:
    static mforms::TaskSidebar* create_instance();

    int find_section(const std::string& title);
    void setup_schema_tree();
    void on_show_menu();
    void on_expand_changed(SidebarSection* section);
    void handle_menu_command(const std::string& command);
    void on_search_text_changed();
    void on_remote_search_clicked();
    void on_tree_node_selected();
  public:
    ~AdvancedSidebar();

    virtual mforms::TreeNodeView *get_schema_tree() { return (_schema_model == _base_model) ? &_new_schema_tree : &_filtered_schema_tree; }
    virtual mforms::TextEntry *get_filter_entry() { return &_schema_search_text; }
    void refresh_clicked(SidebarSection* section);
    virtual void refresh_model();
    virtual void set_schema_model(wb::LiveSchemaTree* model);
    virtual void set_filtered_schema_model(wb::LiveSchemaTree* model);
    virtual void enable_server_search(bool enabled) { _remote_search_enabled = enabled; }

    virtual int add_section(const std::string& title, bool collapsible = true);
    virtual void remove_section(const std::string& title);
    virtual int add_section_entry(const std::string& section, const std::string& title, const std::string& icon, const std::string& command, mforms::TaskEntryType type);
    virtual void set_section_entry_text(const std::string& section, int index, const std::string& title, const std::string& icon);
    virtual void mark_section_busy(const std::string& section, bool busy);

    virtual void remove_section_entry(const std::string& section, const std::string& entry);
    virtual void set_collapse_states(const std::string& data);
    virtual std::string get_collapse_states();

    virtual void clear_sections();
    virtual void clear_section(const std::string& section);
    virtual void set_selection_color(const std::string& color);
    virtual void set_selection_color (const mforms::SystemColor color);
    virtual boost::signals2::signal<void (const std::string&)>* signal_filter_changed() { return &_search_box_changed_signal; }
    virtual boost::signals2::signal<void (void)>* tree_node_selected() { return &_tree_node_selected; };
    const base::Color& selection_color() const
    {
      return _selection_color;
    }

    virtual void expand_schema(int schema_index);

    virtual int select_entry(const std::string& section, const std::string& title);
    virtual void clear_selection();

  private:
    static bool __init;
    static bool init_factory_method();
  };

} // namespace wb

#endif // _ADVANCED_SIDEBAR_H_
