#include "stdafx.h"

#include <iconv.h>
#include <boost/foreach.hpp>

#include "db_reverse_engineer_script.h"

using namespace ScriptImport;

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

ImportInputPage::ImportInputPage(WizardPlugin *form)
  : WizardPage(form, "options"), _contents(true)
{
  set_title(_("Input and Options"));
  set_short_title(_("Input and Options"));

  add(&_table, false, false);
  _table.set_row_count(4);
  _table.set_column_count(2);
  _table.set_row_spacing(14);
  _table.set_column_spacing(4);
  
  _heading.set_style(WizardHeadingStyle);
  _heading.set_text(_("Select the script containing the schemata to reverse engineer"));
  _table.add(&_heading, 0, 2, 0, 1, 0);

  _contents.set_spacing(8);
  _table.add(&_caption, 0, 1, 1, 2, mforms::HFillFlag);
  _contents.add(&_filename, true, true);
  _contents.add(&_browse_button, false, false);
  _table.add(&_contents, 1, 2, 1, 2, mforms::HExpandFlag|mforms::HFillFlag);
  
  enable_file_browsing(&_filename, &_browse_button, mforms::OpenFile, "SQL Files (*.sql)|*.sql");
  
  _caption.set_text_align(mforms::WizardLabelAlignment);
  _caption.set_text(_("Select SQL script file:"));
  _browse_button.set_text(_("Browse..."));

  _filename.signal_changed().connect(sigc::mem_fun(this, &ImportInputPage::file_changed));

  _file_codeset_caption.set_text(_("File encoding:"));
  _file_codeset_caption.set_text_align(mforms::WizardLabelAlignment);
  
  _table.add(&_file_codeset_caption, 0, 1, 2, 3, mforms::HFillFlag);
  _table.add(&_file_codeset_sel, 1, 2, 2, 3, mforms::HExpandFlag | mforms::HFillFlag);

  // Fill the encoding selector with a useful list of encodings.
  fill_encodings_list();

  _table.add(&_autoplace_check, 1, 2, 3, 4, 0);
  _autoplace_check.set_text(_("Place imported objects on a diagram"));
  _autoplace_check.set_active(true);

  signal_leave().connect(sigc::mem_fun(this, &ImportInputPage::gather_options));

  _filename.set_value(form->module()->document_string_data("input_filename", ""));
  _autoplace_check.set_active(form->module()->document_int_data("place_figures", 0));
}

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

/**
 * Fills the selector (lookup) for file encodings with useful values.
 */
void ImportInputPage::fill_encodings_list()
{
  const char* encodings[]=
  {
    "ARMSCII8", "ASCII", "BIG5", "BINARY", "CP1250", "CP1251", "CP1256", "CP1257",
    "CP850", "CP852", "CP866", "CP932", "DEC8", "EUCJPMS", "EUCKR", "GB2312", "GBK",
    "GEOSTD8", "GREEK", "HEBREW", "HP8", "KEYBCS2", "KOI8R", "KOI8U", "LATIN1", "LATIN2",
    "LATIN5", "LATIN7", "MACCE", "MACROMAN", "SJIS", "SWE7", "TIS620", "UCS2", "UJIS", "UTF8"
  };

  int encodings_count= sizeof(encodings)/sizeof(encodings[0]);
  for (int i= 0; i < encodings_count; ++i)
    _file_codeset_sel.add_item(encodings[i]);

  // As default find and select UTF8.
  const std::string default_encoding= "UTF8";
  int default_encoding_index= -1;
  for (int i= 0; i < encodings_count; ++i)
  {
    if (default_encoding == encodings[i])
    {
      default_encoding_index= i;
      break;
    }
  }
  if (default_encoding_index > 0)
    _file_codeset_sel.set_selected(default_encoding_index);
}

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

void ImportInputPage::file_changed()
{
  validate();
}

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

void ImportInputPage::do_validate()
{
  if (!_filename.get_string_value().empty())
  {
    if (!g_file_test(_filename.get_string_value().c_str(), (GFileTest)(G_FILE_TEST_EXISTS|G_FILE_TEST_IS_REGULAR)))
    {
      _form->set_problem(_("Invalid path"));
      return;
    }
  }
  _form->clear_problem();
}

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

bool ImportInputPage::allow_next()
{
  return !_filename.get_string_value().empty();
}

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

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

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

void ImportInputPage::gather_options(bool advancing)
{
  values().gset("import.filename", _filename.get_string_value());
  values().gset("import.file_codeset", _file_codeset_sel.get_string_value());
  values().gset("import.place_figures", _autoplace_check.get_active());
  
  grt::Module *module= ((WizardPlugin*)_form)->module();

  module->set_document_data("input_filename", _filename.get_string_value());
  module->set_document_data("place_figures", _autoplace_check.get_active());
}

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

ImportProgressPage::ImportProgressPage(WizardForm *form)
  : WizardProgressPage(form, "progress")
{
  set_title(_("Reverse Engineering Progress"));
  set_short_title(_("Reverse Engineer"));

  _auto_place= false;
  _done= false;
  
  _import_be.grtm(form->grtm());

  //showAdvancedImportLogPage = false;
  //caseSensitiveIdentifiersCB.Checked = sqlImport.get_bool_option("SqlIdentifiersCS");

  TaskRow *task=
    add_async_task(_("Reverse Engineer SQL Script"), 
                   sigc::mem_fun(this, &ImportProgressPage::import_objects),
                   _("Reverse engineering and importing objects from script..."));
  task->process_finish= sigc::mem_fun(this, &ImportProgressPage::import_objects_finished);

  add_task(_("Verify Results"), 
           sigc::mem_fun(this, &ImportProgressPage::verify_results),
           _("Verifying imported objects..."));

  _auto_place_task= 
    add_async_task(_("Place Objects on Diagram"), 
                   sigc::mem_fun(this, &ImportProgressPage::place_objects),
                   _("Placing imported objects on a new diagram..."));

  end_adding_tasks(true,
                   _("Import finished."));

  set_status_text("");
}

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

void ImportProgressPage::import_objects_finished(grt::ValueRef value)
{
  _form->grtm()->get_grt()->send_info(grt::StringRef::cast_from(value));
}

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

bool ImportProgressPage::import_objects()
{
  execute_grt_task(_import_be.get_task_slot(), false);
  return true;
}

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

bool ImportProgressPage::verify_results()
{
  return true;
}

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

bool ImportProgressPage::place_objects()
{
  if (_auto_place)
  {
    execute_grt_task(_import_be.get_autoplace_task_slot(), false);
    return true;
  }
  return false;
}

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

bool ImportProgressPage::allow_back()
{
  return false;
}

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

void ImportProgressPage::enter(bool advancing)
{
  if (advancing)
  {
    _import_be.sql_script(values().get_string("import.filename"));
    _import_be.sql_script_codeset(values().get_string("import.file_codeset"));
    
    _auto_place= values().get_int("import.place_figures");
    
    _auto_place_task->set_enabled(_auto_place);
    
    // sqlImport.set_option("case_sensitive_identifiers", caseSensitiveIdentifiersCB.Checked);
    // sqlImport.set_option("processing_create_statements", procCreateStmtCB.Checked);
    // sqlImport.set_option("processing_alter_statements", procAlterStmtCB.Checked);
    //sqlImport.set_option("processing_drop_statements", procDropStmtCB.Checked);
  }
  WizardProgressPage::enter(advancing);
}

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

std::string ImportProgressPage::get_summary()
{
  std::string summary;
  int schemas= 0, tables= 0, views= 0, procedures= 0;
  
  grt::ListRef<GrtObject> created_objects= _import_be.get_created_objects();
  
  for (grt::ListRef<GrtObject>::const_iterator iter= created_objects.begin();
       iter != created_objects.end(); ++iter)
  {
    if ((*iter).is_instance<db_Schema>())
      schemas++;
    else if ((*iter).is_instance<db_Table>())
      tables++;
    else if ((*iter).is_instance<db_View>())
      views++;
    else if ((*iter).is_instance<db_Routine>())
      procedures++;
  }

  summary= strfmt(_("Import of SQL script file '%s' has finished.\n\n"
                    "%i tables, %i views and %i stored procedures were imported in %i schemas.\n\n"),
                  _import_be.sql_script().c_str(),
                  tables, views, procedures, schemas);

  if (_got_error_messages)
    summary.append(_("There were errors during the import.\n"));
  else if (_got_warning_messages)
    summary.append(_("There were warnings during the import.\n"));

  summary.append(_("Go Back to the previous page to review the logs."));


  return summary;
}

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

WbPluginSQLImport::WbPluginSQLImport(grt::Module *module)
  : WizardPlugin(module)
{
  _input_page= new ImportInputPage(this);
  _progress_page= new ImportProgressPage(this);
  
  _progress_page->signal_tasks_finished().
    connect(sigc::mem_fun(this, &WbPluginSQLImport::update_summary));
  
  _finish_page= new WizardFinishedPage(this, _("SQL Import Finished"));

  add_page(_input_page);
  add_page(_progress_page);
  add_page(_finish_page);
  
  set_title(_("Reverse Engineer SQL Script"));
}

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

void WbPluginSQLImport::update_summary(bool success)
{
  _finish_page->set_title(success ? _("SQL Import Finished Successfully")
                          : _("SQL Import Failed"));
  _finish_page->set_summary(_progress_page->get_summary());
}

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

grtui::WizardPlugin *createImportScriptWizard(grt::Module *module, db_CatalogRef catalog)
{
  return new ScriptImport::WbPluginSQLImport(module);
}
