#include "stdafx.h"

#include "grtui/grt_wizard_plugin.h"
#include "grtui/wizard_progress_page.h"
#include "grtui/wizard_view_text_page.h"
#include "grtui/grtdb_connect_panel.h"
#include "grtui/wizard_object_filter_page.h"
#include "grtui/db_conn_be.h"

#include "db_frw_eng_be.h"

#include "catalog_validation_page.h"

using namespace grtui;
using namespace mforms;

namespace DBExport
{

class ExportInputPage;
class ExportFilterPage;
class ConnectionPage;
class ExportProgressPage;
class ExportFinishPage;
class PreviewScriptPage;


class WbPluginDbExport : public WizardPlugin
{
  CatalogValidationPage *_validation_page;
  ExportInputPage *_input_page;
  ExportFilterPage *_selection_page;
  ConnectionPage *_connection_page;
  ExportProgressPage *_progress_page;
  PreviewScriptPage *_preview_page;

  Db_frw_eng _db_frw_eng;

public:
  WbPluginDbExport(grt::Module *module);

  Db_frw_eng *be() { return &_db_frw_eng; }
};


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

class ExportInputPage : public WizardPage
{
public:
  ExportInputPage(WizardForm *form)
  : WizardPage(form, "options"), _options(mforms::TitledBoxPanel), _options_box(false)
  {
    set_title(_("Set Options for Database to be Created"));
    set_short_title(_("Options"));

    _options.set_title(_("Options"));

    _options.add(&_options_box);
    _options_box.set_padding(12);
    _options_box.set_spacing(8);

    _generate_drop_check.set_text(_("DROP Objects Before Each CREATE Object"));
    _options_box.add(&_generate_drop_check, false, false);
    _generate_drop_schema_check.set_text(_("Generate DROP SCHEMA"));
    _options_box.add(&_generate_drop_schema_check, false, false);
    _skip_foreign_keys_check.set_text(_("Skip creation of FOREIGN KEYS"));
    _options_box.add(&_skip_foreign_keys_check, false, false);
    _omit_schema_qualifier_check.set_text(_("Omit Schema Qualifier in Object Names"));
    _options_box.add(&_omit_schema_qualifier_check, false, false);
    _generate_create_index_check.set_text(_("Generate Separate CREATE INDEX Statements"));
    _options_box.add(&_generate_create_index_check, false, false);
    _generate_show_warnings_check.set_text(_("Add SHOW WARNINGS After Every DDL Statement"));
    _options_box.add(&_generate_show_warnings_check, false, false);
    _skip_users_check.set_text(_("Do Not Create Users. Only Create Privileges"));
    _options_box.add(&_skip_users_check, false, false);
    _generate_insert_check.set_text(_("Generate INSERT Statements for Tables"));
    _options_box.add(&_generate_insert_check, false, false);

    add(&_options, false, false);
    
    signal_leave().connect(sigc::mem_fun(this, &ExportInputPage::gather_options));
    
    grt::Module *module= ((WizardPlugin*)_form)->module();
    _generate_drop_check.set_active(module->document_int_data("GenerateDrops", 0));
    _generate_drop_schema_check.set_active(module->document_int_data("GenerateSchemaDrops", 0));
    _skip_foreign_keys_check.set_active(module->document_int_data("SkipForeignKeys", 0));
    _generate_show_warnings_check.set_active(module->document_int_data("GenerateWarnings", 0)); 
    _generate_create_index_check.set_active(module->document_int_data("GenerateCreateIndex", 0));
    _skip_users_check.set_active(module->document_int_data("NoUsersJustPrivileges", 0));
    _generate_insert_check.set_active(module->document_int_data("GenerateInserts", 0));
    _omit_schema_qualifier_check.set_active(module->document_int_data("OmitSchemata", 0));
  }

  void gather_options(bool advancing)
  {    
    values().gset("GenerateDrops", _generate_drop_check.get_active());
    values().gset("GenerateSchemaDrops", _generate_drop_schema_check.get_active());
    values().gset("SkipForeignKeys", _skip_foreign_keys_check.get_active());
    values().gset("GenerateWarnings", _generate_show_warnings_check.get_active());
    values().gset("GenerateCreateIndex", _generate_create_index_check.get_active());
    values().gset("NoUsersJustPrivileges", _skip_users_check.get_active());
    values().gset("GenerateInserts", _generate_insert_check.get_active());
    values().gset("OmitSchemata", _omit_schema_qualifier_check.get_active());
    
    grt::Module *module= ((WizardPlugin*)_form)->module();
    module->set_document_data("GenerateDrops", _generate_drop_check.get_active());
    module->set_document_data("GenerateSchemaDrops", _generate_drop_schema_check.get_active());
    module->set_document_data("SkipForeignKeys", _skip_foreign_keys_check.get_active());
    module->set_document_data("GenerateWarnings", _generate_show_warnings_check.get_active());
    module->set_document_data("GenerateCreateIndex", _generate_create_index_check.get_active());
    module->set_document_data("NoUsersJustPrivileges", _skip_users_check.get_active());
    module->set_document_data("GenerateInserts", _generate_insert_check.get_active());
    module->set_document_data("OmitSchemata", _omit_schema_qualifier_check.get_active());
  }

protected:
  Panel _options;
  Box _options_box;

  CheckBox _generate_drop_check;
  CheckBox _generate_drop_schema_check;
  CheckBox _skip_foreign_keys_check;
  CheckBox _generate_create_index_check;
  CheckBox _generate_show_warnings_check;
  CheckBox _skip_users_check;
  CheckBox _generate_insert_check;
  CheckBox _omit_schema_qualifier_check;
};

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

class ExportFilterPage : public WizardObjectFilterPage
{
public:
  ExportFilterPage(WizardForm *form, Db_frw_eng *plugin_be)
    : WizardObjectFilterPage(form, "filter"), _export_be(plugin_be)
  {
    set_short_title(_("Select Objects"));
    set_title(_("Select Objects to Forward Engineer"));

    _top_label.set_wrap_text(true);
    _top_label.set_text(_("To exclude objects of a specific type from the SQL Export, disable the corresponding checkbox. "
                          "Press Show Filter and add objects or patterns to the ignore list to exclude them from the export."));
  }


protected:
  virtual void enter(bool advancing)
  {
    if (advancing)
      setup_filters();
    
    WizardObjectFilterPage::enter(advancing);
  }
  
  
  void setup_filters()
  {
    reset();

    bec::GrtStringListModel *users_model;
    bec::GrtStringListModel *users_imodel;
    bec::GrtStringListModel *tables_model;
    bec::GrtStringListModel *tables_imodel;
    bec::GrtStringListModel *views_model;
    bec::GrtStringListModel *views_imodel;
    bec::GrtStringListModel *routines_model;
    bec::GrtStringListModel *routines_imodel;
    bec::GrtStringListModel *triggers_model;
    bec::GrtStringListModel *triggers_imodel;

    _export_be->setup_grt_string_list_models_from_catalog(&users_model, &users_imodel, 
                                                       &tables_model, &tables_imodel,
                                                       &views_model, &views_imodel, 
                                                       &routines_model, &routines_imodel, 
                                                       &triggers_model, &triggers_imodel);
    
    
    _table_filter= add_filter(db_mysql_Table::static_class_name(),
                              _("Export %s Objects"),
                              tables_model, tables_imodel);
    
    _view_filter= add_filter(db_mysql_View::static_class_name(),
                             _("Export %s Objects"),
                             views_model, views_imodel);
    
    _routine_filter= add_filter(db_mysql_Routine::static_class_name(),
                                _("Export %s Objects"),
                                routines_model, routines_imodel);

    _trigger_filter= add_filter(db_mysql_Trigger::static_class_name(),
                                _("Export %s Objects"),
                                triggers_model, triggers_imodel);

    _user_filter= add_filter(db_User::static_class_name(),
                             _("Export %s Objects"),
                             users_model, users_imodel);
  }
  
  virtual bool advance()
  {
    _export_be->set_option("OutputFileName", values().get_string("OutputFileName"));
    _export_be->set_option("GenerateDrops", values().get_int("GenerateDrops"));
    _export_be->set_option("GenerateSchemaDrops", values().get_int("GenerateSchemaDrops"));
    _export_be->set_option("SkipForeignKeys", values().get_int("SkipForeignKeys"));
    _export_be->set_option("GenerateWarnings", values().get_int("GenerateWarnings"));
    _export_be->set_option("GenerateCreateIndex", values().get_int("GenerateCreateIndex"));
    _export_be->set_option("NoUsersJustPrivileges", values().get_int("NoUsersJustPrivileges"));
    _export_be->set_option("GenerateInserts", values().get_int("GenerateInserts"));
    _export_be->set_option("OmitSchemata", values().get_int("OmitSchemata"));
    
    _export_be->set_option("TablesAreSelected", _table_filter->get_active());
    _export_be->set_option("TriggersAreSelected", _trigger_filter->get_active());
    _export_be->set_option("RoutinesAreSelected", _routine_filter->get_active());
    _export_be->set_option("ViewsAreSelected", _view_filter->get_active());
    _export_be->set_option("UsersAreSelected", _user_filter->get_active());    
    return true;
  }

  
protected:
  Db_frw_eng *_export_be;
  DBObjectFilterFrame *_table_filter;
  DBObjectFilterFrame *_view_filter;
  DBObjectFilterFrame *_routine_filter;
  DBObjectFilterFrame *_trigger_filter;
  DBObjectFilterFrame *_user_filter;
};

//--------------------------------------------------------------------------------
  
class PreviewScriptPage : public ViewTextPage
{
public:
  PreviewScriptPage(WizardForm *form)
  : ViewTextPage(form, "preview", (ViewTextPage::Buttons)(ViewTextPage::CopyButton|ViewTextPage::SaveButton), "SQL Scripts (*.sql)|*.sql")
  {
    set_short_title(_("Review SQL Script"));
    set_title(_("Review the SQL Script to be Executed"));

    set_editable(true);
    
    _heading.set_wrap_text(true);
    _heading.set_style(mforms::WizardHeadingStyle);
    _heading.set_text(_("This script will now be executed on the DB server to create your databases.\nYou may make changes before executing."));
    add(&_heading, false, false);
  }

  virtual void enter(bool advancing)
  {
    if (advancing)
    {
      std::string script;
      
      Db_frw_eng *backend= ((WbPluginDbExport*)_form)->be();
      
      backend->export_task_finish_cb(sigc::mem_fun(this, &PreviewScriptPage::export_task_finished));
      backend->start_export();
    }
  }

  int export_task_finished()
  {
    _text.set_value(((WbPluginDbExport*)_form)->be()->export_sql_script());

    return 0;
  }
  
  virtual void leave(bool advancing)
  {
    if (advancing)
      ((WbPluginDbExport*)_form)->be()->sql_script(_text.get_string_value());
  }
  
protected:
  mforms::Label _heading;
};


//--------------------------------------------------------------------------------
  
#include "connection_page.h"

class MyConnectionPage : public ConnectionPage
{
public:
  MyConnectionPage(WizardForm *form, const char *name= "connect")
    : ConnectionPage(form, name)
  {
  }

  virtual std::string next_button_caption()
  {
    return execute_caption();
  }
};

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

class ExportProgressPage : public WizardProgressPage
{
  bool _finished;

public:
  ExportProgressPage(WizardForm *form) : WizardProgressPage(form, "progress")
  {
    set_title(_("Forward Engineering Progress"));
    set_short_title(_("Commit Progress"));

    add_async_task(_("Connect to DBMS"),
             sigc::mem_fun(this, &ExportProgressPage::do_connect),
             _("Connecting to DBMS..."));

    TaskRow *task= add_async_task(_("Execute Forward Engineered Script"),
                   sigc::mem_fun(this, &ExportProgressPage::do_export),
                   _("Executing forward engineered SQL script in DBMS..."));
    task->process_finish= sigc::mem_fun(this, &ExportProgressPage::export_finished);

    end_adding_tasks(false,
                     _("Forward Engineer Finished Successfully"));
    
    set_status_text("");
  }


  virtual void enter(bool advancing)
  {
    _finished= false;

    if (advancing)
      reset_tasks();
    
    WizardProgressPage::enter(advancing);
  }

  
  virtual bool allow_back()
  {
    return WizardProgressPage::allow_back() && !_finished;
  }

  virtual bool allow_cancel()
  {
    return WizardProgressPage::allow_cancel() && !_finished;
  }


  bool do_connect()
  {
    execute_grt_task(sigc::bind_return(sigc::hide<0>(sigc::mem_fun(((WbPluginDbExport*)_form)->be()->db_conn(), &DbConnection::test_connection)), grt::ValueRef()),
                     false);

    return true;
  }  
  
  bool do_export()
  {
    execute_grt_task(sigc::mem_fun(((WbPluginDbExport*)_form)->be(), 
                                   &Db_plugin::apply_script_to_db), false);

    return true;
  }


  void export_finished(const grt::ValueRef &result)
  {
    _finished= true;
  }

  virtual bool next_closes_wizard()
  {
    return true;
  }
};



WbPluginDbExport::WbPluginDbExport(grt::Module *module)
    : WizardPlugin(module), _db_frw_eng(grtm())
{
  _input_page= new ExportInputPage(this);
  _connection_page= new MyConnectionPage(this);
  _connection_page->set_db_connection(be()->db_conn());
  _preview_page= new PreviewScriptPage(this);
  _selection_page= new ExportFilterPage(this, &_db_frw_eng);
  _progress_page= new ExportProgressPage(this);
  add_page(_input_page);
  add_page(_selection_page);
  add_page(_preview_page);
  add_page(_connection_page);
  add_page(_progress_page);

  set_title(_("Forward Engineer to Database"));
}


};


grtui::WizardPlugin *createDbExportWizard(grt::Module *module, db_CatalogRef catalog)
{
  return new DBExport::WbPluginDbExport(module);
}


