/*
 * 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>

#include <csignal>
// #include <cstdio>
#include <iostream>

#include "../sh4lt/c/clogger.h"
#include "../sh4lt/c/cshtype.h"
#include "../sh4lt/c/cwriter.h"

static bool debug = false;
static bool verbose = false;
static bool properly_quit = false;
static int num_writes = 0;
static bool num_writes_enabled = false;
static char* label = nullptr;
static char* group = sh4lt_shtype_default_group();
static char* description = nullptr;
static Sh4ltLogger logger = nullptr;
static Sh4ltWriter writer = nullptr;
static Sh4ltShType shtype = nullptr;

// a struct with contiguous data storage
using frame_t = struct Frame {
  size_t count = 0;
};

void usage(const char* prog_name) {
  std::cout << "create a sh4lt writer, write to it, and do not clean when dying\n"
               "usage: "
            << prog_name
            << " [-d] [-v] [-q] [-n num_writes] label [group] [description]\n"
               "  -d enable debug\n"
               "  -v enable verbose\n"
               "  -q enable quitting properly\n"
               "  -n num enable quitting after num write(s)"
            << '\n';
  exit(1);
}

void leave(int sig) {
  if (properly_quit) {
    sh4lt_delete_writer(writer);
    sh4lt_delete_shtype(shtype);
    sh4lt_delete_logger(logger);
  }
  exit(sig);
}

void mylog(void* /*user_data*/, const char* str) {
  if (debug) std::cout << str << '\n';
}

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

  opterr = 0;
  int c = 0;
  while ((c = getopt(argc, argv, "dvqn:")) != -1) switch (c) {
      case 'd':
        debug = true;
        break;
      case 'v':
        verbose = true;
        break;
      case 'q':
        properly_quit = true;
        break;
      case 'n':
        num_writes = atoi(optarg);
        num_writes_enabled = true;
        break;
      case '?':
        break;
      default:
        usage(argv[0]);
    }

  if (optind + 2 > argc) usage(argv[0]);

  if (optind + 1 <= argc) {
    label = argv[optind];
  }
  if (optind + 2 <= argc) {
    free(group);
    group = argv[optind + 1];
  }
  if (optind + 3 <= argc) {
    group = argv[optind + 2];
  }

  logger = sh4lt_make_logger(&mylog, &mylog, &mylog, &mylog, &mylog, &mylog, nullptr);
  shtype = sh4lt_make_shtype("application/x-sh4lt-crash", label, group);
  sh4lt_shtype_set_description(shtype, description);
  writer = sh4lt_make_writer(shtype, sizeof(frame_t), nullptr, nullptr, nullptr, logger, 0600);
  if (!writer) {
    std::cout << "writer failed: quit without trying to write" << '\n';
    return 1;
  }

  frame_t frame;
  frame.count = 0;
  bool quit = false;
  while (!quit) {
    ++frame.count;
    if (num_writes_enabled && num_writes <= 0) {
      quit = true;
      continue;
    }
    usleep(50000);
    if (verbose) std::cout << "w-" << '\n';
    sh4lt_copy_to_shm(writer, &frame, sizeof(frame_t), -1, -1, 1.0);
    if (verbose) std::cout << "done" << '\n';
    if (num_writes_enabled) num_writes--;
  }  // end while
  if (properly_quit) {
    sh4lt_delete_writer(writer);
    sh4lt_delete_shtype(shtype);
    sh4lt_delete_logger(logger);
  }
  return 0;
}

