// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.

#include "seq_reconstructor.hpp"
#include "utils/cmd_args.hpp"
#include "utils/logger.hpp"

#include <iostream>
#include <memory>
namespace {
namespace xbr = xrt_core::tools::xbreplay;

/*
 * This function is used to parse the command line arguments
 */
static std::tuple<bool, std::string, std::string> parse_command_line_arguments(std::vector<std::string>& cmd_params)
{
  std::string trace_file;
  std::string mem_file;
  std::vector<std::string>& args = cmd_params;
  xbr::utils::cmd_args_opt opt;
  bool doexit = false;
  std::vector<xbr::utils::cmd_args_opt> options =
  {
    {'h', false, "", "To provide usage information"},
    {'t', true, "", "To provide path to the trace file as input"},
    {'d', true, "", "To provide path to the memory dump file"},
    {'l', true, "", "To set the log level (DEBUG=0, INFO=1, WARN=2, ERROR=3)"}
  };

  xbr::utils::cmd_args cargs(std::move(options));

  while (-1 != cargs.parse(args, opt, "t:d:l:h"))
  {
    switch (opt.type)
    {
      case 'h':
        cargs.print_usage();
        doexit = true;
        break;
      case 't':
        trace_file = opt.value;
        XBREPLAY_INFO("Trace file name:", trace_file);
        break;
      case 'd':
        mem_file = opt.value;
        XBREPLAY_INFO("Memory Dump  file name:", opt.value);
        break;
      case 'l':
        l.set_loglevel(opt.value);
        XBREPLAY_INFO("Received log level: ", opt.value);
        break;
      default:
        throw std::runtime_error("Unknown option or missing argument. ABORT !!");
        break;
    }
  }
  return std::make_tuple(doexit, trace_file, mem_file);
}

/*
 * This function is used to start the replay
 */
static void start_replay(const std::string& trace_file, const std::string& mem_file)
{
  xbr::seq_reconstructor_factory seq_factory = {};

  /* Spawns threads in following order
    * main
    *   -> Sequence Reconstructor thread
    *      -> Replay Master Thread.
    *         -> Replay Worker Thread.
    */
  if (auto pseq_recon = seq_factory.create_seq_recon(trace_file, mem_file))
     pseq_recon->threads_join();
  else
      throw std::runtime_error("Failed to create sequence reconstructor");
}
}
/*
 * Main Function
 * clang warning: do not declare C-style arrays in main
 */
// NOLINTNEXTLINE
int main(int argc, const char* argv[])
{
  std::vector<std::string> args(argv, argv + argc);
  try
  {
    /* doexit - Flag to indicate if the program should exit
     * trace_file & mem_file - Input Trace file path & memory dump file path
     * which is generated by xbtracer.
     */
    auto [doexit, trace_file, mem_file] = parse_command_line_arguments(args);

    /* The user has executed the 'xbreplay' command with the '-h' option.
     * The help message has been displayed on the screen. The program will now terminate.
     */
    if (doexit)
      return 0;

    start_replay(trace_file, mem_file);
  }
  catch (const std::exception& e)
  {
    XBREPLAY_ERROR(e.what());
  }
  catch (...)
  {
    XBREPLAY_ERROR("An unknown error occurred");
  }
  return 0;
}

