/* 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 "cmSystemTools.h"

#include <utility>

// 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(
    const std::string& defaultComponent)
: Parser()
, ArgumentGroup()
, Destination(&Parser, "DESTINATION", &ArgumentGroup)
, Component(&Parser, "COMPONENT", &ArgumentGroup)
, NamelinkComponent(&Parser, "NAMELINK_COMPONENT", &ArgumentGroup)
, ExcludeFromAll(&Parser, "EXCLUDE_FROM_ALL", &ArgumentGroup)
, Rename(&Parser, "RENAME", &ArgumentGroup)
, Permissions(&Parser, "PERMISSIONS", &ArgumentGroup)
, Configurations(&Parser, "CONFIGURATIONS", &ArgumentGroup)
, Optional(&Parser, "OPTIONAL", &ArgumentGroup)
, NamelinkOnly(&Parser, "NAMELINK_ONLY", &ArgumentGroup)
, NamelinkSkip(&Parser, "NAMELINK_SKIP", &ArgumentGroup)
, GenericArguments(nullptr)
, DefaultComponentName(defaultComponent)
{}

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

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

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

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

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

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

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

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

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

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

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

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

void
cmInstallCommandArguments::Parse(const std::vector<std::string>* args,
                                 std::vector<std::string>*       unconsumedArgs)
{
    this->Parser.Parse(args, unconsumedArgs);
}

bool
cmInstallCommandArguments::CheckPermissions()
{
    this->PermissionsString.clear();
    for(std::string const& perm : this->Permissions.GetVector())
    {
        if(!this->CheckPermissions(perm, this->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() {}

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

void
cmInstallCommandIncludesArgument::Parse(const std::vector<std::string>* args,
                                        std::vector<std::string>*)
{
    if(args->empty())
    {
        return;
    }
    std::vector<std::string>::const_iterator it = args->begin();
    ++it;
    for(; it != args->end(); ++it)
    {
        std::string dir = *it;
        cmSystemTools::ConvertToUnixSlashes(dir);
        this->IncludeDirs.push_back(std::move(dir));
    }
}
