#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"
#include "grtdb/diff_dbobjectmatch.h"

class SynchronizeDifferencesPageBEInterface
{
protected:
    boost::shared_ptr<DiffTreeBE> _diff_tree;
    StringRef _sync_profile_name;
public:
  SynchronizeDifferencesPageBEInterface(){};
  StringRef get_sync_profile_name(){return _sync_profile_name;};
  void set_sync_profile_name(StringRef sync_profile_name){_sync_profile_name = sync_profile_name;};
  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 db_mysql_CatalogRef get_model_catalog() = 0;
  virtual std::string get_col_name(const size_t col_id) = 0;
  virtual std::string get_sql_for_object(GrtNamedObjectRef obj) = 0;
  virtual boost::shared_ptr<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;
  grt::DictRef _db_options;



  // 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;

  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);
  virtual ~DbMySQLScriptSync();

  void start_sync();  

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

  boost::shared_ptr<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);

  void set_db_options(grt::DictRef db_options){_db_options = db_options;};
  grt::DictRef get_db_options()const{return _db_options.is_valid()?_db_options:grt::DictRef(_manager->get_grt());};


  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_
