/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
file Copyright.txt or https://cmake.org/licensing for details.  */
#include "cmInstrumentationCommand.h"

#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <functional>
#include <set>

#include <cmext/string_view>

#include "cmArgumentParser.h"
#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
#include "cmExperimental.h"
#include "cmInstrumentation.h"
#include "cmInstrumentationQuery.h"
#include "cmMakefile.h"
#include "cmStringAlgorithms.h"

namespace {

bool isCharDigit(char ch)
{
  return std::isdigit(static_cast<unsigned char>(ch));
}
bool validateVersion(std::string const& key, std::string const& versionString,
                     int& version, cmExecutionStatus& status)
{
  if (!std::all_of(versionString.begin(), versionString.end(), isCharDigit)) {
    status.SetError(cmStrCat("given a non-integer ", key, "."));
    return false;
  }
  version = std::atoi(versionString.c_str());
  if (version != 1) {
    status.SetError(cmStrCat(
      "QUERY subcommand given an unsupported ", key, " \"", versionString,
      "\" (the only currently supported version is 1)."));
    return false;
  }
  return true;
}

template <typename E>
std::function<bool(std::string const&, E&)> EnumParser(
  std::vector<std::string> const toString)
{
  return [toString](std::string const& value, E& out) -> bool {
    for (size_t i = 0; i < toString.size(); ++i) {
      if (value == toString[i]) {
        out = (E)i;
        return true;
      }
    }
    return false;
  };
}
}

bool cmInstrumentationCommand(std::vector<std::string> const& args,
                              cmExecutionStatus& status)
{
  // if (status->GetMakefile().GetPropertyKeys) {
  if (!cmExperimental::HasSupportEnabled(
        status.GetMakefile(), cmExperimental::Feature::Instrumentation)) {
    status.SetError(
      "requires the experimental Instrumentation flag to be enabled");
    return false;
  }

  if (args.empty()) {
    status.SetError("must be called with arguments.");
    return false;
  }

  struct Arguments : public ArgumentParser::ParseResult
  {
    ArgumentParser::NonEmpty<std::string> ApiVersion;
    ArgumentParser::NonEmpty<std::string> DataVersion;
    ArgumentParser::NonEmpty<std::vector<std::string>> Queries;
    ArgumentParser::NonEmpty<std::vector<std::string>> Hooks;
    ArgumentParser::NonEmpty<std::vector<std::string>> Callback;
  };

  static auto const parser = cmArgumentParser<Arguments>{}
                               .Bind("API_VERSION"_s, &Arguments::ApiVersion)
                               .Bind("DATA_VERSION"_s, &Arguments::DataVersion)
                               .Bind("QUERIES"_s, &Arguments::Queries)
                               .Bind("HOOKS"_s, &Arguments::Hooks)
                               .Bind("CALLBACK"_s, &Arguments::Callback);

  std::vector<std::string> unparsedArguments;
  Arguments const arguments = parser.Parse(args, &unparsedArguments);

  if (arguments.MaybeReportError(status.GetMakefile())) {
    return true;
  }
  if (!unparsedArguments.empty()) {
    status.SetError("given unknown argument \"" + unparsedArguments.front() +
                    "\".");
    return false;
  }
  int apiVersion;
  int dataVersion;
  if (!validateVersion("API_VERSION", arguments.ApiVersion, apiVersion,
                       status) ||
      !validateVersion("DATA_VERSION", arguments.DataVersion, dataVersion,
                       status)) {
    return false;
  }

  std::set<cmInstrumentationQuery::Query> queries;
  auto queryParser = EnumParser<cmInstrumentationQuery::Query>(
    cmInstrumentationQuery::QueryString);
  for (auto const& arg : arguments.Queries) {
    cmInstrumentationQuery::Query query;
    if (!queryParser(arg, query)) {
      status.SetError(
        cmStrCat("given invalid argument to QUERIES \"", arg, "\""));
      return false;
    }
    queries.insert(query);
  }

  std::set<cmInstrumentationQuery::Hook> hooks;
  auto hookParser = EnumParser<cmInstrumentationQuery::Hook>(
    cmInstrumentationQuery::HookString);
  for (auto const& arg : arguments.Hooks) {
    cmInstrumentationQuery::Hook hook;
    if (!hookParser(arg, hook)) {
      status.SetError(
        cmStrCat("given invalid argument to HOOKS \"", arg, "\""));
      return false;
    }
    hooks.insert(hook);
  }

  std::string callback;
  for (auto const& arg : arguments.Callback) {
    callback = cmStrCat(callback, arg);
  }

  auto instrument = cmInstrumentation(
    status.GetMakefile().GetHomeOutputDirectory(), queries, hooks, callback);
  instrument.WriteJSONQuery();

  return true;
}
