#ifndef DATABASECONNECTIONPOOL_H
#define DATABASECONNECTIONPOOL_H

#include <memory>
#include <vector>
#include "common.h"

#include "SecureString.h"

#include <memory>
using SecureStringPtr = std::unique_ptr<SecureString>;

class DatabaseConnectionPool;
using DatabaseConnectionPoolPtr = std::shared_ptr<DatabaseConnectionPool>;

/// Management class for the database connection pool
class DatabaseConnectionPool : public Tango::LogAdapter
{
  public:
    DatabaseConnectionPool(Tango::DeviceImpl *dev);

    ~DatabaseConnectionPool() = default;

    DatabaseConnectionPool(const DatabaseConnectionPool &) = delete;
    DatabaseConnectionPool &operator=(const DatabaseConnectionPool &) = delete;
    DatabaseConnectionPool(DatabaseConnectionPool &&) = delete;
    DatabaseConnectionPool &operator=(DatabaseConnectionPool &&) = delete;

    /// Only user: DatabaseConnectionHandle
    /// @{
    MYSQL *GetDatabase(int con_nb);
    int get_connection();
    void release_connection(int con_nb);
    /// @}

    /// Set the connection pool size from main() before the DS is created
    static void set_conn_pool_size(int si);

  private:
    struct DbConnection : public Tango::LogAdapter
    {
        DbConnection(Tango::DeviceImpl *dev);
        ~DbConnection();

        DbConnection(const DbConnection &) = delete;
        DbConnection &operator=(const DbConnection &) = delete;
        DbConnection(DbConnection &&) = delete;
        DbConnection &operator=(DbConnection &&) = delete;

        void connect(const SecureStringPtr &mysql_user,
                     const SecureStringPtr &mysql_password,
                     const std::string &mysql_host,
                     int port,
                     const std::string &mysql_db_name);

        MYSQL *db{nullptr};
        omni_semaphore the_sema;
    };

    static int conn_pool_size;
    int m_last_sem_wait{0};
    std::vector<std::unique_ptr<DbConnection>> m_conn_pool;
    omni_mutex m_sem_wait_mutex;
    Tango::DeviceImpl *m_dev;
    SecureStringPtr m_mysql_user, m_mysql_password;
    std::string m_mysql_host, m_mysql_db_name{TANGO_DB_NAME};
    int m_mysql_port;

    void create_connection_pool();
    void parse_port_from_host(const std::string &mysql_host, int &port, std::string &host_without_port);
};

#endif // DATABASECONNECTIONPOOL_H
