#include "stdafx.h"

#include "wb_config.h"

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


#include "diff_tree.h"
#include "db_mysql_sql_script_sync.h"

#include "db_mysql_sql_sync.h"


using namespace grtui;
using namespace mforms;


namespace DBSynchronize
{
  
class ConnectionPage;
class FetchSchemaNamesProgressPage;
class SchemaSelectionPage;
class FetchSchemaContentsProgressPage;
class ObjectSelectionPage;
class ReviewScriptPage;
class DBSynchronizeProgressPage;
class FinishPage;


#include "connection_page.h"

#include "fetch_schema_names_page.h"

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

#include "schema_selection_page.h"

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

#include "fetch_schema_contents_page.h"

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

#include "synchronize_differences_page.h"

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

class WbPluginDbSynchronize : public WizardPlugin
{
  DbMySQLScriptSync _be;
  DbMySQLSync _db_be;
  
  
  std::vector<std::string> load_schemata()
  {
    std::vector<std::string> schema_names;

    _db_be.load_schemata(schema_names);
    return schema_names;
  }

public:
  WbPluginDbSynchronize(grt::Module *module);
  
  DbMySQLScriptSync *get_be() { return &_be; }

  DbMySQLSync *get_db_be() { return &_db_be; }
};


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

class PreviewScriptPage : public ViewTextPage
{
public:
  PreviewScriptPage(WizardForm *form)
  : ViewTextPage(form, "preview", (ViewTextPage::Buttons)(ViewTextPage::CopyButton|ViewTextPage::SaveButton), "SQL Scripts (*.sql)|*.sql")
  {
    set_title(_("Preview Database Changes to be Applied"));
    set_short_title(_("Review DB Changes"));
    
    set_editable(true);

    signal_leave().connect(sigc::mem_fun(this, &PreviewScriptPage::apply_changes));
  }


  virtual void enter(bool advancing)
  {
    if (advancing)
      set_text(((WbPluginDbSynchronize*)_form)->get_be()->generate_diff_tree_script());
  }
  
  void apply_changes(bool advancing)
  {
    ((WbPluginDbSynchronize*)_form)->get_db_be()->set_option("ScriptToApply", get_text());//TODO: does this seves any purpose any more?
    ((WbPluginDbSynchronize*)_form)->get_db_be()->sql_script(get_text());
  }
  
  virtual std::string next_button_caption() { return execute_caption(); }
};


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

class DBSynchronizeProgressPage : public WizardProgressPage
{
  bool got_errors_in_db_sync;
  
public:
  DBSynchronizeProgressPage(WbPluginDbSynchronize *form)
    : WizardProgressPage(form, "importProgress")
  {    
    set_title(_("Progress of Model and Database Synchronization"));
    set_short_title(_("Synchronize Progress"));

    add_async_task(_("Apply Changes to Database"),
                   sigc::mem_fun(this, &DBSynchronizeProgressPage::perform_sync_db),
                   _("Applying selected changes from model to the database..."));

    add_task(_("Apply Changes to Model"),
             sigc::mem_fun(this, &DBSynchronizeProgressPage::perform_sync_model),
             _("Applying selected changes from database to the model..."));

    end_adding_tasks(true,
                     _("Synchronization Completed Successfully"));

    set_status_text("");
  }


  virtual void enter(bool advancing)
  {
    if (advancing)
      got_errors_in_db_sync= false;
    
    WizardProgressPage::enter(advancing);
  }

  bool perform_sync_db()
  {
    execute_grt_task(sigc::mem_fun(((WbPluginDbSynchronize*)_form)->get_db_be(), 
                                   &Db_plugin::apply_script_to_db), false);
    return true;
  }
  
  bool perform_sync_model()
  {
    if (!got_errors_in_db_sync)
    {
      ((WbPluginDbSynchronize*)_form)->get_be()->update_model_old_names();
    }

    ((WbPluginDbSynchronize*)_form)->get_be()->apply_changes_to_model();

    return true;
  }
  
  virtual bool allow_back() { return false; }
  virtual bool allow_cancel() { return false; }

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


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


WbPluginDbSynchronize::WbPluginDbSynchronize(grt::Module *module)
  : WizardPlugin(module), _be(grtm()), _db_be(grtm())
{  
  // add validation here
  
  ConnectionPage *connection_page= new ConnectionPage(this);
  connection_page->set_db_connection(_db_be.db_conn());
  add_page(connection_page);

  FetchSchemaNamesProgressPage *fetch_progress_page= new FetchSchemaNamesProgressPage(this);
  fetch_progress_page->set_db_connection(_db_be.db_conn());
  fetch_progress_page->set_load_schemata_slot(sigc::mem_fun(this, &WbPluginDbSynchronize::load_schemata));
  add_page(fetch_progress_page);

  SchemaSelectionPage *schema_selection_page= new SchemaSelectionPage(this);
  schema_selection_page->set_db_plugin(&_db_be);
  add_page(schema_selection_page);

  FetchSchemaContentsProgressPage *fetch_contents_page= new FetchSchemaContentsProgressPage(this);
  fetch_contents_page->set_db_plugin(&_db_be);
  add_page(fetch_contents_page);

  SynchronizeDifferencesPage *diffs_page= new SynchronizeDifferencesPage(this, &_be);
  diffs_page->set_title(_("Model and Database Differences"));
  diffs_page->set_source_catalog_slot(sigc::mem_fun(&_db_be, &Db_plugin::db_catalog));
  add_page(diffs_page);
  
  add_page(new PreviewScriptPage(this));
  add_page(new DBSynchronizeProgressPage(this));

  set_title("Synchronize Model with Database");
}


}; // namespace DBSynchronize

grtui::WizardPlugin *createDbSynchronizeWizard(grt::Module *module, db_CatalogRef catalog)
{
  return new DBSynchronize::WbPluginDbSynchronize(module);
}

