/* 
 * Copyright (c) 2009, 2013, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "linux_utilities/image_cache.h"
#include "grtdb/db_object_helpers.h"
#include "treemodel_wrapper.h"
#include "mysql_table_editor_column_page.h"
#include "mysql_table_editor_index_page.h"
#include "mysql_table_editor_fk_page.h"
#include "mysql_table_editor_trigger_page.h"
#include "mysql_table_editor_part_page.h"
#include "mysql_table_editor_opt_page.h"
//!#include "mysql_table_editor_insert_page.h"
#include "sqlide/recordset_view.h"//!
#include "mysql_editor_priv_page.h"

#include "mysql_table_editor_fe.h"

//------------------------------------------------------------------------------
DbMySQLTableEditor::DbMySQLTableEditor(grt::Module *m, bec::GRTManager *grtm, const grt::BaseListRef &args)
//    : PluginEditorBase(m, grtm, args, "modules/data/editor_mysql_table.glade")
    : PluginEditorBase(m, grtm, args, 0)
    , _be(new MySQLTableEditorBE(grtm, db_mysql_TableRef::cast_from(args[0]), get_rdbms_for_db_object(args[0])))
    , _part_page(0)
    , _inserts_page(0)
{
  load_glade((_be->is_editing_live_object()) ? "modules/data/editor_mysql_table_live.glade" : "modules/data/editor_mysql_table.glade");

  xml()->get_widget("mysql_editor_notebook", _editor_notebook);
  _editor_notebook->signal_switch_page().connect(sigc::mem_fun(this, &DbMySQLTableEditor::page_changed));

  Gtk::Image *image(0);
  xml()->get_widget("table_editor_image", image);
  image->set(ImageCache::get_instance()->image_from_filename("db.Table.editor.48x48.png", false));
  image->set_data("is_large", (void*)1);

  xml()->get_widget("table_page_box", _main_page_widget);

  set_border_width(0);

  _columns_page   = new DbMySQLTableEditorColumnPage(this, _be, xml());
  _indexes_page   = new DbMySQLTableEditorIndexPage(this, _be, xml());
  _fks_page       = new DbMySQLTableEditorFKPage(this, _be, xml());
  _triggers_page  = new DbMySQLTableEditorTriggerPage(this, _be, xml());
  _part_page      = new DbMySQLTableEditorPartPage(this, _be, xml());
  _opts_page      = new DbMySQLTableEditorOptPage(this, _be, xml());

  if (!is_editing_live_object())
  {
    Gtk::ScrolledWindow *placeholder= 0;
    xml()->get_widget("inserts_recordset_view_placeholder", placeholder);
    _inserts_page= RecordsetView::create(_be->get_inserts_model(), placeholder);

    _privs_page     = new DbMySQLEditorPrivPage(_be);
    _editor_notebook->append_page(_privs_page->page(), "Privileges");
  }
  else
  {
    Gtk::ScrolledWindow *placeholder= 0;
    xml()->get_widget("inserts_recordset_view_placeholder", placeholder);
    _editor_notebook->remove_page(*placeholder);
    //_inserts_page= NULL;
    _privs_page= NULL;

    Gtk::ComboBox *cbox = 0;
    xml()->get_widget("schema_combo", cbox);
    if (cbox)
    {
      setup_combo_for_string_list(cbox);
      //fill_combo_from_string_list(cbox, _be->get_all_schema_names());
    }
  }
  
  create_table_page();

  add(*_editor_notebook);
  _editor_notebook->show();

  show_all();

  Gtk::Entry *entry(0);
  xml()->get_widget("table_name", entry);
  entry->signal_event().connect(sigc::mem_fun(this, &DbMySQLTableEditor::event_from_table_name_entry));

  refresh_form_data();

  focus_widget_when_idle(entry);

  _be->set_refresh_ui_slot(sigc::mem_fun(this, &DbMySQLTableEditor::refresh_form_data));
  _be->set_partial_refresh_ui_slot(sigc::mem_fun(this, &DbMySQLTableEditor::partial_refresh));

  _be->reset_editor_undo_stack();
  //Gtk::Paned* table_page_paned = 0;
  //xml()->get_widget("table_page_paned", table_page_paned);
  //gtk_paned_set_pos_ratio(table_page_paned, 0.2);
}

//------------------------------------------------------------------------------
DbMySQLTableEditor::~DbMySQLTableEditor()
{
  delete _columns_page;
  delete _indexes_page;
  delete _fks_page;
  delete _triggers_page;
  delete _part_page;
  delete _opts_page;
  //delete _inserts_page;
  delete _privs_page;
  delete _be;
}

//------------------------------------------------------------------------------
void DbMySQLTableEditor::decorate_object_editor()
{
  if (is_editing_live_object())
  {
    PluginEditorBase::decorate_object_editor();
    Gtk::HBox* header_part = 0;
    xml()->get_widget("header_part", header_part);

    if (header_part->get_parent() == NULL)
    {
      decorator_control()->pack_start(*header_part, false, true);
      decorator_control()->reorder_child(*header_part, 0);

      Gtk::Button *hide_button = 0;
      xml()->get_widget("hide_button", hide_button);
      Gtk::Image* hide_image = Gtk::manage(new Gtk::Image(ImageCache::get_instance()->image_from_filename("EditorExpanded.png", false)));
      Gtk::Image* show_image = Gtk::manage(new Gtk::Image(ImageCache::get_instance()->image_from_filename("EditorCollapsed.png", false)));
      hide_image->show();
      Gtk::VBox* box = Gtk::manage(new Gtk::VBox());
      box->pack_start(*hide_image, false, false);
      box->pack_start(*show_image, false, false);
      box->show();
      show_image->hide();
      hide_button->set_image(*box);
      hide_button->signal_clicked().connect(sigc::mem_fun(this, &DbMySQLTableEditor::toggle_header_part));
      toggle_header_part();
    }
  }
}

//------------------------------------------------------------------------------
void DbMySQLTableEditor::toggle_header_part()
{
  Gtk::Button *hide_button = 0;
  xml()->get_widget("hide_button", hide_button);

  Gtk::Image *image = 0;
  xml()->get_widget("table_editor_image", image);
  const bool make_image_small = image->get_data("is_large");
  image->set(ImageCache::get_instance()->image_from_filename(make_image_small ? "db.Table.editor.24x24.png" : "db.Table.editor.48x48.png", false));
  image->set_data("is_large", (void*)(!make_image_small));

  Gtk::VBox* image_box = dynamic_cast<Gtk::VBox*>(hide_button->get_image());
  if (image_box)
  {
    const std::vector<Gtk::Widget*> images = image_box->get_children();
    for (int i = ((int)images.size()) - 1; i >= 0; --i)
    {
      if (images[i]->is_visible())
        images[i]->hide();
      else
        images[i]->show();
    }

    const char* const names[] = {"collation_label", "collation_combo", "engine_label", "engine_combo", "comment_box"};
    const int names_size = sizeof(names) / sizeof(const char**);
    for (int i = 0; i < names_size; ++i)
    {
      Gtk::Widget* w = 0;
      xml()->get_widget(names[i], w);
      if (w)
      {
        if (w->is_visible())
          w->hide();
        else
          w->show();
      }
    }
  }
}

//------------------------------------------------------------------------------
bool DbMySQLTableEditor::switch_edited_object(bec::GRTManager *grtm, const grt::BaseListRef &args)
{
  MySQLTableEditorBE* old_be = _be;
  _be = new MySQLTableEditorBE(grtm, db_mysql_TableRef::cast_from(args[0]), get_rdbms_for_db_object(args[0]));

  _columns_page->switch_be(_be);
  _indexes_page->switch_be(_be);
  _fks_page->switch_be(_be);
  _triggers_page->switch_be(_be);
  _part_page->switch_be(_be);
  _opts_page->switch_be(_be);
  if (!is_editing_live_object())
  {
    Gtk::ScrolledWindow *placeholder= 0;
    xml()->get_widget("inserts_recordset_view_placeholder", placeholder);
    placeholder->remove();
    _inserts_page= RecordsetView::create(_be->get_inserts_model(), placeholder);
    //_inserts_page->model(_be->get_inserts_model());

    _privs_page->switch_be(_be);
  }
  _be->set_refresh_ui_slot(sigc::mem_fun(this, &DbMySQLTableEditor::refresh_form_data));
  _be->set_partial_refresh_ui_slot(sigc::mem_fun(this, &DbMySQLTableEditor::partial_refresh));

  delete old_be;

  do_refresh_form_data();

  if (_editor_notebook->get_nth_page(_editor_notebook->get_current_page()) == _main_page_widget)
  {
    Gtk::Entry *entry(0);
    xml()->get_widget("table_name", entry);
    focus_widget_when_idle(entry);
  }
  return true;
}

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

//------------------------------------------------------------------------------

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

//------------------------------------------------------------------------------
void DbMySQLTableEditor::set_table_option_by_name(const std::string& name, const std::string& value)
{
  if (name == "CHARACTER SET - COLLATE" && value[0] == '*')
    _be->set_table_option_by_name(name, "");
  else
    _be->set_table_option_by_name(name, value);
}

//------------------------------------------------------------------------------
void DbMySQLTableEditor::create_table_page()
{
  // Connect Table tab widgets
  bind_entry_and_be_setter("table_name", this, &DbMySQLTableEditor::set_table_name);

  Gtk::ComboBox* combo = 0;
  xml()->get_widget("engine_combo", combo);
  setup_combo_for_string_list(combo);
  fill_combo_from_string_list(combo, _be->get_engines_list());
  add_option_combo_change_handler(combo, "ENGINE", sigc::mem_fun(this, &DbMySQLTableEditor::set_table_option_by_name));

  combo = 0;
  xml()->get_widget("collation_combo", combo);
  setup_combo_for_string_list(combo);

  std::vector<std::string> collations(_be->get_charset_collation_list());
  collations.insert(collations.begin(), "*Default*");
  fill_combo_from_string_list(combo, collations);
  add_option_combo_change_handler(combo, "CHARACTER SET - COLLATE", sigc::mem_fun(this, &DbMySQLTableEditor::set_table_option_by_name));

  Gtk::TextView *tview = 0;
  xml()->get_widget("table_comments", tview);

  add_text_change_timer(tview, sigc::mem_fun(this, &DbMySQLTableEditor::set_comment));

}

//------------------------------------------------------------------------------

bool DbMySQLTableEditor::can_close()
{
  if (_inserts_page && _inserts_page->has_changes())
  {
    Gtk::MessageDialog dlg("<b>There are unsaved changes in the INSERTS editor</b>\nPlease Apply or Revert these changes before closing.",
                           true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
  
    dlg.run();
    return false;
  }
  return _be->can_close();
}

//------------------------------------------------------------------------------
void DbMySQLTableEditor::set_comment(const std::string& cmt)
{
  _be->set_comment(cmt);
}

//------------------------------------------------------------------------------
void DbMySQLTableEditor::partial_refresh(const int what)
{
  switch (what)
  {
    case ::bec::TableEditorBE::RefreshColumnCollation:
		case ::bec::TableEditorBE::RefreshColumnMoveUp:
		case ::bec::TableEditorBE::RefreshColumnMoveDown:
      {
        _columns_page->partial_refresh(what);
        break;
      }
    default:
      {
        g_message("DbMySQLTableEditor: unsupported partial refresh");
      }
  }
}

//------------------------------------------------------------------------------
void DbMySQLTableEditor::refresh_table_page()
{
  Gtk::Entry *entry(0);
  xml()->get_widget("table_name", entry);

  if (_be->get_name() != entry->get_text())
  {
    entry->set_text(_be->get_name());
    _signal_title_changed.emit(_be->get_title());
  }

  Gtk::TextView *tview;
  xml()->get_widget("table_comments", tview);
  tview->get_buffer()->set_text(_be->get_comment());

  Gtk::ComboBox *combo = 0;
  xml()->get_widget("engine_combo", combo);
  set_selected_combo_item(combo, _be->get_table_option_by_name("ENGINE"));

  xml()->get_widget("collation_combo", combo);
  std::string collation = _be->get_table_option_by_name("CHARACTER SET - COLLATE");
  if (collation == " - " || collation.empty())
    set_selected_combo_item(combo, "*Default*");
  else
    set_selected_combo_item(combo, collation);
}

//------------------------------------------------------------------------------
void DbMySQLTableEditor::do_refresh_form_data()
{
  refresh_table_page();

  _columns_page->refresh();
  _indexes_page->refresh();
  _fks_page->refresh();
  _triggers_page->refresh();
  _part_page->refresh();
  _opts_page->refresh();

  if (!is_editing_live_object())
  {
    Gtk::Notebook *notebook;
    xml()->get_widget("mysql_editor_notebook", notebook);
    Gtk::ScrolledWindow *placeholder= 0;
    xml()->get_widget("inserts_recordset_view_placeholder", placeholder);
    if (notebook->page_num(*placeholder) == notebook->get_current_page())
      _inserts_page->reset();

    _privs_page->refresh();
  }
  else
  {
    Gtk::ComboBox *cbox = 0;
    xml()->get_widget("schema_combo", cbox);
    if (cbox)
    {
      fill_combo_from_string_list(cbox, _be->get_all_schema_names());
      cbox->set_active(0);
    }
  }
}

//TESTING
//--------------------------------------------------------------------------------
void DbMySQLTableEditor::refresh_indices()
{
  _indexes_page->refresh();
}
//\TESTING

//--------------------------------------------------------------------------------
void DbMySQLTableEditor::page_changed(GtkNotebookPage* page, guint page_num)
{
  switch (page_num)
  {
  case 0: // general stuff
    break;

  case 1: // columns
    break;

  case 2: // indexes
    _indexes_page->refresh();
    break;

  case 3: // fks
    _fks_page->refresh(); // Note! Currently the call to refresh is mandatory to show/hide FK page content depending on engine capabilities
    break;

  case 4: // triggers
    _triggers_page->refresh();
    break;

  case 5: // partition
    _part_page->refresh();
    break;

  case 6: // options
    _opts_page->refresh();
    break;

  case 7: // inserts
    //_inserts_page->refresh();
    _be->get_inserts_model()->refresh();
    break;
      
  case 8: // privs
    _privs_page->refresh();
    break;
  }
}

//--------------------------------------------------------------------------------
bool DbMySQLTableEditor::event_from_table_name_entry(GdkEvent* event)
{
  if ( event->type == GDK_KEY_RELEASE && (   event->key.keyval == GDK_Return
                                          || event->key.keyval == GDK_KP_Enter
                                         )
     )
  {
    Gtk::Notebook *editor_window(0);
    xml()->get_widget("mysql_editor_notebook", editor_window);

    editor_window->set_current_page(1);
  }

  return false;
}

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