#ifndef _DB_MYSQL_SQL_SCRIPT_SYNC_H_
#define _DB_MYSQL_SQL_SCRIPT_SYNC_H_

#include "db_mysql_public_interface.h"
#include "grt/grt_manager.h"
#include "grts/structs.db.mysql.h"
#include "grt/grt_string_list_model.h"
#include "diff_tree.h"
#include "db_mysql_validation_page.h"

struct WBPLUGINDBMYSQLBE_PUBLIC_FUNC DbMySQLScriptSyncException : public std::logic_error
{
  DbMySQLScriptSyncException(const std::string& message)
    : std::logic_error(message)
  {}
};

class WBPLUGINDBMYSQLBE_PUBLIC_FUNC DbMySQLScriptSync : public DbMySQLValidationPage
{
  bec::GRTManager *_manager;
  //db_mysql_CatalogRef _catalog;
  db_mysql_CatalogRef _org_cat;
  db_mysql_CatalogRef _mod_cat_copy;

  // options
  std::string _input_filename1, _input_filename2;
  std::string _output_filename;
  std::vector<std::string> schemata_list;  // all schemata present on server (unfiltered)

  ::DiffTreeBE *_diff_tree;
  DiffChange* _alter_change;

  static size_t find_schema_by_old_name(db_mysql_CatalogRef cat, const char *schema_old_name);
  static size_t find_table_by_old_name(db_mysql_SchemaRef schema, const char *table_old_name);
  static size_t find_view_by_old_name(db_mysql_SchemaRef schema, const char *view_old_name);
  static size_t find_routine_by_old_name(db_mysql_SchemaRef schema, const char *routine_old_name);
  static size_t find_trigger_by_old_name(db_mysql_TableRef table, const char *trigger_old_name);  
  static db_ColumnRef find_column_by_old_name(db_mysql_TableRef table, const char *column_old_name);

  static void copy_schema_children(db_mysql_SchemaRef from, db_mysql_SchemaRef to);
  static void copy_table_children(db_mysql_TableRef from, db_mysql_TableRef to);

  void sync_finished(grt::ValueRef res);
  grt::ValueRef sync_task(grt::GRT*, grt::StringRef);
  db_mysql_CatalogRef get_cat_from_file_or_tree(std::string filename, 
                                             std::string& error_msg);

protected:

  virtual db_mysql_CatalogRef get_model_catalog();

public:

  DbMySQLScriptSync(bec::GRTManager *grtm);

  void start_sync();  

  void set_option(const std::string& name, const std::string& value);

  ::DiffTreeBE *init_diff_tree(const std::vector<std::string>& schemata, const ValueRef &cat1, const ValueRef &cat2);
  ::DiffTreeBE *init_diff_tree(const ValueRef &cat1, const ValueRef &cat2);

  void set_next_apply_direction(bec::NodeId nodeid) { _diff_tree->set_next_apply_direction(nodeid); }
  void set_apply_direction(bec::NodeId nodeid, DiffNode::ApplicationDirection dir) { _diff_tree->set_apply_direction(nodeid, dir); }

  std::string generate_diff_tree_script();
  std::string generate_diff_tree_report();
  std::string save_script_to_file(const std::string& script, const std::string& filename);

  void apply_changes_to_model();

  void update_model_old_names();
};


#endif // _DB_MYSQL_SQL_SCRIPT_SYNC_H_
