#ifndef ARGPARSE_H
#define ARGPARSE_H

#include <iostream>
#include <optional>
#include <string>
#include <vector>

#include "program/displaymode.h"
// Generated by make
#include "version.h"

class CommandLine {
public:
  struct Result {
    bool dump_ast = false;
    bool trace_parser = false;
    std::optional<std::string> file = {};
    std::optional<DispMode> mode = std::nullopt;
    bool all_warnings = false;
  };

  // Parse argv directly (the name of the program is still at argv[0]). If an
  // error if found (like a unknown option) std::nullopt is returned.
  std::optional<Result> parse(int argc, char **argv) {

    // If nothing is provided this is error.
    if (argc == 1) {
      help();
      return std::nullopt;
    }

    Result res;

    for (int i = argc - 1; i > 0; --i) {
      std::string arg(argv[i]);

      if (arg == "-h" || arg == "-help") {
        help();
      } else if (arg == "-v" || arg == "-version") {
        version();
      } else if (arg == "-rac") {
        res.mode = DispMode::rac;
      } else if (arg == "-acl2") {
        res.mode = DispMode::acl2;
      } else if (arg == "-pedantic") {
        res.all_warnings = true;
      } else if (arg == "-dump-ast") {
        res.dump_ast = true;
      } else if (arg == "-trace-parser") {
        res.trace_parser = true;
      } else {
        if (arg.size() >= 1 && arg[0] == '-') {
          std::cerr << "Unknown option `" << arg << "`\n";
          help();
          return std::nullopt;
        }
        if (res.file && arg != "") {
          std::cerr << "Duplicate file name\n";
          help();
          return std::nullopt;
        }
        res.file = { arg };
      }
    }

    if ((res.dump_ast || res.mode) && !res.file) {
      std::cerr << "Missing file name";
      help();
      return std::nullopt;
    }

    return res;
  }

  void help() {

    // clang-format off

    std::cout
      << "This is the RAC (Restricted Algorithmic C) parser which translates a\n"
         "RAC program into a list of S-Expressions.\n\n"
         "Usage:\n"
         "  parse FILE [options]\n\n"
         "Options:\n"
         "  -rac           convert to RAC pseudocode and write to file.pc\n"
         "  -acl2          write ACL2 translation to file.ast.lsp\n"
         "  -pedantic      enable all possible warnings/errors.\n"
         "  -version       display the version (the commit hash)\n"
         "  -dump-ast      display the intermediate AST in dot format\n"
         "  -trace-parser  enable bison tracing, used to debug the parser\n";

    // clang-format on
  }

  void version() {
    std::cout << "RAC (Restricted Algorithmic C) parser\n"
              << "Built from ACL2 commit: " << git_commit << '\n';
  }
};

#endif // ARGPARSE_H
