#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"

class SynchronizeDifferencesPageBEInterface
{
protected:
    ::DiffTreeBE *_diff_tree;
public:
  SynchronizeDifferencesPageBEInterface():_diff_tree(NULL){};
  ValueRef get_model_object(const bec::NodeId &node) const {return _diff_tree->get_node_with_id(node)->get_model_part().get_object();};
  ValueRef get_db_object(const bec::NodeId &node) const {return _diff_tree->get_node_with_id(node)->get_db_part().get_object();};
  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, bool recursive) { _diff_tree->set_apply_direction(nodeid, dir, recursive); }
  virtual std::string get_col_name(const size_t col_id) = 0;
  virtual std::string get_sql_for_object(GrtNamedObjectRef obj) = 0;
  virtual ::DiffTreeBE *init_diff_tree(const std::vector<std::string>& schemata, const grt::ValueRef &ext_cat, 
                                              const grt::ValueRef &cat2, grt::StringListRef SchemaSkipList) = 0;
};


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, public SynchronizeDifferencesPageBEInterface
{
  bec::GRTManager *_manager;
  //db_mysql_CatalogRef _catalog;
  db_mysql_CatalogRef _org_cat;
  db_mysql_CatalogRef _mod_cat_copy;
  grt::StringListRef _alter_list;
  grt::ListRef<GrtNamedObject> _alter_object_list;



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

  boost::shared_ptr<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,StringListRef SchemaSkipList = StringListRef());


  std::string get_sql_for_object(GrtNamedObjectRef obj);



  std::string generate_diff_tree_script();
  std::string generate_diff_tree_report();

  void apply_changes_to_model();

  void update_model_old_names();
  std::string get_col_name(const size_t col_id);
};


#endif // _DB_MYSQL_SQL_SCRIPT_SYNC_H_
