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

#include <utility>

#include <cmext/string_view>

#include "cmRange.h"
#include "cmSystemTools.h"

// Table of valid permissions.
const char* cmInstallCommandArguments::PermissionsTable[] = {
  "OWNER_READ",    "OWNER_WRITE",   "OWNER_EXECUTE", "GROUP_READ",
  "GROUP_WRITE",   "GROUP_EXECUTE", "WORLD_READ",    "WORLD_WRITE",
  "WORLD_EXECUTE", "SETUID",        "SETGID",        nullptr
};

const std::string cmInstallCommandArguments::EmptyString;

cmInstallCommandArguments::cmInstallCommandArguments(
  std::string defaultComponent)
  : DefaultComponentName(std::move(defaultComponent))
{
  Bind("DESTINATION"_s, Destination);
  Bind("COMPONENT"_s, Component);
  Bind("NAMELINK_COMPONENT"_s, NamelinkComponent);
  Bind("EXCLUDE_FROM_ALL"_s, ExcludeFromAll);
  Bind("RENAME"_s, Rename);
  Bind("PERMISSIONS"_s, Permissions);
  Bind("CONFIGURATIONS"_s, Configurations);
  Bind("OPTIONAL"_s, Optional);
  Bind("NAMELINK_ONLY"_s, NamelinkOnly);
  Bind("NAMELINK_SKIP"_s, NamelinkSkip);
  Bind("TYPE"_s, Type);
}

const std::string& cmInstallCommandArguments::GetDestination() const
{
  if (!DestinationString.empty()) {
    return DestinationString;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetDestination();
  }
  return EmptyString;
}

const std::string& cmInstallCommandArguments::GetComponent() const
{
  if (!Component.empty()) {
    return Component;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetComponent();
  }
  if (!DefaultComponentName.empty()) {
    return DefaultComponentName;
  }
  static std::string unspecifiedComponent = "Unspecified";
  return unspecifiedComponent;
}

const std::string& cmInstallCommandArguments::GetNamelinkComponent() const
{
  if (!NamelinkComponent.empty()) {
    return NamelinkComponent;
  }
  return GetComponent();
}

const std::string& cmInstallCommandArguments::GetRename() const
{
  if (!Rename.empty()) {
    return Rename;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetRename();
  }
  return EmptyString;
}

const std::string& cmInstallCommandArguments::GetPermissions() const
{
  if (!PermissionsString.empty()) {
    return PermissionsString;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetPermissions();
  }
  return EmptyString;
}

bool cmInstallCommandArguments::GetOptional() const
{
  if (Optional) {
    return true;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetOptional();
  }
  return false;
}

bool cmInstallCommandArguments::GetExcludeFromAll() const
{
  if (ExcludeFromAll) {
    return true;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetExcludeFromAll();
  }
  return false;
}

bool cmInstallCommandArguments::GetNamelinkOnly() const
{
  if (NamelinkOnly) {
    return true;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetNamelinkOnly();
  }
  return false;
}

bool cmInstallCommandArguments::GetNamelinkSkip() const
{
  if (NamelinkSkip) {
    return true;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetNamelinkSkip();
  }
  return false;
}

bool cmInstallCommandArguments::HasNamelinkComponent() const
{
  if (!NamelinkComponent.empty()) {
    return true;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->HasNamelinkComponent();
  }
  return false;
}

const std::string& cmInstallCommandArguments::GetType() const
{
  return Type;
}

const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations()
  const
{
  if (!Configurations.empty()) {
    return Configurations;
  }
  if (GenericArguments != nullptr) {
    return GenericArguments->GetConfigurations();
  }
  return Configurations;
}

bool cmInstallCommandArguments::Finalize()
{
  if (!CheckPermissions()) {
    return false;
  }
  DestinationString = Destination;
  cmSystemTools::ConvertToUnixSlashes(DestinationString);
  return true;
}

bool cmInstallCommandArguments::CheckPermissions()
{
  PermissionsString.clear();
  for (std::string const& perm : Permissions) {
    if (!cmInstallCommandArguments::CheckPermissions(perm,
                                                     PermissionsString)) {
      return false;
    }
  }
  return true;
}

bool cmInstallCommandArguments::CheckPermissions(
  const std::string& onePermission, std::string& permissions)
{
  // Check the permission against the table.
  for (const char** valid = cmInstallCommandArguments::PermissionsTable;
       *valid; ++valid) {
    if (onePermission == *valid) {
      // This is a valid permission.
      permissions += " ";
      permissions += onePermission;
      return true;
    }
  }
  // This is not a valid permission.
  return false;
}

cmInstallCommandIncludesArgument::cmInstallCommandIncludesArgument() = default;

const std::vector<std::string>&
cmInstallCommandIncludesArgument::GetIncludeDirs() const
{
  return IncludeDirs;
}

void cmInstallCommandIncludesArgument::Parse(
  const std::vector<std::string>* args, std::vector<std::string>*)
{
  if (args->empty()) {
    return;
  }
  for (std::string dir : cmMakeRange(*args).advance(1)) {
    cmSystemTools::ConvertToUnixSlashes(dir);
    IncludeDirs.push_back(std::move(dir));
  }
}
