/*---------------------------------------------------------------------------*/
/* websocketsql_server.h                                                     */
/* copyright (c) innovaphone 2023                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

static constexpr const char * WSQL_ERR_ID_PROTOCOL   = "WSQL_PROTOCOL_ERROR";
static constexpr const char * WSQL_ERR_ID_SQL        = "WSQL_SQL_ERROR";
static constexpr const char * WSQL_ERR_ID_SERVER     = "WSQL_SERVER_ERROR";

static constexpr const char * WSQL_ERR_FETCH_NO_DS   = "IDataSet::FetchNextRow() called, but not active dataset available";
static constexpr const char * WSQL_ERR_SQL           = "SQL execution error: '%s'";
static constexpr const char * WSQL_ERR_SQL_SERVER    = "SQL server error: '%s'";

enum class wsql_ps_data_type_t {
    PARAM_NONE,
    PARAM_BOOL,
    PARAM_INT32,
    PARAM_UINT32,
    PARAM_INT64,
    PARAM_UINT64,
    PARAM_DOUBLE,
    PARAM_STRING,
    PARAM_BINARY
};

inline const char * WSQLPsDataTypeToStr(wsql_ps_data_type_t dt)
{
    switch (dt) {
    case wsql_ps_data_type_t::PARAM_BOOL: return "PARAM_BOOL";
    case wsql_ps_data_type_t::PARAM_INT32: return "PARAM_INT32";
    case wsql_ps_data_type_t::PARAM_UINT32: return "PARAM_UINT32";
    case wsql_ps_data_type_t::PARAM_INT64: return "PARAM_INT64";
    case wsql_ps_data_type_t::PARAM_UINT64: return "PARAM_UINT64";
    case wsql_ps_data_type_t::PARAM_DOUBLE: return "PARAM_DOUBLE";
    case wsql_ps_data_type_t::PARAM_STRING: return "PARAM_STRING";
    case wsql_ps_data_type_t::PARAM_BINARY: return "PARAM_BINARY";
    case wsql_ps_data_type_t::PARAM_NONE: return "PARAM_NONE";
    }
    return "<unknown type>";
}

class UWebsocketSqlServer {
public:
    UWebsocketSqlServer() {}
    virtual ~UWebsocketSqlServer() {}

    virtual void WebsocketSqlServerConnect(class IWebsocketSqlServer * sender, const char * address, const char * dbname, const char * user, const char * pwd) = 0;
    virtual void WebsocketSqlServerPrepareStatement(class IWebsocketSqlServer * sender, const char * statementQuery) = 0;
    virtual void WebsocketSqlServerExecSQL(class IWebsocketSqlServer * sender, dword flags, class IWebsocketSqlServerPreparedStatement * stmt) = 0;
    virtual void WebsocketSqlServerExecSQL(class IWebsocketSqlServer * sender, dword flags, const char * query) = 0;
    virtual void WebsocketSqlServerExecSqlFetchNextRow(class IWebsocketSqlServer * sender) = 0;
    virtual void WebsocketSqlServerInsertSQL(class IWebsocketSqlServer * sender, class IWebsocketSqlServerPreparedStatement * stmt) = 0;
    virtual void WebsocketSqlServerInsertSQL(class IWebsocketSqlServer * sender, const char * query) = 0;
    virtual void WebsocketSqlServerBeginTransaction(class IWebsocketSqlServer * sender) = 0;
    virtual void WebsocketSqlServerEndTransaction(class IWebsocketSqlServer * sender) = 0;
    virtual void WebsocketSqlServerDatasetDeleted(class IWebsocketSqlServer * sender) = 0;
    virtual void WebsocketSqlServerShutdown(IWebsocketSqlServer * sender) = 0;
};

// Note: This is a wrapper which just acts as a proxy to pass data to the IWebsocketSqlServer::SendExecSQLResult() function. So it must
//       be guaranteed, that no memory will be relased until IWebsocketSqlServer::SendExecSQLResult() had been called.
class IWebsocketSqlServerResultSet {
public:
    static IWebsocketSqlServerResultSet * Create(size_t rowCount, uint32_t flags);

    virtual void AddColumn(column_data_type_t type, const char * name) = 0;
    virtual void InitRows() = 0;
    virtual void SetEOT() = 0;

    virtual void SetValue(size_t row, size_t col, bool value) = 0;
    virtual void SetValue(size_t row, size_t col, int value) = 0;
    virtual void SetValue(size_t row, size_t col, dword value) = 0;
    virtual void SetValue(size_t row, size_t col, long64 value) = 0;
    virtual void SetValue(size_t row, size_t col, ulong64 value) = 0;
    virtual void SetValue(size_t row, size_t col, double value) = 0;
    virtual void SetValue(size_t row, size_t col, const char * str) = 0;
    virtual void SetValue(size_t row, size_t col, const byte * data, size_t dataLen = 0) = 0;
};


class IWebsocketSqlServerPreparedStatement {
public:
    virtual const char * StatementID() = 0;
    virtual size_t ParamCount() = 0;
    virtual wsql_ps_data_type_t ParamDataType(size_t idx) = 0;

    virtual bool ParamAsBool(size_t idx) = 0;
    virtual int ParamAsInt32(size_t idx) = 0;
    virtual dword ParamAsUInt32(size_t idx) = 0;
    virtual long64 ParamAsInt64(size_t idx) = 0;
    virtual ulong64 ParamAsUInt64(size_t idx) = 0;
    virtual double ParamAsDouble(size_t idx) = 0;
    virtual const char * ParamAsString(size_t idx) = 0;
    virtual const byte * ParamAsArray(size_t idx) = 0;
    virtual size_t ParamArrayLength(size_t idx) = 0;
    virtual bool ParamIsNull(size_t idx) = 0;
};


class IWebsocketSqlMessage {
public:
    static const char * ApiName(byte * buffer, size_t len);
};

class IWebsocketSqlServer {
public:
    IWebsocketSqlServer() {}
    virtual ~IWebsocketSqlServer() {}

    virtual const char * ApiName() = 0;

    virtual bool HandleMessage(byte * buffer, size_t len) = 0;

    virtual void SendConnectComplete() = 0;
    virtual void SendShutdownComplete(db_error_t reason, const char * errID = nullptr, const char * errMsg = nullptr) = 0;
    virtual void SendError(db_error_t reason, const char * errID = nullptr, const char * errMsg = nullptr) = 0;
    virtual void SendPrepareStatementResult(const char * statementID) = 0;
    virtual void SendExecSQLResult(class IWebsocketSqlServerResultSet * resultSet) = 0;
    virtual void SendExecSQLComplete() = 0;
    virtual void SendInsertSQLResult(ulong64 id) = 0;
    virtual void SendBeginTransactionResult() = 0;
    virtual void SendEndTransactionResult() = 0;
    virtual void SendDatabaseError(const char * errMsg, const char * errCode, db_error_t error) = 0;
};

extern IWebsocketSqlServer * CreateWebsocketSQLServer(class IInstanceLog * log, UWebsocketSqlServer * user, class IAppWebsocketClient * client);
