// Copyright 2020 Bloomberg Finance L.P
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <buildboxcommon_commandlinetypes.h>

namespace buildboxcommon {

using DefaultValue = CommandLineTypes::DefaultValue;

template <typename T> T DefaultValue::value() const
{
    if (!d_value.has_value()) {
        throw std::runtime_error("default value was not set");
    }
    return std::any_cast<T>(d_value.value());
}

template std::string DefaultValue::value<std::string>() const;
template int DefaultValue::value<int>() const;
template double DefaultValue::value<double>() const;
template bool DefaultValue::value<bool>() const;

std::string DefaultValue::getString() const
{
    return this->value<std::string>();
}

int DefaultValue::getInt() const { return this->value<int>(); }

double DefaultValue::getDouble() const { return this->value<double>(); }

bool DefaultValue::getBool() const { return this->value<bool>(); }

std::ostream &operator<<(std::ostream &out,
                         const CommandLineTypes::ArgumentSpec &obj)
{
    out << "[\"" << obj.d_name << "\", \"" << obj.d_desc << "\", "
        << obj.d_typeInfo << ", " << obj.d_occurrence << ", "
        << obj.d_constraint << ", ";
    obj.d_defaultValue.print(out, obj.dataType());

    return out;
}

void CommandLineTypes::DefaultValue::print(std::ostream &out,
                                           const DataType dataType) const
{
    out << "[";
    switch (dataType) {
        case CommandLineTypes::DataType::COMMANDLINE_DT_STRING:
            out << "\"" << getString() << "\"";
            break;
        case CommandLineTypes::DataType::COMMANDLINE_DT_INT:
            out << getInt();
            break;
        case CommandLineTypes::DataType::COMMANDLINE_DT_DOUBLE:
            out << std::fixed << getDouble();
            break;
        case CommandLineTypes::DataType::COMMANDLINE_DT_BOOL: {
            out << std::boolalpha << getBool();
            break;
        }
        default:
            break;
    }

    out << "]";
}

std::ostream &operator<<(std::ostream &out,
                         const CommandLineTypes::TypeInfo &obj)
{
    out << obj.d_dataType;
    return out;
}

} // namespace buildboxcommon
