/*
 * 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 <signal.h>
#include <unistd.h>

#include <chrono>
#include <iostream>
#include <memory>
#include <thread>

#include "../sh4lt/logger/console.hpp"
#include "../sh4lt/writer.hpp"

using namespace sh4lt;

static bool debug = false;
static bool show_version = false;
static std::string label;
static std::string group = ShType::default_group();
static std::string description = std::string();
static std::string text = std::string();
static std::unique_ptr<Writer> writer{};

void leave(int sig) {
  writer.reset();
  exit(sig);
}

void usage(const char* prog_name) {
  std::cout << "usage: " << prog_name << " [OPTIONS] label [group]" << '\n';
  std::cout << R""""(
shlinew writes lines of text read from standard input.
shlinew data can be monitored using `shflow -f c <label>`.
 
EXAMPLE:
Repeat `Hello World` each second, 100 times into the "hello" Sh4lt:
for i in {1..100}; do echo Hello World; sleep 1; done | shlinew hello

Write system log into the `syslog` Sh4lt :
tail -f /var/log/syslog | shlinew syslog

OPTIONS:
  -d         print debug
  -u <descr> set Sh4lt description
  -t <text>  write "text", each line in a buffer, and exit
  -v         print Sh4lt version and exits
)"""" << '\n';
  exit(1);
}

auto parse_options(int argc, char* argv[]) -> bool {
  opterr = 0;
  int c = 0;
  while ((c = getopt(argc, argv, "dt:u:v")) != -1) switch (c) {
      case 'd':
        debug = true;
        break;
      case 't':
        text = std::string(optarg);
        break;
      case 'u':
        description = std::string(optarg);
        break;
      case 'v':
        show_version = true;
        break;
      case '?':
        break;
      default:
        return false;
    }

  if (show_version) {
    std::cout << SH4LT_VERSION_STRING << '\n';
    exit(0);
  }

  if (optind + 1 <= argc) {
    label = argv[optind];
    if (optind + 2 == argc) group = argv[optind + 1];
  }
  if (label.empty()) {
    return false;
  }
  return true;
}

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 logger = std::make_shared<logger::Console>();
  logger->set_debug(debug);
  auto shtype = ShType("text/x-raw", label, group, description);
  writer = std::make_unique<Writer>(shtype, 1, logger);
  std::this_thread::sleep_for(std::chrono::milliseconds(20));
  int64_t start_time = Time::system_clock_now();

  if (!text.empty()) {
    writer->copy_to_shm(
        text.data(), text.size() * sizeof(char), Time::system_clock_now() - start_time, -1);
    return 0;
  }
  // read lines
  std::string line;
  while (std::getline(std::cin, line)) {
    writer->copy_to_shm(
        line.data(), line.size() * sizeof(char), Time::system_clock_now() - start_time, -1);
  }

  while (!writer->wait_readers_for(100000)) {  // 0.1 msec
  }
  return 0;
}
