/*---------------------------------------------------------------------------*/
/* tasks_postgresql.h                                                        */
/* copyright (c) innovaphone 2016                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

class PostgreSQLTableColumn {
public:
    PostgreSQLTableColumn(const char * name, const char * type);
    ~PostgreSQLTableColumn();
    char * name;
    char * type;
    bool exists;
};

class PostgreSQLTableConstraint {
public:
    PostgreSQLTableConstraint(const char * name, const char * value);
    ~PostgreSQLTableConstraint();
    char * name;
    char * value;
    bool exists;
};

class PostgreSQLTableIndex {
public:
    PostgreSQLTableIndex(const char * name, const char * value, bool unique, const char * usng);
    ~PostgreSQLTableIndex();
    char * name;
    char * value;
    bool unique;
    bool exists;
    char * usng;
};


class TaskPostgreSQLInitTable : public ITask, public UDatabase {
private:
    char * tableName;
    class IDatabase * database;
    dword constraintCount;
    dword indexCount;
    enum { Idle, CreateTable, GetColumns, AddMissingColumns, GetConstraints, AddMissingConstraints, GetIndexes, AddMissingIndexes, Finished } state;
    std::deque<class PostgreSQLTableColumn *> columns;
    std::deque<class PostgreSQLTableConstraint *> constraints;
    std::deque<class PostgreSQLTableIndex *> indexes;

    void DatabaseExecSQLResult(IDatabase * const database, class IDataSet * dataset) override;
    void DatabaseError(IDatabase * const database, db_error_t error) override;

    void GetConstraintsQuery();
    void GetIndexesQuery();

public:
    TaskPostgreSQLInitTable(class IDatabase * database, const char * tableName);
    virtual ~TaskPostgreSQLInitTable();
    void SetDatabase(IDatabase * database) { this->database = database; };

    void AddColumn(const char * name, const char * type);
    void AddConstraint(const char * name, const char * value);
    void AddIndex(const char * name, const char * value, bool unique, const char * usng = 0);

    void Start(class UTask * user) override;
};


class TaskPostgreSQLInitEnum : public ITask, public UDatabase {
private:
    char * enumName;
    int sqlCmdCnt;
    class IDatabase * database;
    enum { Idle, GetEnum, CreateEnumType, GetEnumValues, AddEnumItem, Finished } state;
    std::deque<char *> enumValues;

    void DatabaseError(IDatabase * const database, db_error_t error) override;
    void DatabaseExecSQLResult(IDatabase * const database, class IDataSet * dataset) override;

    void CreateEnum();
    void UpdateEnum(IDataSet * dataset);

public:
    TaskPostgreSQLInitEnum(IDatabase * const database, const char * enumName);
    virtual ~TaskPostgreSQLInitEnum();

    void AddValue(const char * name);
    void Start(class UTask * user) override;
};


class TaskPostgreSQLInitSequence : public ITask, public UDatabase {
private:
    char * seqName;
    class IDatabase * database;

    void DatabaseError(IDatabase * const database, db_error_t error) override;
    void DatabaseExecSQLResult(IDatabase * const database, class IDataSet * dataset) override;

public:
    TaskPostgreSQLInitSequence(IDatabase * const database, const char * sequenceName);
    virtual ~TaskPostgreSQLInitSequence();

    void Start(class UTask * user) override;
};


class TaskPostgreSQLInitTrigger : public ITask, public UDatabase {
private:
    class IDatabase * database;
    char * triggerName;
    char * tableName;
    char * statement;
    bool update;
    bool triggerExist;
    enum { CheckingTrigger, DeletingTrigger, CreatingTrigger } state;

    void DatabaseError(IDatabase * const database, db_error_t error) override;
    void DatabaseExecSQLResult(IDatabase * const database, class IDataSet * dataset) override;

    void CheckTrigger();
    void DeleteTrigger();
    void CreateTrigger();

public:
    TaskPostgreSQLInitTrigger(IDatabase * const database, const char * triggerName);
    virtual ~TaskPostgreSQLInitTrigger();

    void DefineTrigger(const char * condition, const char * table, const char * fncName, bool updateIfExists = false);
    void Start(class UTask * user) override;
};


class TaskPostgreSQLInitFunction : public ITask, public UDatabase {
private:
    class IDatabase * database;
    char * fncName;
    char * fncBody;

    void DatabaseError(IDatabase * const database, db_error_t error) override;
    void DatabaseExecSQLResult(IDatabase * const database, class IDataSet * dataset) override;

public:
    TaskPostgreSQLInitFunction(class IDatabase * const database, const char * fncName);
    virtual ~TaskPostgreSQLInitFunction();

    void TriggerFunction(const char * fncBody);
    void Start(class UTask * user) override;
};
