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

#include <algorithm>
#include <cassert>
#include <utility>

#include "cmFindCommon.h"
#include "cmMakefile.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"

cmSearchPath::cmSearchPath(cmFindCommon* findCmd)
  : FC(findCmd)
{
}

cmSearchPath::~cmSearchPath() = default;

void cmSearchPath::ExtractWithout(const std::set<std::string>& ignore,
                                  std::vector<std::string>& outPaths,
                                  bool clear) const
{
  if (clear) {
    outPaths.clear();
  }
  for (std::string const& path : this->Paths) {
    if (ignore.count(path) == 0) {
      outPaths.push_back(path);
    }
  }
}

void cmSearchPath::AddPath(const std::string& path)
{
  this->AddPathInternal(path);
}

void cmSearchPath::AddUserPath(const std::string& path)
{
  assert(this->FC != nullptr);

  std::vector<std::string> outPaths;

  // We should view the registry as the target application would view
  // it.
  cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
  cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
  if (this->FC->Makefile->PlatformIs64Bit()) {
    view = cmSystemTools::KeyWOW64_64;
    other_view = cmSystemTools::KeyWOW64_32;
  }

  // Expand using the view of the target application.
  std::string expanded = path;
  cmSystemTools::ExpandRegistryValues(expanded, view);
  cmSystemTools::GlobDirs(expanded, outPaths);

  // Executables can be either 32-bit or 64-bit, so expand using the
  // alternative view.
  if (expanded != path && this->FC->CMakePathName == "PROGRAM") {
    expanded = path;
    cmSystemTools::ExpandRegistryValues(expanded, other_view);
    cmSystemTools::GlobDirs(expanded, outPaths);
  }

  // Process them all from the current directory
  for (std::string const& p : outPaths) {
    this->AddPathInternal(
      p, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
  }
}

void cmSearchPath::AddCMakePath(const std::string& variable)
{
  assert(this->FC != nullptr);

  // Get a path from a CMake variable.
  if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
    std::vector<std::string> expanded = cmExpandedList(*value);

    for (std::string const& p : expanded) {
      this->AddPathInternal(
        p, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
    }
  }
}

void cmSearchPath::AddEnvPath(const std::string& variable)
{
  std::vector<std::string> expanded;
  cmSystemTools::GetPath(expanded, variable.c_str());
  for (std::string const& p : expanded) {
    this->AddPathInternal(p);
  }
}

void cmSearchPath::AddCMakePrefixPath(const std::string& variable)
{
  assert(this->FC != nullptr);

  // Get a path from a CMake variable.
  if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
    std::vector<std::string> expanded = cmExpandedList(*value);

    this->AddPrefixPaths(
      expanded, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
  }
}

static std::string cmSearchPathStripBin(std::string const& s)
{
  // If the path is a PREFIX/bin case then add its parent instead.
  if ((cmHasLiteralSuffix(s, "/bin")) || (cmHasLiteralSuffix(s, "/sbin"))) {
    return cmSystemTools::GetFilenamePath(s);
  }
  return s;
}

void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin)
{
  std::vector<std::string> expanded;
  cmSystemTools::GetPath(expanded, variable.c_str());
  if (stripBin) {
    std::transform(expanded.begin(), expanded.end(), expanded.begin(),
                   cmSearchPathStripBin);
  }
  this->AddPrefixPaths(expanded);
}

void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes)
{
  std::vector<std::string> inPaths;
  inPaths.swap(this->Paths);
  this->Paths.reserve(inPaths.size() * (suffixes.size() + 1));

  for (std::string& inPath : inPaths) {
    cmSystemTools::ConvertToUnixSlashes(inPath);

    // if *i is only / then do not add a //
    // this will get incorrectly considered a network
    // path on windows and cause huge delays.
    std::string p = inPath;
    if (!p.empty() && p.back() != '/') {
      p += "/";
    }

    // Combine with all the suffixes
    for (std::string const& suffix : suffixes) {
      this->Paths.push_back(p + suffix);
    }

    // And now the original w/o any suffix
    this->Paths.push_back(std::move(inPath));
  }
}

void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
                                  const char* base)
{
  assert(this->FC != nullptr);

  // default for programs
  std::string subdir = "bin";

  if (this->FC->CMakePathName == "INCLUDE") {
    subdir = "include";
  } else if (this->FC->CMakePathName == "LIBRARY") {
    subdir = "lib";
  } else if (this->FC->CMakePathName == "FRAMEWORK") {
    subdir.clear(); // ? what to do for frameworks ?
  }

  for (std::string const& path : paths) {
    std::string dir = path;
    if (!subdir.empty() && !dir.empty() && dir.back() != '/') {
      dir += "/";
    }
    if (subdir == "include" || subdir == "lib") {
      cmValue arch =
        this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
      if (cmNonempty(arch)) {
        if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") &&
            this->FC->Makefile->IsDefinitionSet(
              "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) {
          this->AddPathInternal(cmStrCat('/', *arch, dir, subdir), base);
        } else {
          this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), base);
        }
      }
    }
    std::string add = dir + subdir;
    if (add != "/") {
      this->AddPathInternal(add, base);
    }
    if (subdir == "bin") {
      this->AddPathInternal(dir + "sbin", base);
    }
    if (!subdir.empty() && path != "/") {
      this->AddPathInternal(path, base);
    }
  }
}

void cmSearchPath::AddPathInternal(const std::string& path, const char* base)
{
  assert(this->FC != nullptr);

  std::string collapsed = cmSystemTools::CollapseFullPath(path, base);

  if (collapsed.empty()) {
    return;
  }

  // Insert the path if has not already been emitted.
  if (this->FC->SearchPathsEmitted.insert(collapsed).second) {
    this->Paths.push_back(std::move(collapsed));
  }
}
