/*
 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
 *
 * This software is dual-licensed to you under the MIT License (MIT) and
 * the Universal Permissive License (UPL). See the LICENSE file in the root
 * directory for license terms. You may choose either license, or both.
 */

#pragma once

#include <DirectlyConnectedDevice.hpp>
#include <map>
#include <string>
#include <initializer_list>
#include <stdexcept>




namespace iotdcl {
#if defined IOTCS_GATEWAY || defined IOTCS_DOXYGEN

    /**
     * @file GatewayDevice.hpp
     * @brief A GatewayDevice is capable of registering indirectly&ndash;connected devices
     * and proxies messages for indirectly&ndash;connected devices.
     */
    class GatewayDevice : public DirectlyConnectedDevice {
    public:    
        /**
         * The {@code manufacturer} attribute. This attribute is to be used
         * when setting the {@code manufacturer} value in the meta-data.
         */
        static const std::string MANUFACTURER;

        /**
         * The {@code modelNumber} attribute. This attribute is to be used
         * when setting the {@code modelNumber} value in the meta-data.
         */
        static const std::string MODEL_NUMBER;

        /**
         * The {@code serialNumber} attribute. This attribute is to be used
         * when setting the {@code serialNumber} value in the meta-data.
         */
        static const std::string SERIAL_NUMBER;

        /**
         * The {@code deviceClass} attribute. This attribute is to be used
         * when setting the {@code deviceClass} value in the meta-data.
         */
        static const std::string DEVICE_CLASS;

        /**
         * The {@code protocol} attribute. This attribute is to be used
         * when setting the {@code protocol} value in the meta-data.
         */
        static const std::string PROTOCOL;

        /**
         * The {@code protocolDeviceClass} attribute. This attribute is to be used
         * when setting the {@code protocolDeviceClass} value in the meta-data.
         */
        static const std::string PROTOCOL_DEVICE_CLASS;

        /**
         * The {@code protocolDeviceId} attribute. This attribute is to be used
         * when setting the {@code protocolDeviceId} value in the meta-data.
         */
        static const std::string PROTOCOL_DEVICE_ID;

        /**
         * Constructs a new GatewayDevice instance that will load
         * the device configuration from the given file path and password.
         *
         * @param configFilePath the path of the configuration file
         * @param configFilePassword the configuration file password
         * @throw std::invalid_argument if \a filePath or password is NULL.
         * @throw GeneralException otherwise.
         */
        GatewayDevice(const std::string &filePath, const std::string &password) throw (std::invalid_argument, GeneralException);

        /**
         * @brief Destructor
         */
        virtual ~GatewayDevice();

        /**
         * @brief Register an indirectly-connected device with the cloud service and specify whether
         * the gateway device is required to have the appropriate credentials for activating
         * the indirectly-connected device.
         *
         * <p>
         *     The {@code restricted} parameter controls whether or not the client
         *     library is <em>required</em> to supply credentials for activating
         *     the indirectly-connected device. The client library will
         *     always supply credentials for an indirectly-connected
         *     device whose trusted assets have been provisioned to the client.
         *     If, however, the trusted assets of the indirectly-connected device
         *     have not been provisioned to the client, the client library can
         *     create credentials that attempt to restrict the indirectly connected
         *     device to this gateway device.
         * </p>
         * <p>
         *     Pass true for the restricted parameter
         *     to ensure the indirectly-connected device cannot be activated
         *     by this gateway device without presenting credentials. If restricted
         *     is true, the client library will provide credentials to the server.
         *     The server will reject the activation request if the indirectly connected
         *     device is not allowed to roam to this gateway device.
         * </p>
         * <p>
         *     Pass {@code false} to allow the indirectly-connected device to be activated
         *     without presenting credentials if the trusted assets of the
         *     indirectly-connected device have not been provisioned to the client.
         *     If restricted is false, the client library will provide
         *     credentials if, and only if, the credentials have been provisioned to the
         *     client. The server will reject the activation if credentials are required
         *     but not supplied, or if the provisioned credentials do not allow the
         *     indirectly connected device to roam to this gateway device.
         * </p>
         * <p>
         *     The hardwareId is a unique identifier within the cloud service
         *     instance and may not be {@code null}. If one is not present for the device,
         *     it should be generated based on other metadata such as: model, manufacturer,
         *     serial number, etc.
         * </p>
         * <p>
         *     The metaData Map should typically contain all the standard
         *     metadata (the constants documented in this class) along with any other
         *     vendor defined metadata.
         * </p>
         * @param restricted indicate whether or not credentials are required for
         *                   activating the indirectly connected device
         * @param hardwareId an identifier unique within the Cloud Service instance
         * @param metaData The metadata of the device
         * @param urns should contain the device model type URNs supported by the indirectly connected device.
         *                The {@code deviceModels} parameter is one or more, comma separated, device model URNs.
         * @return The endpoint id of the indirectly-connected device
         * @throw std::invalid_argument if \a hardwareId or urns is incorrect.
         * @throw CanNotAuthorizeException if there are problems with authorization.
         * @throw GeneralException otherwise.
         */
        std::string registerDevice(const bool restricted,
                const std::string &hardwareId,
                const std::map<std::string, std::string> &metaData,
                const std::initializer_list<std::string> &urns) throw (GeneralException, CanNotAuthorizeException, std::invalid_argument) ;
    };
#endif
};
