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

#include <utility>

#include <cm/memory>
#include <cm/string_view>
#include <cmext/algorithm>

#include "cm_static_string_view.hxx"

#include "cmExecutionStatus.h"
#include "cmFunctionBlocker.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
#include "cmRange.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"

namespace {
std::string const ARGC = "ARGC";
std::string const ARGN = "ARGN";
std::string const ARGV = "ARGV";
std::string const CMAKE_CURRENT_FUNCTION = "CMAKE_CURRENT_FUNCTION";
std::string const CMAKE_CURRENT_FUNCTION_LIST_FILE =
  "CMAKE_CURRENT_FUNCTION_LIST_FILE";
std::string const CMAKE_CURRENT_FUNCTION_LIST_DIR =
  "CMAKE_CURRENT_FUNCTION_LIST_DIR";
std::string const CMAKE_CURRENT_FUNCTION_LIST_LINE =
  "CMAKE_CURRENT_FUNCTION_LIST_LINE";

// define the class for function commands
class cmFunctionHelperCommand
{
public:
  /**
   * This is called when the command is first encountered in
   * the CMakeLists.txt file.
   */
  bool operator()(std::vector<cmListFileArgument> const& args,
                  cmExecutionStatus& inStatus) const;

  std::vector<std::string> Args;
  std::vector<cmListFileFunction> Functions;
  cmPolicies::PolicyMap Policies;
  std::string FilePath;
  long Line;
};

bool cmFunctionHelperCommand::operator()(
  std::vector<cmListFileArgument> const& args,
  cmExecutionStatus& inStatus) const
{
  cmMakefile& makefile = inStatus.GetMakefile();

  // Expand the argument list to the function.
  std::vector<std::string> expandedArgs;
  makefile.ExpandArguments(args, expandedArgs);

  // make sure the number of arguments passed is at least the number
  // required by the signature
  if (expandedArgs.size() < this->Args.size() - 1) {
    auto const errorMsg = cmStrCat(
      "Function invoked with incorrect arguments for function named: ",
      this->Args.front());
    inStatus.SetError(errorMsg);
    return false;
  }

  cmMakefile::FunctionPushPop functionScope(&makefile, this->FilePath,
                                            this->Policies);

  // set the value of argc
  makefile.AddDefinition(ARGC, std::to_string(expandedArgs.size()));
  makefile.MarkVariableAsUsed(ARGC);

  // set the values for ARGV0 ARGV1 ...
  for (auto t = 0u; t < expandedArgs.size(); ++t) {
    auto const value = cmStrCat(ARGV, std::to_string(t));
    makefile.AddDefinition(value, expandedArgs[t]);
    makefile.MarkVariableAsUsed(value);
  }

  // define the formal arguments
  for (auto j = 1u; j < this->Args.size(); ++j) {
    makefile.AddDefinition(this->Args[j], expandedArgs[j - 1]);
  }

  // define ARGV and ARGN
  auto const argvDef = cmJoin(expandedArgs, ";");
  auto const eit = expandedArgs.begin() + (this->Args.size() - 1);
  auto const argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
  makefile.AddDefinition(ARGV, argvDef);
  makefile.MarkVariableAsUsed(ARGV);
  makefile.AddDefinition(ARGN, argnDef);
  makefile.MarkVariableAsUsed(ARGN);

  makefile.AddDefinition(CMAKE_CURRENT_FUNCTION, this->Args.front());
  makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION);
  makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_FILE, this->FilePath);
  makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_FILE);
  makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_DIR,
                         cmSystemTools::GetFilenamePath(this->FilePath));
  makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_DIR);
  makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_LINE,
                         std::to_string(this->Line));
  makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_LINE);

  // Invoke all the functions that were collected in the block.
  // for each function
  for (cmListFileFunction const& func : this->Functions) {
    cmExecutionStatus status(makefile);
    if (!makefile.ExecuteCommand(func, status) || status.GetNestedError()) {
      // The error message should have already included the call stack
      // so we do not need to report an error here.
      functionScope.Quiet();
      inStatus.SetNestedError();
      return false;
    }
    if (status.GetReturnInvoked()) {
      break;
    }
  }

  // pop scope on the makefile
  return true;
}

class cmFunctionFunctionBlocker : public cmFunctionBlocker
{
public:
  cm::string_view StartCommandName() const override { return "function"_s; }
  cm::string_view EndCommandName() const override { return "endfunction"_s; }

  bool ArgumentsMatch(cmListFileFunction const&,
                      cmMakefile& mf) const override;

  bool Replay(std::vector<cmListFileFunction> functions,
              cmExecutionStatus& status) override;

  std::vector<std::string> Args;
};

bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
                                               cmMakefile& mf) const
{
  std::vector<std::string> expandedArguments;
  mf.ExpandArguments(lff.Arguments, expandedArguments,
                     this->GetStartingContext().FilePath.c_str());
  return expandedArguments.empty() ||
    expandedArguments.front() == this->Args.front();
}

bool cmFunctionFunctionBlocker::Replay(
  std::vector<cmListFileFunction> functions, cmExecutionStatus& status)
{
  cmMakefile& mf = status.GetMakefile();
  // create a new command and add it to cmake
  cmFunctionHelperCommand f;
  f.Args = this->Args;
  f.Functions = std::move(functions);
  f.FilePath = this->GetStartingContext().FilePath;
  f.Line = this->GetStartingContext().Line;
  mf.RecordPolicies(f.Policies);
  mf.GetState()->AddScriptedCommand(this->Args.front(), std::move(f));
  return true;
}

} // anonymous namespace

bool cmFunctionCommand(std::vector<std::string> const& args,
                       cmExecutionStatus& status)
{
  if (args.empty()) {
    status.SetError("called with incorrect number of arguments");
    return false;
  }

  // create a function blocker
  auto fb = cm::make_unique<cmFunctionFunctionBlocker>();
  cm::append(fb->Args, args);
  status.GetMakefile().AddFunctionBlocker(std::move(fb));

  return true;
}
