/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file LICENSE.rst or https://cmake.org/licensing for details.  */

#include "cmFastbuildUtilityTargetGenerator.h"

#include <set>
#include <string>
#include <utility>
#include <vector>

#include <cm/memory>

#include "cmFastbuildTargetGenerator.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalFastbuildGenerator.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmStringAlgorithms.h"
#include "cmTarget.h"
#include "cmTargetDepend.h"
#include "cmTargetTypes.h"

cmFastbuildUtilityTargetGenerator::cmFastbuildUtilityTargetGenerator(
  cmGeneratorTarget* gt, std::string configParam)
  : cmFastbuildTargetGenerator(gt, std::move(configParam))
{
}

void cmFastbuildUtilityTargetGenerator::Generate()
{
  if (!this->GetGeneratorTarget()->IsInBuildSystem()) {
    return;
  }
  std::string targetName = GeneratorTarget->GetName();

  if (this->GeneratorTarget->GetType() == cm::TargetType::GLOBAL_TARGET) {
    targetName = GetGlobalGenerator()->GetTargetName(GeneratorTarget);
  }

  FastbuildAliasNode fastbuildTarget;
  auto const addUtilDepToTarget = [&fastbuildTarget](std::string depName) {
    FastbuildTargetDep dep{ depName };
    dep.Type = FastbuildTargetDepType::UTIL;
    fastbuildTarget.PreBuildDependencies.emplace(std::move(dep));
  };

  fastbuildTarget.Name = targetName;
  fastbuildTarget.BaseName = targetName;

  LogMessage("<-------------->");
  LogMessage("Generate Utility target: " + targetName);
  LogMessage("Config: " + Config);
  for (auto const& dep : TargetDirectDependencies) {
    LogMessage("Dep: " + dep->GetName());
  }

  std::vector<std::string> nonImportedUtils;
  for (BT<std::pair<std::string, bool>> const& util :
       this->GeneratorTarget->GetUtilities()) {
    if (util.Value.first == targetName) {
      continue;
    }
    auto const& utilTargetName =
      this->ConvertToFastbuildPath(util.Value.first);
    LogMessage("Util: " + utilTargetName);
    auto* const target = this->Makefile->FindTargetToUse(utilTargetName);
    if (target && target->IsImported()) {
      LogMessage("Skipping imported util target: " + utilTargetName);
      continue;
    }
    // Since interface target don't appear in the generated build files,
    // transitively propagate their deps (if any).
    // Tested in "ExternalProjectSubdir" test.
    if (target && target->GetType() == cm::TargetType::INTERFACE_LIBRARY) {
      for (auto const& dep : target->GetUtilities()) {
        auto const& depName = this->ConvertToFastbuildPath(dep.Value.first);
        LogMessage("Transitively propagating iface dep: " + depName +
                   ", is cross: " + std::to_string(dep.Value.second));
        nonImportedUtils.emplace_back(depName);
        addUtilDepToTarget(this->ConvertToFastbuildPath(depName));
      }
    } else {
      nonImportedUtils.emplace_back(utilTargetName);
      addUtilDepToTarget(utilTargetName);
    }
  }
  if (this->GetGlobalGenerator()->IsExcluded(this->GetGeneratorTarget())) {
    LogMessage(cmStrCat("Excluding ", targetName, " from ALL"));
    fastbuildTarget.ExcludeFromAll = true;
  }
  auto preBuild = GenerateCommands(FastbuildBuildStep::PRE_BUILD);

  // Tested in "RunCMake.CPack*" tests.
  // Utility target "package" has packaging steps as "POST_BUILD".
  for (auto& exec : GenerateCommands(FastbuildBuildStep::POST_BUILD).Nodes) {
    addUtilDepToTarget(exec.Name);
    for (std::string const& util : nonImportedUtils) {
      LogMessage("Adding: util " + util);
      exec.PreBuildDependencies.emplace(util);
    }
    // So POST_BUILD is executed AFTER PRE_BUILD (tested in "CustomCommand"
    // test).
    for (auto const& pre : preBuild.Nodes) {
      LogMessage("Adding: " + pre.Name);
      exec.PreBuildDependencies.emplace(pre.Name);
    }
    this->GetGlobalGenerator()->AddTarget(std::move(exec));
  }

  for (auto& exec : preBuild.Nodes) {
    LogMessage("Adding exec " + exec.Name);
    addUtilDepToTarget(exec.Name);
    this->GetGlobalGenerator()->AddTarget(std::move(exec));
  }

  for (auto& exec : GenerateCommands(FastbuildBuildStep::REST).Nodes) {
    addUtilDepToTarget(exec.Name);
    for (auto const& dep : TargetDirectDependencies) {
      LogMessage("Direct dep " + dep->GetName() +
                 "-all propagating to CC: " + exec.Name);
      // All custom commands from within the target must be executed AFTER all
      // the target's deps.
      exec.PreBuildDependencies.emplace(dep->GetName());
    }
    this->GetGlobalGenerator()->AddTarget(std::move(exec));
  }
  // The target has to be in the build system, but has no custom commands
  // associated with it.
  if (fastbuildTarget.PreBuildDependencies.empty()) {
    std::vector<cmSourceFile*> sources;
    this->GetGeneratorTarget()->GetSourceFiles(sources, this->Config);
    if (sources.empty()) {
      FastbuildTargetDep dep{ FASTBUILD_NOOP_FILE_NAME };
      dep.Type = FastbuildTargetDepType::ORDER_ONLY;
      fastbuildTarget.PreBuildDependencies.emplace(std::move(dep));
    } else {
      for (cmSourceFile const* source : sources) {
        FastbuildTargetDep dep{
          this->GetGlobalGenerator()->ConvertToFastbuildPath(
            source->GetFullPath())
        };
        dep.Type = FastbuildTargetDepType::ARTIFACT;
        fastbuildTarget.PreBuildDependencies.emplace(std::move(dep));
      }
    }
  }

  fastbuildTarget.Hidden = false;
  this->AdditionalCleanFiles();

  fastbuildTarget.BasePath = this->GetMakefile()->GetCurrentSourceDirectory();
  if (this->GetGeneratorTarget()->GetType() != cm::TargetType::GLOBAL_TARGET) {
    this->GetGlobalGenerator()->AddIDEProject(fastbuildTarget, Config);
  }
  this->GetGlobalGenerator()->AddTarget(std::move(fastbuildTarget));
}
