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

#include <string>
#include <utility>

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

#include "cmConditionEvaluator.h"
#include "cmExecutionStatus.h"
#include "cmExpandedCommandArgument.h"
#include "cmFunctionBlocker.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"

static std::string cmIfCommandError(
  std::vector<cmExpandedCommandArgument> const& args)
{
  std::string err = "given arguments:\n ";
  for (cmExpandedCommandArgument const& i : args) {
    err += " ";
    err += cmOutputConverter::EscapeForCMake(i.GetValue());
  }
  err += "\n";
  return err;
}

class cmIfFunctionBlocker : public cmFunctionBlocker
{
public:
  cm::string_view StartCommandName() const override { return "if"_s; }
  cm::string_view EndCommandName() const override { return "endif"_s; }

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

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

  std::vector<cmListFileArgument> Args;
  bool IsBlocking;
  bool HasRun = false;
  bool ElseSeen = false;
};

bool cmIfFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
                                         cmMakefile&) const
{
  return lff.Arguments().empty() || lff.Arguments() == this->Args;
}

bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
                                 cmExecutionStatus& inStatus)
{
  cmMakefile& mf = inStatus.GetMakefile();
  // execute the functions for the true parts of the if statement
  int scopeDepth = 0;
  for (cmListFileFunction const& func : functions) {
    // keep track of scope depth
    if (func.LowerCaseName() == "if") {
      scopeDepth++;
    }
    if (func.LowerCaseName() == "endif") {
      scopeDepth--;
    }
    // watch for our state change
    if (scopeDepth == 0 && func.LowerCaseName() == "else") {

      if (this->ElseSeen) {
        cmListFileBacktrace elseBT = mf.GetBacktrace().Push(cmListFileContext{
          func.OriginalName(), this->GetStartingContext().FilePath,
          func.Line() });
        mf.GetCMakeInstance()->IssueMessage(
          MessageType::FATAL_ERROR,
          "A duplicate ELSE command was found inside an IF block.", elseBT);
        cmSystemTools::SetFatalErrorOccured();
        return true;
      }

      this->IsBlocking = this->HasRun;
      this->HasRun = true;
      this->ElseSeen = true;

      // if trace is enabled, print a (trivially) evaluated "else"
      // statement
      if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) {
        mf.PrintCommandTrace(func);
      }
    } else if (scopeDepth == 0 && func.LowerCaseName() == "elseif") {
      cmListFileBacktrace elseifBT = mf.GetBacktrace().Push(
        cmListFileContext{ func.OriginalName(),
                           this->GetStartingContext().FilePath, func.Line() });
      if (this->ElseSeen) {
        mf.GetCMakeInstance()->IssueMessage(
          MessageType::FATAL_ERROR,
          "An ELSEIF command was found after an ELSE command.", elseifBT);
        cmSystemTools::SetFatalErrorOccured();
        return true;
      }

      if (this->HasRun) {
        this->IsBlocking = true;
      } else {
        // if trace is enabled, print the evaluated "elseif" statement
        if (mf.GetCMakeInstance()->GetTrace()) {
          mf.PrintCommandTrace(func);
        }

        std::string errorString;

        std::vector<cmExpandedCommandArgument> expandedArguments;
        mf.ExpandArguments(func.Arguments(), expandedArguments);

        MessageType messType;

        cmConditionEvaluator conditionEvaluator(mf, elseifBT);

        bool isTrue =
          conditionEvaluator.IsTrue(expandedArguments, errorString, messType);

        if (!errorString.empty()) {
          std::string err =
            cmStrCat(cmIfCommandError(expandedArguments), errorString);
          mf.GetCMakeInstance()->IssueMessage(messType, err, elseifBT);
          if (messType == MessageType::FATAL_ERROR) {
            cmSystemTools::SetFatalErrorOccured();
            return true;
          }
        }

        if (isTrue) {
          this->IsBlocking = false;
          this->HasRun = true;
        }
      }
    }

    // should we execute?
    else if (!this->IsBlocking) {
      cmExecutionStatus status(mf);
      mf.ExecuteCommand(func, status);
      if (status.GetReturnInvoked()) {
        inStatus.SetReturnInvoked();
        return true;
      }
      if (status.GetBreakInvoked()) {
        inStatus.SetBreakInvoked();
        return true;
      }
      if (status.GetContinueInvoked()) {
        inStatus.SetContinueInvoked();
        return true;
      }
    }
  }
  return true;
}

//=========================================================================
bool cmIfCommand(std::vector<cmListFileArgument> const& args,
                 cmExecutionStatus& inStatus)
{
  cmMakefile& makefile = inStatus.GetMakefile();
  std::string errorString;

  std::vector<cmExpandedCommandArgument> expandedArguments;
  makefile.ExpandArguments(args, expandedArguments);

  MessageType status;

  cmConditionEvaluator conditionEvaluator(makefile, makefile.GetBacktrace());

  bool isTrue =
    conditionEvaluator.IsTrue(expandedArguments, errorString, status);

  if (!errorString.empty()) {
    std::string err =
      cmStrCat("if ", cmIfCommandError(expandedArguments), errorString);
    if (status == MessageType::FATAL_ERROR) {
      makefile.IssueMessage(MessageType::FATAL_ERROR, err);
      cmSystemTools::SetFatalErrorOccured();
      return true;
    }
    makefile.IssueMessage(status, err);
  }

  {
    auto fb = cm::make_unique<cmIfFunctionBlocker>();
    // if is isn't true block the commands
    fb->IsBlocking = !isTrue;
    if (isTrue) {
      fb->HasRun = true;
    }
    fb->Args = args;
    makefile.AddFunctionBlocker(std::move(fb));
  }

  return true;
}
