/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *     http://aws.amazon.com/apache2.0/
 *
 * or in the "license" file accompanying this file. This file 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.
 */

#ifndef AACE_VEHICLE_CONFIG_VEHICLE_CONFIGURATION_H
#define AACE_VEHICLE_CONFIG_VEHICLE_CONFIGURATION_H

#include <string>
#include <utility>

#include "AACE/Core/EngineConfiguration.h"

/** @file */

namespace aace {
namespace vehicle {
namespace config {

/**
 * The @c VehicleConfiguration class is a factory that creates "aace.vehicle"
 * Engine configuration objects.
 */
class VehicleConfiguration {
public:
    /**
     * Specifies the device info configuration keys
     */
    enum class DeviceInfoPropertyType {
        /**
         * The manufacturer of the head unit hardware.
         * Example values: "Alpine", "Pioneer"
         */
        MANUFACTURER,

        /**
         * The model name of the head unit hardware.
         * Example value: "Coral"
         */
        MODEL,

        /**
         * The serial number of the head unit expressed as a string.
         */
        SERIAL_NUMBER,

        /**
         * The head unit software platform or operating system name.
         * Example values: "Android", "Ubuntu"
         */
        PLATFORM,

        /**
         * The version of the head unit operating system expressed as a string.
         * Example values: "12", "18.04.6 LTS"
         */
        OS_VERSION,

        /**
         * The hardware architecture of the head unit or CPU+instruction set.
         * Examples: "arm64-v8a", "x86_64", "armv7hf", "armv8"
         */
        HARDWARE_ARCH
    };

    /**
     * Specifies the app info configuration keys
     */
    enum class AppInfoPropertyType {
        /**
         * The version of the Auto SDK client application expressed as a string.
         * Example value: "1.0.1"
         */
        SOFTWARE_VERSION
    };

    /**
     * Specifies the vehicle info configuration keys
     */
    enum class VehicleInfoPropertyType {
        /**
         * The make of the vehicle.
         * @note This property is required.
         */
        MAKE,

        /**
         * The model of the vehicle.
         * @note This property is required.
         */
        MODEL,

        /**
         * The model year of the vehicle.
         * A value of this property type must be an integer in the range
         * 1900-2100 expressed as a string.
         * Example value: "2019"
         * @note This property is required.
         */
        YEAR,

        /**
         * The trim package of the vehicle, identifying the vehicle's level of
         * equipment or special features.
         * Example values: "Standard", "Sport", "Limited"
         */
        TRIM,

        /**
         * The current (or intended, if current is not available) operating
         * country for the vehicle. The value must be an ISO 3166
         * Alpha-2 country code.
         * Example values: "US", "MX", "JP"
         */
        OPERATING_COUNTRY,

        /**
         * The type and arrangement of microphone used by the vehicle.
         * Example value: "7 mic array centrally mounted"
         */
        MICROPHONE_TYPE,

        /**
         * The automaker's identifier for the vehicle.
         */
        VEHICLE_IDENTIFIER,

        /**
         * The type of engine in the vehicle.
         * Accepted values: "GAS", "HYBRID", "ELECTRIC"
         */
        ENGINE_TYPE,

        /**
         * The number of rear seat embedded Fire TVs in the vehicle. The value
         * must be an integer expressed as a string.
         * Example value: "2"
         */
        RSE_EMBEDDED_FIRE_TVS
    };

    /**
     * Identifies a vehicle info property with a pair of type and value.
     */
    using VehicleInfoProperty = std::pair<VehicleInfoPropertyType, std::string>;

    /**
     * Identifies a device info property with a pair of type and value.
     */
    using DeviceInfoProperty = std::pair<DeviceInfoPropertyType, std::string>;

    /**
     * Identifies an app info property with a pair of type and value.
     */
    using AppInfoProperty = std::pair<AppInfoPropertyType, std::string>;

    /**
     * Factory function used to programmatically generate
     * "aace.vehicle.vehicleInfo" Engine configuration data. The data
     * generated by this function is equivalent to providing the following JSON
     * format in a configuration file:
     *
     * @code{.json}
     * {
     *   "aace.vehicle": {
     *      "vehicleInfo": {
     *          "make": "<VEHICLE_MAKE>",
     *          "model": "<VEHICLE_MODEL>",
     *          "year": "<VEHICLE_MODEL_YEAR>",
     *          "trim": "<TRIM>",
     *          "microphoneType": "<MICROPHONE_TYPE>",
     *          "operatingCountry": "<OPERATING_COUNTRY>",
     *          "vehicleIdentifier": "<VEHICLE_ID>",
     *          "engineType": "<ENGINE_TYPE>",
     *          "rseEmbeddedFireTvs": "<EMBEDDED_FIRE_TV_COUNT>"
     *      }
     *   }
     * }
     * @endcode
     *
     * @param [in] propertyList A list of @c VehicleInfoProperty pairs
     * @return An @c aace::core::config::EngineConfiguration containing the
     *         specified data in JSON format
     */
    static std::shared_ptr<aace::core::config::EngineConfiguration> createVehicleInfoConfig(
        const std::vector<VehicleInfoProperty>& propertyList);

    /**
     * Factory function used to programmatically generate
     * "aace.vehicle.deviceInfo" Engine configuration data. The data
     * generated by this function is equivalent to providing the following JSON
     * format in a configuration file:
     *
     * @code{.json}
     * {
     *   "aace.vehicle": {
     *      "deviceInfo": {
     *          "manufacturer": "<DEVICE_MANUFACTURER>",
     *          "model": "<DEVICE_MODEL>",
     *          "serialNumber": <DEVICE_SERIAL_NUMBER>,
     *          "osVersion": "<OS_VERSION>",
     *          "hardwareArch": "<HARDWARE_ARCH>",
     *          "platform": "<PLATFORM>",
     *      }
     *   }
     * }
     * @endcode
     *
     * @param [in] propertyList A list of @c DeviceInfoProperty pairs
     * @return An @c aace::core::config::EngineConfiguration containing the
     *         specified data in JSON format
     */
    static std::shared_ptr<aace::core::config::EngineConfiguration> createDeviceInfoConfig(
        const std::vector<DeviceInfoProperty>& propertyList);

    /**
     * Factory function used to programmatically generate
     * "aace.vehicle.appInfo" Engine configuration data. The data
     * generated by this function is equivalent to providing the following JSON
     * format in a configuration file:
     *
     * @code{.json}
     * {
     *   "aace.vehicle": {
     *      "appInfo": {
     *          "softwareVersion": "<APP_VERSION>"
     *      }
     *   }
     * }
     * @endcode
     *
     * @param [in] propertyList A list of @c AppInfoProperty pairs
     * @return An @c aace::core::config::EngineConfiguration containing the
     *         specified data in JSON format
     */
    static std::shared_ptr<aace::core::config::EngineConfiguration> createAppInfoConfig(
        const std::vector<AppInfoProperty>& propertyList);
};

inline std::ostream& operator<<(std::ostream& stream, const VehicleConfiguration::VehicleInfoPropertyType& property) {
    switch (property) {
        case VehicleConfiguration::VehicleInfoPropertyType::MAKE:
            stream << "MAKE";
            break;
        case VehicleConfiguration::VehicleInfoPropertyType::MODEL:
            stream << "MODEL";
            break;
        case VehicleConfiguration::VehicleInfoPropertyType::YEAR:
            stream << "YEAR";
            break;
        case VehicleConfiguration::VehicleInfoPropertyType::TRIM:
            stream << "TRIM";
            break;
        case VehicleConfiguration::VehicleInfoPropertyType::MICROPHONE_TYPE:
            stream << "MICROPHONE_TYPE";
            break;
        case VehicleConfiguration::VehicleInfoPropertyType::OPERATING_COUNTRY:
            stream << "OPERATING_COUNTRY";
            break;
        case VehicleConfiguration::VehicleInfoPropertyType::VEHICLE_IDENTIFIER:
            stream << "VEHICLE_IDENTIFIER";
            break;
        case VehicleConfiguration::VehicleInfoPropertyType::ENGINE_TYPE:
            stream << "ENGINE_TYPE";
            break;
        case VehicleConfiguration::VehicleInfoPropertyType::RSE_EMBEDDED_FIRE_TVS:
            stream << "RSE_EMBEDDED_FIRE_TVS";
            break;
    }
    return stream;
}

inline std::ostream& operator<<(std::ostream& stream, const VehicleConfiguration::DeviceInfoPropertyType& property) {
    switch (property) {
        case VehicleConfiguration::DeviceInfoPropertyType::MANUFACTURER:
            stream << "MANUFACTURER";
            break;
        case VehicleConfiguration::DeviceInfoPropertyType::MODEL:
            stream << "MODEL";
            break;
        case VehicleConfiguration::DeviceInfoPropertyType::SERIAL_NUMBER:
            stream << "SERIAL_NUMBER";
            break;
        case VehicleConfiguration::DeviceInfoPropertyType::OS_VERSION:
            stream << "OS_VERSION";
            break;
        case VehicleConfiguration::DeviceInfoPropertyType::HARDWARE_ARCH:
            stream << "HARDWARE_ARCH";
            break;
        case VehicleConfiguration::DeviceInfoPropertyType::PLATFORM:
            stream << "PLATFORM";
            break;
    }
    return stream;
}

inline std::ostream& operator<<(std::ostream& stream, const VehicleConfiguration::AppInfoPropertyType& property) {
    switch (property) {
        case VehicleConfiguration::AppInfoPropertyType::SOFTWARE_VERSION:
            stream << "SOFTWARE_VERSION";
            break;
    }
    return stream;
}

}  // namespace config
}  // namespace vehicle
}  // namespace aace

#endif  // AACE_VEHICLE_CONFIG_VEHICLE_CONFIGURATION_H
