//!
//!    \addtogroup Diff Diff SQL Generator Module
//!             Diff SQL Generator Module
//!
//!    @{
//!
#ifndef _MODULE_DB_MYSQL_H_
#define _MODULE_DB_MYSQL_H_

/**
 * @file module_db_mysql.h
 *
 * This file contains declarations for SQL script creation routiness
 *
 * The SQL script generation process consists of 2 steps:
 * <br/>1. generate SQL for individual objects
 * <br/>2. put the gereneated SQL together (e.g. into a string or  a file)
 *
 * The DbMySQLImpl class implements the second step.
 */

#include "db_mysql_public_interface.h"
#include "grtpp_module_cpp.h"
#include "interfaces/sqlgenerator.h"
#include "grtdb/db_object_helpers.h"
#include "grts/structs.db.mysql.h"
#include "module_db_mysql_shared_code.h"

using namespace bec;

#define DbMySQL_VERSION "1.0"

class DiffSQLGeneratorBE;

/**
 * class DiffSQLGeneratorBEActionInterface defines interface to call-backs that are used to generate
 * DLL SQL or plain text description of changes
 */
class MYSQLMODULEDBMYSQL_PUBLIC_FUNC DiffSQLGeneratorBEActionInterface
{
protected:
  bool use_short_names;
public:
  
  virtual ~DiffSQLGeneratorBEActionInterface();

  //use short or full table names
  virtual void set_short_names(const bool flag){use_short_names = flag;};
  // create table
  virtual void create_table_props_begin(db_mysql_TableRef) = 0;
  virtual void create_table_props_end(db_mysql_TableRef) = 0;
  
  virtual void create_table_columns_begin(db_mysql_TableRef) = 0;
  virtual void create_table_column(db_mysql_ColumnRef) = 0;
  virtual void create_table_columns_end(db_mysql_TableRef) = 0;

  virtual void create_table_indexes_begin(db_mysql_TableRef) = 0;
  virtual void create_table_index(db_mysql_IndexRef, bool gen_create_index) = 0;
  virtual void create_table_indexes_end(db_mysql_TableRef) = 0;

  virtual void create_table_fks_begin(db_mysql_TableRef) = 0;
  virtual void create_table_fk(db_mysql_ForeignKeyRef) = 0;
  virtual void create_table_fks_end(db_mysql_TableRef) = 0;

  virtual void create_table_engine(grt::StringRef) = 0;
  virtual void create_table_next_auto_inc(grt::StringRef) = 0;
  virtual void create_table_password(grt::StringRef) = 0;
  virtual void create_table_delay_key_write(grt::IntegerRef) = 0;
  virtual void create_table_charset(grt::StringRef) = 0;
  virtual void create_table_collate(grt::StringRef) = 0;
  virtual void alter_table_comment(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void create_table_merge_union(grt::StringRef) = 0;
  virtual void create_table_merge_insert(grt::StringRef) = 0;
  virtual void create_table_pack_keys(grt::StringRef) = 0;
  virtual void create_table_checksum(grt::IntegerRef) = 0;
  virtual void create_table_row_format(grt::StringRef) = 0;
  virtual void create_table_avg_row_length(grt::StringRef) = 0;
  virtual void create_table_min_rows(grt::StringRef) = 0;
  virtual void create_table_max_rows(grt::StringRef) = 0;
  virtual void create_table_comment(grt::StringRef) = 0;
  virtual void create_table_data_dir(grt::StringRef) = 0;
  virtual void create_table_index_dir(grt::StringRef) = 0;

  // drop table
  virtual void drop_table(db_mysql_TableRef) = 0;

  // alter table
  virtual void alter_table_props_begin(db_mysql_TableRef) = 0;
  virtual void alter_table_name(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_engine(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_next_auto_inc(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_password(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_delay_key_write(db_mysql_TableRef, grt::IntegerRef) = 0;
  virtual void alter_table_charset(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_collate(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_merge_union(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_merge_insert(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_pack_keys(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_checksum(db_mysql_TableRef, grt::IntegerRef) = 0;
  virtual void alter_table_row_format(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_avg_row_length(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_min_rows(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_max_rows(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_connection_string(db_mysql_TableRef, grt::StringRef) = 0;

  virtual void alter_table_generate_partitioning(db_mysql_TableRef table, 
                                                 const std::string& part_type,
                                                 const std::string& part_expr, 
                                                 int part_count,
                                                 const std::string& subpart_type, 
                                                 const std::string& subpart_expr,
                                                 grt::ListRef<db_mysql_PartitionDefinition> part_defs) = 0;
  virtual void alter_table_drop_partitioning(db_mysql_TableRef table) = 0;
  virtual void alter_table_add_partition(db_mysql_PartitionDefinitionRef part, bool is_range) = 0;
  virtual void alter_table_drop_partition(const std::string& part_name) = 0;
  virtual void alter_table_reorganize_partition(
                                            db_mysql_PartitionDefinitionRef old_part,
                                            db_mysql_PartitionDefinitionRef new_part,
                                            bool is_range) = 0;
  virtual void alter_table_partition_count(db_mysql_TableRef, grt::IntegerRef) = 0;
  virtual void alter_table_partition_definitions(db_mysql_TableRef, grt::StringRef) = 0;
  virtual void alter_table_props_end(db_mysql_TableRef) = 0;

  virtual void alter_table_columns_begin(db_mysql_TableRef) = 0;
  virtual void alter_table_add_column(db_mysql_TableRef, std::map<std::string, std::string>, 
                                      db_mysql_ColumnRef column, db_mysql_ColumnRef after) = 0;
  virtual void alter_table_drop_column(db_mysql_TableRef, db_mysql_ColumnRef) = 0;
  virtual void alter_table_change_column(db_mysql_TableRef table, db_mysql_ColumnRef org_col, 
                                         db_mysql_ColumnRef mod_col, db_mysql_ColumnRef after,
                                         bool modified, 
                                         std::map<std::string, std::string> column_rename_map) = 0;
  virtual void alter_table_columns_end(db_mysql_TableRef) = 0;

  virtual void alter_table_indexes_begin(db_mysql_TableRef) = 0;
  virtual void alter_table_add_index(db_mysql_IndexRef) = 0;
  virtual void alter_table_drop_index(db_mysql_IndexRef) = 0;
  virtual void alter_table_indexes_end(db_mysql_TableRef) = 0;

  virtual void alter_table_fks_begin(db_mysql_TableRef) = 0;
  virtual void alter_table_add_fk(db_mysql_ForeignKeyRef) = 0;
  virtual void alter_table_drop_fk(db_mysql_ForeignKeyRef) = 0;
  virtual void alter_table_fks_end(db_mysql_TableRef) = 0;

  // triggers create/drop
  virtual void create_trigger(db_mysql_TriggerRef, bool for_alter) = 0;
  virtual void drop_trigger(db_mysql_TriggerRef, bool for_alter) = 0;

  // views create/drop
  virtual void create_view(db_mysql_ViewRef) = 0;
  virtual void drop_view(db_mysql_ViewRef) = 0;

  // routines create/drop
  virtual void create_routine(db_mysql_RoutineRef, bool for_alter) = 0;
  virtual void drop_routine(db_mysql_RoutineRef, bool for_alter) = 0;

  // users create/drop
  virtual void create_user(db_UserRef) = 0;
  virtual void drop_user(db_UserRef) = 0;

  // schema create/drop
  virtual void create_schema(db_mysql_SchemaRef) = 0;
  virtual void drop_schema(db_mysql_SchemaRef) = 0;

  // alter schema
  virtual void alter_schema_props_begin(db_mysql_SchemaRef) = 0;
  virtual void alter_schema_name(db_mysql_SchemaRef, grt::StringRef value) = 0;
  virtual void alter_schema_default_charset(db_mysql_SchemaRef, grt::StringRef value) = 0;
  virtual void alter_schema_default_collate(db_mysql_SchemaRef, grt::StringRef value) = 0;
  virtual void alter_schema_props_end(db_mysql_SchemaRef) = 0;
};


/**
 * class DbMySQLImpl is the main class responsible for SQL export/sync functionality. DbMySQLImpl runs
 * DiffSQLGeneratorBE to generate SQL for individual objects and then gathers it into a script.
 */
class MYSQLMODULEDBMYSQL_PUBLIC_FUNC DbMySQLImpl
  : public SQLGeneratorInterfaceImpl,
    public grt::ModuleImplBase
{
public:

  DbMySQLImpl(grt::CPPModuleLoader *ldr) : grt::ModuleImplBase(ldr) {}

  DEFINE_INIT_MODULE(DbMySQL_VERSION, "MySQL AB", grt::ModuleImplBase,
                  DECLARE_MODULE_FUNCTION(DbMySQLImpl::getTargetDBMSName),
                  DECLARE_MODULE_FUNCTION(DbMySQLImpl::generateSQL),
                  DECLARE_MODULE_FUNCTION(DbMySQLImpl::generateReport),
                  DECLARE_MODULE_FUNCTION(DbMySQLImpl::makeSQLExportScript),
                  DECLARE_MODULE_FUNCTION(DbMySQLImpl::makeSQLSyncScript),
                  DECLARE_MODULE_FUNCTION(DbMySQLImpl::makeCreateScriptForObject),
                  DECLARE_MODULE_FUNCTION(DbMySQLImpl::getKnownEngines));

  virtual std::string getTargetDBMSName()
  {
    return "mysql";
  }
  
  /**
   * generate sql (create or alter)
   */
  virtual int generateSQL(GrtNamedObjectRef, const grt::DictRef& options, const std::string &);

  /**
   * generate report (create or alter)
   */
  virtual grt::StringRef generateReport(GrtNamedObjectRef org_object,   
                                          const grt::DictRef& options, 
                                          const std::string &address1);

  /** 
   * generate SQL export script (CREATE statements only)
   */
  virtual int makeSQLExportScript(GrtNamedObjectRef, 
                                  const grt::DictRef& options, 
                                  const grt::DictRef& createSQL, 
                                  const grt::DictRef& dropSQL);
  
  /**
   * generate CREATE SQL script fro an individual object
   */
  virtual std::string makeCreateScriptForObject(GrtNamedObjectRef object);

  /** 
   * generate SQL alter script
   */
  virtual int makeSQLSyncScript(const grt::DictRef& options, 
                                const grt::StringListRef& sql_list, 
                                const grt::ListRef<GrtNamedObject>& param2);

  virtual grt::ListRef<db_mysql_StorageEngine> getKnownEngines();
};

#endif // _MODULE_DB_MYSQL_H_
//!
//!     @}
//!
