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

#include <memory>
#include <utility>

#include <cmext/algorithm>

#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmProperty.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"

cmGlobalCommonGenerator::cmGlobalCommonGenerator(cmake* cm)
  : cmGlobalGenerator(cm)
{
}

cmGlobalCommonGenerator::~cmGlobalCommonGenerator() = default;

std::map<std::string, cmGlobalCommonGenerator::DirectoryTarget>
cmGlobalCommonGenerator::ComputeDirectoryTargets() const
{
  std::map<std::string, DirectoryTarget> dirTargets;
  for (const auto& lg : this->LocalGenerators) {
    std::string const& currentBinaryDir(
      lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
    DirectoryTarget& dirTarget = dirTargets[currentBinaryDir];
    dirTarget.LG = lg.get();
    const std::vector<std::string>& configs =
      lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);

    // The directory-level rule should depend on the target-level rules
    // for all targets in the directory.
    for (const auto& gt : lg->GetGeneratorTargets()) {
      cmStateEnums::TargetType const type = gt->GetType();
      if (type == cmStateEnums::GLOBAL_TARGET || !gt->IsInBuildSystem()) {
        continue;
      }
      DirectoryTarget::Target t;
      t.GT = gt.get();
      const std::string EXCLUDE_FROM_ALL("EXCLUDE_FROM_ALL");
      if (cmProp exclude = gt->GetProperty(EXCLUDE_FROM_ALL)) {
        for (const std::string& config : configs) {
          cmGeneratorExpressionInterpreter genexInterpreter(lg.get(), config,
                                                            gt.get());
          if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
            // This target has been explicitly excluded.
            t.ExcludedFromAllInConfigs.push_back(config);
          }
        }

        if (t.ExcludedFromAllInConfigs.empty()) {
          // This target has been explicitly un-excluded.  The directory-level
          // rule for every directory between this and the root should depend
          // on the target-level rule for this target.
          for (cmStateSnapshot dir =
                 lg->GetStateSnapshot().GetBuildsystemDirectoryParent();
               dir.IsValid(); dir = dir.GetBuildsystemDirectoryParent()) {
            std::string const& d = dir.GetDirectory().GetCurrentBinary();
            dirTargets[d].Targets.emplace_back(t);
          }
        }
      }
      dirTarget.Targets.emplace_back(t);
    }

    // The directory-level rule should depend on the directory-level
    // rules of the subdirectories.
    for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
      DirectoryTarget::Dir d;
      d.Path = state.GetDirectory().GetCurrentBinary();
      d.ExcludeFromAll =
        state.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL");
      dirTarget.Children.emplace_back(std::move(d));
    }
  }

  return dirTargets;
}

bool cmGlobalCommonGenerator::IsExcludedFromAllInConfig(
  const DirectoryTarget::Target& t, const std::string& config)
{
  if (this->IsMultiConfig()) {
    return cm::contains(t.ExcludedFromAllInConfigs, config);
  }
  return !t.ExcludedFromAllInConfigs.empty();
}

std::string cmGlobalCommonGenerator::GetEditCacheCommand() const
{
  // If generating for an extra IDE, the edit_cache target cannot
  // launch a terminal-interactive tool, so always use cmake-gui.
  if (!this->GetExtraGeneratorName().empty()) {
    return cmSystemTools::GetCMakeGUICommand();
  }

  // Use an internal cache entry to track the latest dialog used
  // to edit the cache, and use that for the edit_cache target.
  cmake* cm = this->GetCMakeInstance();
  std::string editCacheCommand = cm->GetCMakeEditCommand();
  if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") ||
      !editCacheCommand.empty()) {
    if (this->SupportsDirectConsole() && editCacheCommand.empty()) {
      editCacheCommand = cmSystemTools::GetCMakeCursesCommand();
    }
    if (editCacheCommand.empty()) {
      editCacheCommand = cmSystemTools::GetCMakeGUICommand();
    }
    if (!editCacheCommand.empty()) {
      cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
                        "Path to cache edit program executable.",
                        cmStateEnums::INTERNAL);
    }
  }
  cmProp edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
  return edit_cmd ? *edit_cmd : std::string();
}
