/**
 * Copyright 2011-2012,2017, 2021 Centreon
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For more information : contact@centreon.com
 */

#include "com/centreon/broker/config/state.hh"
#include "broker/core/bbdo/internal.hh"
#include "common/log_v2/log_v2.hh"

using namespace com::centreon::broker::config;
using namespace com::centreon::exceptions;
using namespace com::centreon::broker;

using log_v2 = com::centreon::common::log_v2::log_v2;
using log_v2_config = com::centreon::common::log_v2::config;

/**
 *  Default constructor.
 */
state::state()
    : _broker_id{0},
      _rpc_port{0},
      _bbdo_version(BBDO_VERSION_MAJOR, BBDO_VERSION_MINOR, BBDO_VERSION_PATCH),
      _command_protocol{"json"},
      _event_queue_max_size{10000},
      _poller_id{0},
      _pool_size{0},
      _log_conf{"/var/log/centreon-broker/",
                log_v2_config::logger_type::LOGGER_FILE, 5u, false, false} {
  // FIXME DBO: Is it useful since the log_conf constructor parse the name to
  // create a path + filename.
  _log_conf.set_filename("");
  _log_conf.set_max_size(0);
}

/**
 *  Copy constructor.
 *
 *  @param[in] other  Object to copy.
 */
state::state(const state& other)
    : _broker_id(other._broker_id),
      _rpc_port(other._rpc_port),
      _listen_address{other._listen_address},
      _broker_name(other._broker_name),
      _cache_directory(other._cache_directory),
      _command_file(other._command_file),
      _command_protocol(other._command_protocol),
      _endpoints(other._endpoints),
      _event_queue_max_size(other._event_queue_max_size),
      _module_dir(other._module_dir),
      _module_list(other._module_list),
      _params(other._params),
      _poller_id(other._poller_id),
      _poller_name(other._poller_name),
      _pool_size(other._pool_size),
      _log_conf(other._log_conf) {}

/**
 *  Destructor.
 */
state::~state() {}

/**
 *  Assignment operator.
 *
 *  @param[in] other  Object to copy.
 *
 *  @return This object.
 */
state& state::operator=(state const& other) {
  if (this != &other) {
    _broker_id = other._broker_id;
    _rpc_port = other._rpc_port;
    _listen_address = other._listen_address;
    _broker_name = other._broker_name;
    _cache_directory = other._cache_directory;
    _command_file = other._command_file;
    _command_protocol = other._command_protocol;
    _endpoints = other._endpoints;
    _event_queue_max_size = other._event_queue_max_size;
    _module_dir = other._module_dir;
    _module_list = other._module_list;
    _params = other._params;
    _poller_id = other._poller_id;
    _poller_name = other._poller_name;
    _pool_size = other._pool_size;
  }
  return *this;
}

/**
 *  Reset state to default values.
 */
void state::clear() {
  _broker_id = 0;
  _rpc_port = 0;
  _listen_address.resize(0);
  _broker_name.clear();
  _cache_directory.clear();
  _command_file.clear();
  _command_protocol = "json";
  _endpoints.clear();
  _event_queue_max_size = 10000;
  _module_dir.clear();
  _module_list.clear();
  _params.clear();
  _poller_id = 0;
  _poller_name.clear();
  _pool_size = 0;
}

/**
 *  Set the Broker ID.
 *
 *  @param[in] id  Broker ID.
 */
void state::broker_id(int id) noexcept {
  _broker_id = id;
}

/**
 *  Get the Broker ID.
 *
 *  @return Broker ID.
 */
int state::broker_id() const noexcept {
  return _broker_id;
}

/**
 *  Set the Broker name.
 *
 *  @param[in] name  Broker name.
 */
void state::broker_name(std::string const& name) {
  _broker_name = name;
}

/**
 *  Get the Broker name.
 *
 *  @return Broker name.
 */
std::string const& state::broker_name() const noexcept {
  return _broker_name;
}

/**
 *  Set the event queues total size. The limit size allowed for all the
 *  memory and queue files generated by broker. If 0, there is no limit
 *  specified.
 *
 *  @param[in] size  the size in bytes.
 */
void state::event_queues_total_size(size_t size) {
  _event_queues_total_size = size;
}

/**
 *  Get the event queues total size, ie the limit size allowed for all the
 *  memory and queue files generated by broker. If 0, no limit specified.
 *
 *  @return a size in bytes.
 */
size_t state::event_queues_total_size() const noexcept {
  return _event_queues_total_size;
}

/**
 *  Set the BBDO version.
 *
 *  @param[in] v  bbdo version given as a tuple of uint16.
 */
void state::set_bbdo_version(bbdo::bbdo_version v) {
  _bbdo_version = v;
}

/**
 *  Get BBDO version.
 *
 *  @return bbdo version as a tuple of uint16.
 */
bbdo::bbdo_version state::get_bbdo_version() const noexcept {
  return _bbdo_version;
}

/**
 *  Set the cache directory.
 *
 *  @param[in] dir  Cache directory.
 */
void state::cache_directory(std::string const& dir) {
  _cache_directory = dir;
  if (_cache_directory[_cache_directory.size() - 1] != '/')
    _cache_directory.append("/");
}

/**
 *  Get the cache directory.
 *
 *  @return Cache directory.
 */
std::string const& state::cache_directory() const noexcept {
  return _cache_directory;
}

/**
 *  Set the command file.
 *
 *  @param[in] file  The command file.
 */
void state::command_file(std::string const& file) {
  _command_file = file;
}

/**
 *  Get the command file.
 *
 *  @return  The command file.
 */
std::string const& state::command_file() const noexcept {
  return _command_file;
}

/**
 *  Set the command protocol.
 *
 *  @param[in] prot  The command protocol.
 */
void state::command_protocol(std::string const& prot) {
  _command_protocol = prot;
}

/**
 *  Get the command protocol.
 *
 *  @return  The command protocol.
 */
std::string const& state::command_protocol() const noexcept {
  return _command_protocol;
}

/**
 * @brief Add a new endpoint to the configuration.
 *
 * @param out The endpoint is moved to the configuration.
 */
void state::add_endpoint(endpoint&& out) noexcept {
  log_v2::instance()
      .get(log_v2::CORE)
      ->trace("endpoint {} added to state", out.name);
  _endpoints.emplace_back(std::move(out));
}

/**
 *  Get the list of endpoints.
 *
 *  @return Endpoint list.
 */
std::list<endpoint> const& state::endpoints() const noexcept {
  return _endpoints;
}

/**
 *  Set the maximum limit size of the event queue.
 *
 *  @param[in] val Size limit.
 */
void state::event_queue_max_size(int val) noexcept {
  _event_queue_max_size = val;
}

/**
 *  Get the maximum limit size of the event queue.
 *
 *  @return The size limit.
 */
int state::event_queue_max_size() const noexcept {
  return _event_queue_max_size;
}

/**
 *  Get the module directory.
 *
 *  @return Module directory.
 */
std::string const& state::module_directory() const noexcept {
  return _module_dir;
}

/**
 *  Set the module directory.
 *
 *  @param[in] dir Module directory.
 */
void state::module_directory(std::string const& dir) {
  _module_dir = dir;
}

/**
 *  Get the module list.
 *
 *  @return Modifiable module list.
 */
std::list<std::string>& state::module_list() noexcept {
  return _module_list;
}

/**
 * @brief Add the module to the module list if not already present.
 *
 * @param module the module name to add.
 */
void state::add_module(std::string module) {
  bool conflict{false};
  if (module == "20-unified_sql.so")
    conflict = std::find(_module_list.begin(), _module_list.end(),
                         "20-storage.so") != _module_list.end() ||
               std::find(_module_list.begin(), _module_list.end(),
                         "80-sql.so") != _module_list.end();
  else if (module == "80-sql.so" || module == "20-storage.so")
    conflict = std::find(_module_list.begin(), _module_list.end(),
                         "20-unified_sql.so") != _module_list.end();
  if (conflict)
    throw msg_fmt(
        "config parser: unified_sql output is incompatible with storage/sql "
        "outputs");

  auto found = std::find(_module_list.begin(), _module_list.end(), module);
  if (found == _module_list.end())
    _module_list.emplace_back(std::move(module));
}

/**
 *  Get the module list.
 *
 *  @return Const module list.
 */
std::list<std::string> const& state::module_list() const noexcept {
  return _module_list;
}

/**
 *  Get the additional parameters.
 *
 *  @return Additional parameters list.
 */
std::map<std::string, std::string>& state::params() noexcept {
  return _params;
}

/**
 *  Get the additional parameters.
 *
 *  @return Additional parameters list.
 */
const std::map<std::string, std::string>& state::params() const noexcept {
  return _params;
}

/**
 *  Set the poller ID.
 *
 *  @param[in] id  Poller ID.
 */
void state::poller_id(int id) noexcept {
  _poller_id = id;
}

/**
 *  Get the poller ID.
 *
 *  @return Poller ID.
 */
int state::poller_id() const noexcept {
  return _poller_id;
}

/**
 * @brief Set the pool thread size. This pool is used at the moment by the tcp
 * connector, but should be used by others very soon.
 *
 * @param size A non negative integer. If 0, the pool size will be computed
 * automatically with max(2, number of CPUs / 2).
 */
void state::pool_size(int size) noexcept {
  _pool_size = size;
}

/**
 * @brief Get the pool thread size. This pool is used at the moment by the TCP
 * connector, but should be used by others very soon.
 *
 * @return a int integer.
 */
int state::pool_size() const noexcept {
  return _pool_size;
}

/**
 *  Set the poller name.
 *
 *  @param[in] name  Poller name.
 */
void state::poller_name(std::string const& name) {
  _poller_name = name;
}

/**
 *  Get the poller name.
 *
 *  @return Poller name.
 */
std::string const& state::poller_name() const noexcept {
  return _poller_name;
}

void state::rpc_port(uint16_t port) noexcept {
  _rpc_port = port;
}
uint16_t state::rpc_port() const noexcept {
  return _rpc_port;
}

/**
 * @brief Force the interface address to listen from for the gRPC API.
 *
 * @param listen_address An address or a hostname ("127.0.0.1", "localhost",
 * ...)
 */
void state::listen_address(const std::string& listen_address) noexcept {
  _listen_address = listen_address;
}

/**
 * @brief Access to the configured listen address or an empty string if not
 * defined. The behavior of broker in the latter is to listen from localhost.
 *
 * @return The listen address for the gRPC API.
 */
const std::string& state::listen_address() const noexcept {
  return _listen_address;
}

log_v2_config& state::mut_log_conf() {
  return _log_conf;
}

const log_v2_config& state::log_conf() const {
  return _log_conf;
}

const state::stats_exporter_conf& state::get_stats_exporter() const {
  return _stats_exporter_conf;
}

state::stats_exporter_conf& state::mut_stats_exporter() {
  return _stats_exporter_conf;
}

/**
 * @brief Set the directory containing the Engine configuration.
 *
 * @param engine_config_dir The directory containing the Engine configuration.
 */
void state::set_engine_config_dir(const std::string& dir) {
  _engine_config_dir = dir;
}

/**
 * @brief Get the directory containing the Engine configuration.
 *
 * @return The directory containing the Engine configuration.
 */
const std::string& state::engine_config_dir() const noexcept {
  return _engine_config_dir;
}

/**
 * @brief Set the directory containing the cache configuration of the pollers.
 *
 * @param config_cache_dir The directory name
 */
void state::set_config_cache_dir(const std::string& config_cache_dir) {
  _config_cache_dir = config_cache_dir;
}

/**
 * @brief Get the directory containing the cache configuration of the pollers.
 *
 * @return The directory name
 */
const std::string& state::config_cache_dir() const noexcept {
  return _config_cache_dir;
}

/**
 * @brief Set the directory containing the pollers configurations.
 *
 * @param pollers_config_dir The directory name
 */
void state::set_pollers_config_dir(const std::string& pollers_config_dir) {
  _pollers_config_dir = pollers_config_dir;
}

/**
 * @brief Get the directory containing the pollers configurations.
 *
 * @return The directory name
 */
const std::string& state::pollers_config_dir() const noexcept {
  return _pollers_config_dir;
}
