/*
 * 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 <unistd.h>  // getopt

#include <chrono>
#include <csignal>

#include "../sh4lt/infotree/json-serializer.hpp"
#include "../sh4lt/logger/console.hpp"
#include "../sh4lt/monitor/monitor.hpp"
#include "../sh4lt/shtype/shtype.hpp"

using namespace sh4lt;

static bool print_debug = false;
static bool print_version = false;
static bool print_type = false;
static bool print_help = false;
static std::string dir = ShType::get_socket_dir();

void leave(int sig) { exit(sig); }

void usage(const char* prog_name) {
  printf("usage: %s [OPTIONS] label [group]\n", prog_name);
  printf(R""""(
shlist prints the list of Sh4lt writers. 
Each line provides "id" "media" "label" "group" for enabled Sh4lt writers.

OPTIONS:
  -t         print shtypes along labels and groups in JSON format
  -v         print shlist version and exit
  -d         enable debug
  -p dir     check writers in 'dir'
  -h         help
)"""");
  exit(1);
}

auto parse_options(int argc, char* argv[]) -> bool {
  opterr = 0;
  int c = 0;
  while ((c = getopt(argc, argv, "hitp:dv")) != -1) switch (c) {
      case 'h':
        print_help = true;
        break;
      case 't':
        print_type = true;
        break;
      case 'v':
        print_version = true;
        break;
      case 'd':
        print_debug = true;
        break;
      case 'p':
        dir = std::string(optarg);
        break;
      case '?':
        break;
      default:
        return false;
    }

  if (print_version) {
    std::printf("%s\n", SH4LT_VERSION_STRING);
    exit(1);
  }
  if (print_help) {
    usage("shlist");
  }
  return true;
}

void print_sh4lt_info(InfoTree::ptrc stats, const std::string& key) {
  auto label = Any::to_string(stats->branch_get_value("infos." + key + ".shtype.label"));
  if (std::string::npos != label.find(' ')) {
    label = "\"" + label + "\"";
  }
  auto group = Any::to_string(stats->branch_get_value("infos." + key + ".shtype.group"));
  if (std::string::npos != group.find(' ')) {
    group = "\"" + group + "\"";
  }
  std::cout << key << ' ' << stats->branch_get_value("infos." + key + ".shtype.media") << ' '
            << label << ' ' << group << '\n';
}

auto main(int argc, char* argv[]) -> int {
  (void)signal(SIGINT, leave);
  (void)signal(SIGABRT, leave);
  (void)signal(SIGQUIT, leave);
  (void)signal(SIGTERM, leave);

  if (!parse_options(argc, argv)) {
    usage(argv[0]);
    return 1;
  }

  auto log = std::make_shared<logger::Console>(print_debug);
  auto monitor = monitor::Monitor(log, dir);
  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  monitor.update();
  auto stats = monitor.get_stats();

  // print shtypes in JSON format
  if (print_type) {
    auto infos = InfoTree::make();

    for (const auto& key : stats->get_child_keys("infos")) {
      infos->graft(key, stats->branch_get_copy("infos." + key + ".shtype"));
    }
    std::cout << infotree::json::serialize(infos.get()) << '\n';
    return 0;
  }

  // list
  for (const auto& key : stats->get_child_keys("infos")) {
    print_sh4lt_info(stats, key);
  }

  return 0;
}
