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

#include <map>
#include <memory>
#include <utility>
#include <vector>

#include <cm/optional>

#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmObjectLocation.h"
#include "cmOutputConverter.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmValue.h"

cmLocalCommonGenerator::cmLocalCommonGenerator(cmGlobalGenerator* gg,
                                               cmMakefile* mf)
  : cmLocalGenerator(gg, mf)
{
  // Multi-config generators define one set of configurations at the top.
  // Single-config generators nominally define one configuration at the top,
  // but the implementation has never been strict about that, so look up the
  // per-directory config to preserve behavior.
  this->ConfigNames = (gg->IsMultiConfig() && !gg->GetMakefiles().empty()
                         ? gg->GetMakefiles().front().get()
                         : this->Makefile)
                        ->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
}

cmLocalCommonGenerator::~cmLocalCommonGenerator() = default;

std::string const& cmLocalCommonGenerator::GetWorkingDirectory() const
{
  return this->StateSnapshot.GetDirectory().GetCurrentBinary();
}

std::string cmLocalCommonGenerator::GetTargetFortranFlags(
  cmGeneratorTarget const* target, std::string const& config)
{
  std::string flags;

  // Enable module output if necessary.
  this->AppendFlags(
    flags, this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODOUT_FLAG"));

  // Add a module output directory flag if necessary.
  std::string mod_dir =
    target->GetFortranModuleDirectory(this->GetWorkingDirectory());
  if (!mod_dir.empty()) {
    mod_dir = this->ConvertToOutputFormat(
      this->MaybeRelativeToWorkDir(mod_dir), cmOutputConverter::SHELL);
  } else {
    mod_dir =
      this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_DEFAULT");
  }
  if (!mod_dir.empty()) {
    std::string modflag = cmStrCat(
      this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG"),
      mod_dir);
    this->AppendFlags(flags, modflag);
    // Some compilers do not search their own module output directory
    // for using other modules.  Add an include directory explicitly
    // for consistency with compilers that do search it.
    std::string incflag =
      this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_INCLUDE_FLAG");
    if (!incflag.empty()) {
      incflag = cmStrCat(incflag, mod_dir);
      this->AppendFlags(flags, incflag);
    }
  }

  // If there is a separate module path flag then duplicate the
  // include path with it.  This compiler does not search the include
  // path for modules.
  if (cmValue modpath_flag =
        this->Makefile->GetDefinition("CMAKE_Fortran_MODPATH_FLAG")) {
    std::vector<std::string> includes;
    this->GetIncludeDirectories(includes, target, "C", config);
    for (std::string const& id : includes) {
      std::string flg =
        cmStrCat(*modpath_flag,
                 this->ConvertToOutputFormat(id, cmOutputConverter::SHELL));
      this->AppendFlags(flags, flg);
    }
  }

  return flags;
}

std::string cmLocalCommonGenerator::ComputeLongTargetDirectory(
  cmGeneratorTarget const* target) const
{
  std::string dir = target->GetName();
#if defined(__VMS)
  dir += "_dir";
#else
  dir += ".dir";
#endif
  return dir;
}

std::string cmLocalCommonGenerator::GetTargetDirectory(
  cmGeneratorTarget const* target,
  cmStateEnums::IntermediateDirKind kind) const
{
  if (target->GetUseShortObjectNames(kind)) {
    return this->ComputeShortTargetDirectory(target);
  }
  return this->ComputeLongTargetDirectory(target);
}

void cmLocalCommonGenerator::ComputeObjectFilenames(
  std::map<cmSourceFile const*, cmObjectLocations>& mapping,
  std::string const& config, cmGeneratorTarget const* gt)
{
  // Determine if these object files should use a custom extension
  char const* custom_ext = gt->GetCustomObjectExtension();
  for (auto& si : mapping) {
    cmSourceFile const* sf = si.first;
    bool keptSourceExtension;
    bool force = true;
    si.second.ShortLoc.emplace(this->GetObjectFileNameWithoutTarget(
      *sf, gt->ObjectDirectory, &keptSourceExtension, custom_ext, &force));
    force = false;
    si.second.LongLoc.Update(this->GetObjectFileNameWithoutTarget(
      *sf, gt->ObjectDirectory, &keptSourceExtension, custom_ext, &force));
    this->FillCustomInstallObjectLocations(*sf, config, custom_ext,
                                           si.second.InstallLongLoc);
  }
}
