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

#include "cmLinkLineComputer.h"

#include <sstream>
#include <utility>
#include <vector>

#include "cmComputeLinkInformation.h"
#include "cmGeneratorTarget.h"
#include "cmListFileCache.h"
#include "cmOutputConverter.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"

cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter* outputConverter,
                                       cmStateDirectory const& stateDir)
  : StateDir(stateDir)
  , OutputConverter(outputConverter)
{
}

cmLinkLineComputer::~cmLinkLineComputer() = default;

void cmLinkLineComputer::SetUseWatcomQuote(bool useWatcomQuote)
{
  this->UseWatcomQuote = useWatcomQuote;
}

void cmLinkLineComputer::SetUseNinjaMulti(bool useNinjaMulti)
{
  this->UseNinjaMulti = useNinjaMulti;
}

void cmLinkLineComputer::SetForResponse(bool forResponse)
{
  this->ForResponse = forResponse;
}

void cmLinkLineComputer::SetRelink(bool relink)
{
  this->Relink = relink;
}

std::string cmLinkLineComputer::ConvertToLinkReference(
  std::string const& lib) const
{
  return this->OutputConverter->MaybeRelativeToCurBinDir(lib);
}

std::string cmLinkLineComputer::ComputeLinkLibs(cmComputeLinkInformation& cli)
{
  std::string linkLibs;
  std::vector<BT<std::string>> linkLibsList;
  this->ComputeLinkLibs(cli, linkLibsList);
  cli.AppendValues(linkLibs, linkLibsList);
  return linkLibs;
}

void cmLinkLineComputer::ComputeLinkLibs(
  cmComputeLinkInformation& cli, std::vector<BT<std::string>>& linkLibraries)
{
  using ItemVector = cmComputeLinkInformation::ItemVector;
  ItemVector const& items = cli.GetItems();
  for (auto const& item : items) {
    if (item.Target &&
        (item.Target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
         item.Target->GetType() == cmStateEnums::OBJECT_LIBRARY)) {
      continue;
    }

    BT<std::string> linkLib;
    if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
      linkLib = item.GetFormattedItem(this->ConvertToOutputFormat(
        this->ConvertToLinkReference(item.Value.Value)));
    } else {
      linkLib = item.Value;
    }
    linkLib.Value += " ";

    linkLibraries.emplace_back(linkLib);
  }
}

std::string cmLinkLineComputer::ConvertToOutputFormat(std::string const& input)
{
  cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL;
  if (this->ForResponse) {
    shellFormat = cmOutputConverter::RESPONSE;
  } else if (this->UseNinjaMulti) {
    shellFormat = cmOutputConverter::NINJAMULTI;
  }

  return this->OutputConverter->ConvertToOutputFormat(input, shellFormat,
                                                      this->UseWatcomQuote);
}

std::string cmLinkLineComputer::ConvertToOutputForExisting(
  std::string const& input)
{
  cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL;
  if (this->ForResponse) {
    shellFormat = cmOutputConverter::RESPONSE;
  } else if (this->UseNinjaMulti) {
    shellFormat = cmOutputConverter::NINJAMULTI;
  }

  return this->OutputConverter->ConvertToOutputForExisting(
    input, shellFormat, this->UseWatcomQuote);
}

std::string cmLinkLineComputer::ComputeLinkPath(
  cmComputeLinkInformation& cli, std::string const& libPathFlag,
  std::string const& libPathTerminator)
{
  std::string linkPath;
  std::vector<BT<std::string>> linkPathList;
  this->ComputeLinkPath(cli, libPathFlag, libPathTerminator, linkPathList);
  cli.AppendValues(linkPath, linkPathList);
  return linkPath;
}

void cmLinkLineComputer::ComputeLinkPath(
  cmComputeLinkInformation& cli, std::string const& libPathFlag,
  std::string const& libPathTerminator, std::vector<BT<std::string>>& linkPath)
{
  if (cli.GetLinkLanguage() == "Swift") {
    std::string linkPathNoBT;

    for (const cmComputeLinkInformation::Item& item : cli.GetItems()) {
      const cmGeneratorTarget* target = item.Target;
      if (!target) {
        continue;
      }

      if (target->GetType() == cmStateEnums::STATIC_LIBRARY ||
          target->GetType() == cmStateEnums::SHARED_LIBRARY) {
        cmStateEnums::ArtifactType type = cmStateEnums::RuntimeBinaryArtifact;
        if (target->HasImportLibrary(cli.GetConfig())) {
          type = cmStateEnums::ImportLibraryArtifact;
        }

        linkPathNoBT +=
          cmStrCat(" ", libPathFlag,
                   this->ConvertToOutputForExisting(
                     item.Target->GetDirectory(cli.GetConfig(), type)),
                   libPathTerminator, " ");
      }
    }

    if (!linkPathNoBT.empty()) {
      linkPath.emplace_back(std::move(linkPathNoBT));
    }
  }

  for (BT<std::string> libDir : cli.GetDirectoriesWithBacktraces()) {
    libDir.Value = cmStrCat(" ", libPathFlag,
                            this->ConvertToOutputForExisting(libDir.Value),
                            libPathTerminator, " ");
    linkPath.emplace_back(libDir);
  }
}

std::string cmLinkLineComputer::ComputeRPath(cmComputeLinkInformation& cli)
{
  std::string rpath;
  // Check what kind of rpath flags to use.
  if (cli.GetRuntimeSep().empty()) {
    // Each rpath entry gets its own option ("-R a -R b -R c")
    std::vector<std::string> runtimeDirs;
    cli.GetRPath(runtimeDirs, this->Relink);

    for (std::string const& rd : runtimeDirs) {
      rpath += cli.GetRuntimeFlag();
      rpath += this->ConvertToOutputFormat(rd);
      rpath += " ";
    }
  } else {
    // All rpath entries are combined ("-Wl,-rpath,a:b:c").
    std::string rpathString = cli.GetRPathString(this->Relink);

    // Store the rpath option in the stream.
    if (!rpathString.empty()) {
      rpath += cli.GetRuntimeFlag();
      rpath +=
        this->OutputConverter->EscapeForShell(rpathString, !this->ForResponse);
      rpath += " ";
    }
  }
  return rpath;
}

std::string cmLinkLineComputer::ComputeFrameworkPath(
  cmComputeLinkInformation& cli, cmValue fwSearchFlag)
{
  if (!fwSearchFlag) {
    return std::string{};
  }

  std::string frameworkPath;
  for (auto const& fd : cli.GetFrameworkPaths()) {
    frameworkPath +=
      cmStrCat(fwSearchFlag, this->ConvertToOutputFormat(fd), ' ');
  }
  return frameworkPath;
}

std::string cmLinkLineComputer::ComputeLinkLibraries(
  cmComputeLinkInformation& cli, std::string const& stdLibString)
{
  std::string linkLibraries;
  std::vector<BT<std::string>> linkLibrariesList;
  this->ComputeLinkLibraries(cli, stdLibString, linkLibrariesList);
  cli.AppendValues(linkLibraries, linkLibrariesList);
  return linkLibraries;
}

void cmLinkLineComputer::ComputeLinkLibraries(
  cmComputeLinkInformation& cli, std::string const& stdLibString,
  std::vector<BT<std::string>>& linkLibraries)
{
  std::ostringstream rpathOut;
  rpathOut << this->ComputeRPath(cli);

  std::string rpath = rpathOut.str();
  if (!rpath.empty()) {
    linkLibraries.emplace_back(std::move(rpath));
  }

  // Write the library flags to the build rule.
  this->ComputeLinkLibs(cli, linkLibraries);

  // Add the linker runtime search path if any.
  std::ostringstream fout;
  std::string rpath_link = cli.GetRPathLinkString();
  if (!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) {
    fout << cli.GetRPathLinkFlag();
    fout << this->OutputConverter->EscapeForShell(rpath_link,
                                                  !this->ForResponse);
    fout << " ";
  }

  if (!stdLibString.empty()) {
    fout << stdLibString << " ";
  }

  std::string remainingLibs = fout.str();
  if (!remainingLibs.empty()) {
    linkLibraries.emplace_back(remainingLibs);
  }
}

std::string cmLinkLineComputer::GetLinkerLanguage(cmGeneratorTarget* target,
                                                  std::string const& config)
{
  return target->GetLinkerLanguage(config);
}
