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

#include <cassert>
#include <cstddef>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include <cm/string_view>
#include <cmext/string_view>

#include "cmScanDepFormat.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"

CxxBmiLocation::CxxBmiLocation() = default;

CxxBmiLocation::CxxBmiLocation(std::string path)
  : BmiLocation(std::move(path))
{
}

CxxBmiLocation CxxBmiLocation::Unknown()
{
  return {};
}

CxxBmiLocation CxxBmiLocation::Private()
{
  return { std::string{} };
}

CxxBmiLocation CxxBmiLocation::Known(std::string path)
{
  return { std::move(path) };
}

bool CxxBmiLocation::IsKnown() const
{
  return this->BmiLocation.has_value();
}

bool CxxBmiLocation::IsPrivate() const
{
  if (auto const& loc = this->BmiLocation) {
    return loc->empty();
  }
  return false;
}

std::string const& CxxBmiLocation::Location() const
{
  if (auto const& loc = this->BmiLocation) {
    return *loc;
  }
  static std::string empty;
  return empty;
}

CxxBmiLocation CxxModuleLocations::BmiGeneratorPathForModule(
  std::string const& logical_name) const
{
  auto bmi_loc = this->BmiLocationForModule(logical_name);
  if (bmi_loc.IsKnown() && !bmi_loc.IsPrivate()) {
    bmi_loc =
      CxxBmiLocation::Known(this->PathForGenerator(bmi_loc.Location()));
  }
  return bmi_loc;
}

namespace {

struct TransitiveUsage
{
  TransitiveUsage(std::string name, std::string location, LookupMethod method)
    : LogicalName(std::move(name))
    , Location(std::move(location))
    , Method(method)
  {
  }

  std::string LogicalName;
  std::string Location;
  LookupMethod Method;
};

std::vector<TransitiveUsage> GetTransitiveUsages(
  CxxModuleLocations const& loc, std::vector<cmSourceReqInfo> const& required,
  CxxModuleUsage const& usages)
{
  std::set<std::string> transitive_usage_directs;
  std::set<std::string> transitive_usage_names;

  std::vector<TransitiveUsage> all_usages;

  for (auto const& r : required) {
    auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName);
    if (bmi_loc.IsKnown()) {
      all_usages.emplace_back(r.LogicalName, bmi_loc.Location(), r.Method);
      transitive_usage_directs.insert(r.LogicalName);

      // Insert transitive usages.
      auto transitive_usages = usages.Usage.find(r.LogicalName);
      if (transitive_usages != usages.Usage.end()) {
        transitive_usage_names.insert(transitive_usages->second.begin(),
                                      transitive_usages->second.end());
      }
    }
  }

  for (auto const& transitive_name : transitive_usage_names) {
    if (transitive_usage_directs.count(transitive_name)) {
      continue;
    }

    auto module_ref = usages.Reference.find(transitive_name);
    if (module_ref != usages.Reference.end()) {
      all_usages.emplace_back(transitive_name, module_ref->second.Path,
                              module_ref->second.Method);
    }
  }

  return all_usages;
}

std::string CxxModuleMapContentClang(CxxModuleLocations const& loc,
                                     cmScanDepInfo const& obj,
                                     CxxModuleUsage const& usages)
{
  std::stringstream mm;

  // Clang's command line only supports a single output. If more than one is
  // expected, we cannot make a useful module map file.
  if (obj.Provides.size() > 1) {
    return {};
  }

  // A series of flags which tell the compiler where to look for modules.

  for (auto const& p : obj.Provides) {
    auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName);
    if (bmi_loc.IsKnown()) {
      // Force the TU to be considered a C++ module source file regardless of
      // extension.
      mm << "-x c++-module\n";

      mm << "-fmodule-output=\"" << bmi_loc.Location() << "\"\n";
      break;
    }
  }

  auto all_usages = GetTransitiveUsages(loc, obj.Requires, usages);
  for (auto const& usage : all_usages) {
    mm << "-fmodule-file=\"" << usage.LogicalName << '=' << usage.Location
       << "\"\n";
  }

  return mm.str();
}

std::string CxxModuleMapContentGcc(CxxModuleLocations const& loc,
                                   cmScanDepInfo const& obj)
{
  std::stringstream mm;

  // Documented in GCC's documentation. The format is a series of
  // lines with a module name and the associated filename separated
  // by spaces. The first line may use `$root` as the module name
  // to specify a "repository root". That is used to anchor any
  // relative paths present in the file (CMake should never
  // generate any).

  // Write the root directory to use for module paths.
  mm << "$root " << loc.RootDirectory << '\n';

  for (auto const& p : obj.Provides) {
    auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName);
    if (bmi_loc.IsKnown()) {
      mm << p.LogicalName << ' ' << bmi_loc.Location() << '\n';
    }
  }
  for (auto const& r : obj.Requires) {
    auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName);
    if (bmi_loc.IsKnown()) {
      mm << r.LogicalName << ' ' << bmi_loc.Location() << '\n';
    }
  }

  return mm.str();
}

std::string CxxModuleMapContentMsvc(CxxModuleLocations const& loc,
                                    cmScanDepInfo const& obj,
                                    CxxModuleUsage const& usages)
{
  std::stringstream mm;

  // A response file of `-reference NAME=PATH` arguments.

  // MSVC's command line only supports a single output. If more than one is
  // expected, we cannot make a useful module map file.
  if (obj.Provides.size() > 1) {
    return {};
  }

  auto flag_for_method = [](LookupMethod method) -> cm::static_string_view {
    switch (method) {
      case LookupMethod::ByName:
        return "-reference"_s;
      case LookupMethod::IncludeAngle:
        return "-headerUnit:angle"_s;
      case LookupMethod::IncludeQuote:
        return "-headerUnit:quote"_s;
    }
    assert(false && "unsupported lookup method");
    return ""_s;
  };

  for (auto const& p : obj.Provides) {
    if (p.IsInterface) {
      mm << "-interface\n";
    } else {
      mm << "-internalPartition\n";
    }

    auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName);
    if (bmi_loc.IsKnown()) {
      mm << "-ifcOutput \"" << bmi_loc.Location() << "\"\n";
    }
  }

  auto all_usages = GetTransitiveUsages(loc, obj.Requires, usages);
  for (auto const& usage : all_usages) {
    auto flag = flag_for_method(usage.Method);

    mm << flag << " \"" << usage.LogicalName << '=' << usage.Location
       << "\"\n";
  }

  return mm.str();
}
}

bool CxxModuleUsage::AddReference(std::string const& logical,
                                  std::string const& loc, LookupMethod method)
{
  auto r = this->Reference.find(logical);
  if (r != this->Reference.end()) {
    auto& ref = r->second;

    if (ref.Path == loc && ref.Method == method) {
      return true;
    }

    auto method_name = [](LookupMethod m) -> cm::static_string_view {
      switch (m) {
        case LookupMethod::ByName:
          return "by-name"_s;
        case LookupMethod::IncludeAngle:
          return "include-angle"_s;
        case LookupMethod::IncludeQuote:
          return "include-quote"_s;
      }
      assert(false && "unsupported lookup method");
      return ""_s;
    };

    cmSystemTools::Error(cmStrCat("Disagreement of the location of the '",
                                  logical,
                                  "' module. "
                                  "Location A: '",
                                  ref.Path, "' via ", method_name(ref.Method),
                                  "; "
                                  "Location B: '",
                                  loc, "' via ", method_name(method), '.'));
    return false;
  }

  auto& ref = this->Reference[logical];
  ref.Path = loc;
  ref.Method = method;

  return true;
}

cm::static_string_view CxxModuleMapExtension(
  cm::optional<CxxModuleMapFormat> format)
{
  if (format) {
    switch (*format) {
      case CxxModuleMapFormat::Clang:
        return ".pcm"_s;
      case CxxModuleMapFormat::Gcc:
        return ".gcm"_s;
      case CxxModuleMapFormat::Msvc:
        return ".ifc"_s;
    }
  }

  return ".bmi"_s;
}

std::set<std::string> CxxModuleUsageSeed(
  CxxModuleLocations const& loc, std::vector<cmScanDepInfo> const& objects,
  CxxModuleUsage& usages, bool& private_usage_found)
{
  // Track inner usages to populate usages from internal bits.
  //
  // This is a map of modules that required some other module that was not
  // found to those that were not found.
  std::map<std::string, std::set<std::string>> internal_usages;
  std::set<std::string> unresolved;

  for (cmScanDepInfo const& object : objects) {
    // Add references for each of the provided modules.
    for (auto const& p : object.Provides) {
      auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName);
      if (bmi_loc.IsKnown()) {
        // XXX(cxx-modules): How to support header units?
        usages.AddReference(p.LogicalName, bmi_loc.Location(),
                            LookupMethod::ByName);
      }
    }

    // For each requires, pull in what is required.
    for (auto const& r : object.Requires) {
      // Find the required name in the current target.
      auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName);
      if (bmi_loc.IsPrivate()) {
        cmSystemTools::Error(
          cmStrCat("Unable to use module '", r.LogicalName,
                   "' as it is 'PRIVATE' and therefore not accessible outside "
                   "of its owning target."));
        private_usage_found = true;
        continue;
      }

      // Find transitive usages.
      auto transitive_usages = usages.Usage.find(r.LogicalName);

      for (auto const& p : object.Provides) {
        auto& this_usages = usages.Usage[p.LogicalName];

        // Add the direct usage.
        this_usages.insert(r.LogicalName);

        if (transitive_usages == usages.Usage.end() ||
            internal_usages.find(r.LogicalName) != internal_usages.end()) {
          // Mark that we need to update transitive usages later.
          if (bmi_loc.IsKnown()) {
            internal_usages[p.LogicalName].insert(r.LogicalName);
          }
        } else {
          // Add the transitive usage.
          this_usages.insert(transitive_usages->second.begin(),
                             transitive_usages->second.end());
        }
      }

      if (bmi_loc.IsKnown()) {
        usages.AddReference(r.LogicalName, bmi_loc.Location(), r.Method);
      }
    }
  }

  // While we have internal usages to manage.
  while (!internal_usages.empty()) {
    size_t starting_size = internal_usages.size();

    // For each internal usage.
    for (auto usage = internal_usages.begin(); usage != internal_usages.end();
         /* see end of loop */) {
      auto& this_usages = usages.Usage[usage->first];

      for (auto use = usage->second.begin(); use != usage->second.end();
           /* see end of loop */) {
        // Check if this required module uses other internal modules; defer
        // if so.
        if (internal_usages.count(*use)) {
          // Advance the iterator.
          ++use;
          continue;
        }

        auto transitive_usages = usages.Usage.find(*use);
        if (transitive_usages != usages.Usage.end()) {
          this_usages.insert(transitive_usages->second.begin(),
                             transitive_usages->second.end());
        }

        // Remove the entry and advance the iterator.
        use = usage->second.erase(use);
      }

      // Erase the entry if it doesn't have any remaining usages.
      if (usage->second.empty()) {
        usage = internal_usages.erase(usage);
      } else {
        ++usage;
      }
    }

    // Check that at least one usage was resolved.
    if (starting_size == internal_usages.size()) {
      // Nothing could be resolved this loop; we have a cycle, so record the
      // cycle and exit.
      for (auto const& usage : internal_usages) {
        unresolved.insert(usage.first);
      }
      break;
    }
  }

  return unresolved;
}

std::string CxxModuleMapContent(CxxModuleMapFormat format,
                                CxxModuleLocations const& loc,
                                cmScanDepInfo const& obj,
                                CxxModuleUsage const& usages)
{
  switch (format) {
    case CxxModuleMapFormat::Clang:
      return CxxModuleMapContentClang(loc, obj, usages);
    case CxxModuleMapFormat::Gcc:
      return CxxModuleMapContentGcc(loc, obj);
    case CxxModuleMapFormat::Msvc:
      return CxxModuleMapContentMsvc(loc, obj, usages);
  }

  assert(false);
  return {};
}

CxxModuleMapMode CxxModuleMapOpenMode(CxxModuleMapFormat format)
{
  switch (format) {
    case CxxModuleMapFormat::Gcc:
      return CxxModuleMapMode::Binary;
    case CxxModuleMapFormat::Clang:
    case CxxModuleMapFormat::Msvc:
      return CxxModuleMapMode::Default;
  }

  assert(false);
  return CxxModuleMapMode::Default;
}
