#include "stdafx.h"
#include "db_mysql_diff_reporting.h"

#include "grtdb/db_object_helpers.h"

#include "grts/structs.h"
#include "grts/structs.db.mgmt.h"
#include "grts/structs.db.mysql.h"
#include "grts/structs.workbench.h"

#include "grtpp.h"

using namespace grt;

#include "diff/diffchange.h"
#include "grtdb/diff_dbobjectmatch.h"

#include "grtsqlparser/sql_facade.h"
#include "grti/sqlgenerator.h"
#include "db.mysql/backend/db_mysql_public_interface.h"

#include "db.mysql/src/module_db_mysql_shared_code.h"
#include "grtdb/charset_utils.h"
#include "grtdb/db_object_helpers.h"

DbMySQLDiffReporting::DbMySQLDiffReporting(bec::GRTManager *m) 
  : manager_(m)
{}

DbMySQLDiffReporting::~DbMySQLDiffReporting()
{}

// this function gets catalog from file or (if filename is empty) from the GRT tree
db_mysql_CatalogRef DbMySQLDiffReporting::get_cat_from_file_or_tree(std::string filename, 
                                                                 std::string& error_msg)
{
  db_mysql_CatalogRef ref_cat= get_model_catalog();

  if(!ref_cat.is_valid())
  {
    error_msg.assign("Internal error. Catalog is invalid");
    return db_mysql_CatalogRef();
  }

  if(filename.empty())
  {
    ref_cat->name("default");
    ref_cat->oldName("default");
    return ref_cat;
  }

  workbench_physical_ModelRef pm= workbench_physical_ModelRef::cast_from(ref_cat->owner());

  db_mysql_CatalogRef cat(manager_->get_grt());
  cat->version(pm->rdbms()->version());
  grt::replace_contents(cat->simpleDatatypes(), pm->rdbms()->simpleDatatypes());

  cat->name("default");
  cat->oldName("default");

  GError *file_error= NULL;
  char *sql_input_script= NULL;
  size_t sql_input_script_length= 0;
  
  if(!g_file_get_contents(filename.c_str(), &sql_input_script, &sql_input_script_length, &file_error))
  {
    std::string file_error_msg("Error reading input file: ");
    file_error_msg.append(file_error->message);
    error_msg.assign(file_error_msg.c_str());
    return db_mysql_CatalogRef();
  }

  SqlFacade::Ref sql_parser= SqlFacade::instance_for_rdbms(pm->rdbms());
  sql_parser->parseSqlScriptString(cat, sql_input_script);
  g_free(sql_input_script);

  return cat;
}

std::string DbMySQLDiffReporting::generate_report(const std::string& left_file, 
                                                  const std::string& right_file, 
                                                  const grt::ValueRef &left, 
                                                  const grt::ValueRef &right)
{
  std::string err;
  db_mysql_CatalogRef left_cat, right_cat, left_cat_copy, right_cat_copy;

  if(!left.is_valid())
  {
    left_cat= get_cat_from_file_or_tree(left_file, err);
    if(!err.empty())
      throw DbMySQLDiffReportingException(err);
  }
  else
  {
    left_cat= db_mysql_CatalogRef::cast_from(left);
  }

  std::string default_engine_name;
  grt::ValueRef default_engine = manager_->get_app_option("db.mysql.Table:tableEngine");
  if(grt::StringRef::can_wrap(default_engine))
    default_engine_name = grt::StringRef::cast_from(default_engine);

  left_cat_copy= db_mysql_CatalogRef::cast_from(grt::copy_object(manager_->get_grt(), left_cat));
  bec::CatalogHelper::apply_defaults(left_cat_copy, default_engine_name);

  if(!right.is_valid())
  {
    right_cat= get_cat_from_file_or_tree(right_file, err);
    if(!err.empty())
      throw DbMySQLDiffReportingException(err);
  }
  else
  {
    right_cat= db_mysql_CatalogRef::cast_from(right);
  }

  right_cat_copy= db_mysql_CatalogRef::cast_from(grt::copy_object(manager_->get_grt(), right_cat));
  bec::CatalogHelper::apply_defaults(right_cat_copy, default_engine_name);

  CatalogMap left_catalog_map;
  build_catalog_map(left_cat_copy, left_catalog_map);
  update_all_old_names(left_cat_copy, true, left_catalog_map);

  CatalogMap right_catalog_map;
  build_catalog_map(right_cat_copy, right_catalog_map);
  update_all_old_names(right_cat_copy, true, right_catalog_map);

  db_mgmt_RdbmsRef rdbms= db_mgmt_RdbmsRef::cast_from(manager_->get_grt()->get("/wb/rdbmsMgmt/rdbms/0"));

  bec::apply_user_datatypes(right_cat_copy, rdbms);
  bec::apply_user_datatypes(left_cat_copy, rdbms);


  grt::DbObjectMatchAlterOmf omf;
  omf.dontdiff_mask = 3;
  grt::NormalizedComparer normalizer(manager_->get_grt());
  normalizer.init_omf(&omf);
  boost::shared_ptr<DiffChange> alter_change= diff_make(left_cat_copy, right_cat_copy, &omf);

  SQLGeneratorInterfaceWrapper *diffsql_module= 
    manager_->get_grt()->get_module_wrapper<SQLGeneratorInterfaceWrapper>("DbMySQL");

  if(diffsql_module == NULL)
    throw DbMySQLDiffReportingException("error loading module MySQLModuleDbMySQL");

  std::string tpath;
  tpath.append("modules").append(G_DIR_SEPARATOR_S).append("data").append(G_DIR_SEPARATOR_S).append("db_mysql_catalog_reporting")
    .append(G_DIR_SEPARATOR_S).append("Basic_Text.tpl").append(G_DIR_SEPARATOR_S).append("basic_text_report.txt.tpl");

  grt::DictRef options(manager_->get_grt());
  options.set("UseFilteredLists", grt::IntegerRef(0));
  options.set("KeepOrder", grt::IntegerRef(1));
  options.set("TemplateFile", 
    grt::StringRef(manager_->get_data_file_path(tpath).c_str()));

  char buf1[128];
  sprintf(buf1, "%p", alter_change.get());

  //if(alter_change)
  //  alter_change->dump_log(0); 

  grt::StringRef output_string(
    diffsql_module->generateReport(left_cat_copy, options, std::string(buf1)));

  return std::string(output_string.c_str());
}
