/********************************************************************
 * gnc-backend-dbi.hpp: load and save data to SQL via libdbi     *
 *                                                                  *
 * This program is free software; you can redistribute it and/or    *
 * modify it under the terms of the GNU General Public License as   *
 * published by the Free Software Foundation; either version 2 of   *
 * the License, or (at your option) any later version.              *
 *                                                                  *
 * This program is distributed in the hope that it will be useful,  *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
 * GNU General Public License for more details.                     *
 *                                                                  *
 * You should have received a copy of the GNU General Public License*
 * along with this program; if not, contact:                        *
 *                                                                  *
 * Free Software Foundation           Voice:  +1-617-542-5942       *
 * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
 * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
\********************************************************************/

/* Private structures and variables for gnc-backend-dbi.c and its unit tests */
#ifndef GNC_BACKEND_DBI_HPP
#define GNC_BACKEND_DBI_HPP

#include <dbi/dbi.h>
#ifdef G_OS_WIN32
#include <winsock2.h>
#define GETPID() GetCurrentProcessId()
#else
#include <limits.h>
#include <unistd.h>
#define GETPID() getpid()
#endif

#include <gnc-sql-backend.hpp>
#include <gnc-sql-connection.hpp>

class GncSqlRow;

#define GNC_HOST_NAME_MAX 255

/**
 * Options to conn_table_operation
 * @var drop Drop (remove without recourse) the table from the database
 * @var empty Delete all of the records from the table
 * @var backup Rename the table "name" to "name_back"
 * @var rollback drop the name table if it exists and rename name_back to name
 * @var drop_backup Drop the backup table
 */
enum TableOpType
{
    backup = 0,
    rollback,
    drop_backup,
    recover
};

/**
 * Return values from conn_test_dbi_library
 * @var GNC_DBI_PASS Did not find the large numbers bug
 * @var GNC_DBI_FAIL_SETUP Could not completed the test
 * @var GNC_DBI_FAIL_TEST Found the large numbers bug
 */
typedef enum
{
    GNC_DBI_PASS = 0,
    GNC_DBI_FAIL_SETUP,
    GNC_DBI_FAIL_TEST
} GncDbiTestResult;

/**
 * Supported Dbi Backends.
 */
enum class DbType
{
    DBI_SQLITE, /**< Sqlite3 */
    DBI_MYSQL,  /**< MySQL and probably MariaDB */
    DBI_PGSQL   /**< Postgresql */
};

/**
 * Implementations of GncSqlBackend.
 */
struct UriStrings;

template <DbType Type>
class GncDbiBackend : public GncSqlBackend
{
public:
    GncDbiBackend(GncSqlConnection *conn, QofBook* book) :
        GncSqlBackend(conn, book), m_exists{false} {}
    ~GncDbiBackend();
    void session_begin(QofSession*, const char*, SessionOpenMode) override;
    void session_end() override;
    void load(QofBook*, QofBackendLoadType) override;
    void safe_sync(QofBook*) override;
    bool connected() const noexcept { return m_conn != nullptr; }
    /** FIXME: Just a pass-through to m_conn: */
    void set_dbi_error(QofBackendError error, unsigned int repeat,
                       bool retry) noexcept
    {
        m_conn->set_error(error, repeat, retry);
    }
    void retry_connection(const char* msg) const noexcept
    {
        m_conn->retry_connection(msg);
    }
    /*-----*/
    bool exists() { return m_exists; }
    void set_exists(bool exists) { m_exists = exists; }
private:
    dbi_conn conn_setup(PairVec& options, UriStrings& uri);
    bool conn_test_dbi_library(dbi_conn conn);
    bool set_standard_connection_options(dbi_conn conn, const UriStrings& uri);
    bool create_database(dbi_conn conn, const char* db);
    bool m_exists;         // Does the database exist?
};

/* locale-stack */
inline std::string
gnc_push_locale(const int category, const std::string locale)
{
    std::string retval(setlocale(category, nullptr));
    setlocale(category, locale.c_str());
    return retval;
}

inline void
gnc_pop_locale(const int category, std::string locale)
{
    setlocale(category, locale.c_str());
}

/* external access required for tests */
std::string adjust_sql_options_string(const std::string&);



#endif //GNC_BACKEND_DBI_HPP
