/*
 * 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 "iotcs_virtual_device.h"
#include <string>
#include <stdexcept>

/**
 * @file Data.hpp
 * @brief Represents a set of custom data fields (key/value pair) to be sent to the
 * server. The custom data is sent by calling the
 * submit() method. The time of the data fields are set when
 * submit() is called, allowing {@code submit()} to be called more
 * than once.
 * <p>
 * The set() method returns the #Data instance to allow
 * fields of data to be set in fluent style.
 * @see VirtualDevice::createData(const std::string &)
 */
namespace iotdcl {
    class Data {
    public:
        /**
         * @brief Destructor
         */
        virtual ~Data();
        /**
         * @brief Set the value of a field in the Data. The fields are
         * determined by the format given when the Data is created.
         * The value is validated according to the constraints in the format.
         * If the value is not valid, an IllegalArgumentException is raised.
         * <p>All fields defined in the format that are {@code "optional" : true}
         * must be set before calling submit().</p>
         * @param <T> the type of the value.
         * @param attributeName the name of a field from the custom data format
         * @param value the value to set
         * @return this Data instance
         * @see VirtualDevice::createData(const std::string &)
         * @throw std::invalid_argument if the value is not valid,
          * or attributeName is NULL
         */
        template <typename T> Data& set(const std::string &attributeName, const T& value) throw (std::invalid_argument);
        /**
         * @brief Submit the data. The event time is set when this method is called.
         * <p>
         * The onError handler of the parent virtual device will be called
         * if there is error submiting the custom data fields.
         * <p>All fields defined in the format that are {@code "optional" : true}
         * must be set before calling submit(). If submit() is called
         * before setting all {@code "optional" : true} fields, an std::invalid_argument.</p>
         * @throw std::invalid_argument
         */
        void submit(void) throw (std::invalid_argument);
    protected:
        Data(iotcs_virtual_device_handle handle, const std::string &dataName) throw (std::invalid_argument);
    private:
        Data();
        iotcs_data_handle handle;
    };
};
