text: #include <database/database.hpp>
  #include <config/config.hpp>
  #include <logging/logging.hpp>
  #include <botan/hex.h>
  #include <tuple>
  
  using namespace std::string_literals;
  
  Database::Database():
    rng(),
    db(Config::get("db_type", "postgresql"),
       Config::get("db_login", ""))
  {
    this->db.verbose = true;
    if (this->db.needsUpgrade())
      {
        log_debug("The database scheme changed, updating it...");
        this->db.upgrade();
        log_debug("Done.");
      }
  }
  
  boost::optional<db::User> Database::get_user_by_login(const std::string& login)
  {
    boost::optional<db::User> user;
  
    auto users = litesql::select<db::User>(this->db, db::User::Login == login).all();
    if (!users.empty())
      user = users[0];
  
    return user;
  }
  
  std::tuple<bool, std::string> Database::create_new_user(const std::string& login, const std::string& password)
  {
    auto nb = litesql::select<db::User>(this->db, db::User::Login == login).count();
    if (nb != 0)
      return std::make_tuple(false, "User with login "s + login + " already exists.");
  
    db::User user(this->db);
    user.login = login;
    set_user_password(user, password);
    user.update();
    user.update();
    return std::make_tuple(true, "");
  }
  
  void Database::change_user_password(db::User& user, const std::string& password)
  {
    set_user_password(user, password);
    user.update();
  }
  
  void Database::set_user_password(db::User& user, const std::string& password)
  {
    // A salt is generated by the bcrypt function and stored directly as part
    // of the resulting hash. We do not need to generate one ourself to store
    // it in the database.
    user.hash = Botan::generate_bcrypt(password, this->rng, 8);
  }
  
  std::tuple<bool, std::string> Database::check_user_password(const db::User& user, const std::string& password) const
  {
    std::string hash = user.hash;
  
    if (Botan::check_bcrypt(password, hash) == true)
      return std::make_tuple(true, "");
    return std::make_tuple(false, "Password mismatch.");
  }
  
  db::Game Database::create_new_game() const
  {
    db::Game game(this->db);
    game.update();
    return game;
  }
  