/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * 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 Lesser General Public License for more details.
 */

#include "./monitor.hpp"

#include "../shtype/shtype.hpp"

namespace sh4lt::monitor {

void Monitor::update_with_new_sh4lt(const std::vector<fs::path>& paths) {
  // prepare the ".created" subtree
  auto created = InfoTree::make();
  info_->graft("created", created);
  info_->tag_as_array("created", true);
  // update the tree
  for (auto& it : paths) {
    // check if the path is not already followed
    const auto found = std::find_if(
        begin(follower_stats_), end(follower_stats_), [&](const std::unique_ptr<FollowerStat>& f) {
          return f->shtype().path() == it;
        });
    if (end(follower_stats_) == found) {
      // create the follower
      follower_stats_.push_back(std::make_unique<FollowerStat>(log_, it));
    }
  }
}

const InfoTree* Monitor::get_data_printer_configuration(const fs::path& path) {
  auto found = std::find_if(
      follower_stats_.begin(), follower_stats_.end(), [&](const std::unique_ptr<FollowerStat>& fs) {
        return fs->path() == path;
      });
  if (follower_stats_.end() == found) return nullptr;
  return (*found)->data_printer_configuration_ptr();
}

bool Monitor::set_data_printer_configuration(const fs::path& path,
                                             std::string value_format,
                                             std::string separator,
                                             size_t precision,
                                             size_t min_width) {
  auto found = std::find_if(
      follower_stats_.begin(), follower_stats_.end(), [&](const std::unique_ptr<FollowerStat>& fs) {
        return fs->path() == path;
      });
  if (follower_stats_.end() == found) return false;
  return (*found)->set_data_printer_configuration(
      std::move(value_format), std::move(separator), precision, min_width);
}

bool Monitor::set_num_value_to_print(const fs::path& path, size_t num_val) {
  auto found = std::find_if(
      follower_stats_.begin(), follower_stats_.end(), [&](const std::unique_ptr<FollowerStat>& fs) {
        return fs->path() == path;
      });
  if (follower_stats_.end() == found) return false;
  (*found)->set_num_value_to_print(num_val);
  return true;
}

Monitor::Monitor(logger::Logger::ptr log, fs::path path)
    : log_(std::move(log)), dir_watcher_(std::move(path)), info_(InfoTree::make()) {
  // start Followers for currently active Sh4lts
  dir_watcher_.update();
  update_with_new_sh4lt(dir_watcher_.get_currents());
}

Monitor::Monitor(logger::Logger::ptr log) : Monitor(std::move(log), ShType::get_socket_dir()) {}

auto Monitor::update() -> void {
  dir_watcher_.update();
  update_with_new_sh4lt(dir_watcher_.get_created());
}

auto Monitor::get_stats() -> const InfoTree* {
  for (const auto& fstat : follower_stats_) {
    if (!fstat->has_shtype()) continue;
    auto id = std::to_string(fstat->id());
    info_->vgraft("created." + id, id);
    // save id/group/label/path
    auto idskey = "ids." + id;
    info_->vgraft(idskey + ".group", fstat->group());
    info_->vgraft(idskey + ".label", fstat->label());
    info_->vgraft(idskey + ".path", fstat->path().string());
    // save informations
    auto infokey = "infos." + id;
    info_->graft(infokey, fstat->stats());
  }
  return info_.get();
}

}  // namespace sh4lt::monitor
