/* 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 "cmList.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 const& stdLinkDirString)
{
  std::string linkPath;
  std::vector<BT<std::string>> linkPathList;
  this->ComputeLinkPath(cli, libPathFlag, libPathTerminator, stdLinkDirString,
                        linkPathList);
  cli.AppendValues(linkPath, linkPathList);
  return linkPath;
}

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

    for (cmComputeLinkInformation::Item const& item : cli.GetItems()) {
      cmGeneratorTarget const* 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);
  }

  for (auto& linkDir : cmList(stdLinkDirString)) {
    linkPath.emplace_back(cmStrCat(' ', libPathFlag,
                                   this->ConvertToOutputForExisting(linkDir),
                                   libPathTerminator, ' '));
  }
}

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);
}
