/*
 * 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.
 */

#include <AbstractVirtualDevice.hpp>
#include <Data.hpp>

/* include iot cs device model APIs */
#include "iotcs_virtual_device.h"
#include <messaging/DataImpl.hpp>
#include <util/CPPUtils.hpp>
#include <scs/StorageObjectImpl.hpp>

#ifdef __MBED__
#include "mbed.h"
#define dynamic_cast static_cast
#endif

using namespace std;

namespace iotdcl {
    Data::Data(iotcs_virtual_device_handle handle, const string &dataName) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_virtual_device_create_data_handle(handle, dataName.c_str(), &this->handle);
        checkResult(rv);
    }

    Data::~Data() {
        iotcs_virtual_device_free_data_handle(handle);
    }

    template <>
    Data& Data::set(const string &attributeName, const int &value) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_data_set_integer(handle, attributeName.c_str(), value);
        checkResult(rv);
        return *this;
    }

    template <>
    Data& Data::set(const string &attributeName, const float &value) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_data_set_float(handle, attributeName.c_str(), value);
        checkResult(rv);
        return *this;
    }

    template <>
    Data& Data::set(const string &attributeName, const double &value) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_data_set_float(handle, attributeName.c_str(), (float)value);
        checkResult(rv);
        return *this;
    }

    template <>
    Data& Data::set(const string &attributeName, const string &value) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_data_set_string(handle, attributeName.c_str(), value.c_str());
        checkResult(rv);
        return *this;
    }

    template <>
    Data& Data::set(const string &attributeName, const char * const &value) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_data_set_string(handle, attributeName.c_str(), value);
        checkResult(rv);
        return *this;
    }

    template <>
    Data& Data::set(const string &attributeName, const bool &value) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_data_set_boolean(handle, attributeName.c_str(), value ? IOTCS_TRUE : IOTCS_FALSE);
        checkResult(rv);
        return *this;
    }

    template <>
    Data& Data::set(const string &attributeName, const time_t &value) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_data_set_date_time(handle, attributeName.c_str(), (iotcs_date_time) value);
        checkResult(rv);
        return *this;
    }

    template <>
    Data& Data::set(const string &attributeName, const StorageObject& value)  throw(std::invalid_argument) {
        const StorageObjectImpl *ptr(dynamic_cast<const StorageObjectImpl*>(&value));
        iotcs_result rv = IOTCS_RESULT_INVALID_ARGUMENT;
        if (ptr) {
            rv = iotcs_data_set_storage_object(handle, attributeName.c_str(), ptr->c_handler());
        }
        checkResult(rv);
        return *this;
    }

    void Data::submit(void) throw (std::invalid_argument) {
        iotcs_result rv = iotcs_data_submit(handle);
        checkResult(rv);
    }


    Data* DataImpl::createData(iotcs_virtual_device_handle handler, const string &alertName) {
        return new DataImpl(handler, alertName);
    }

    DataImpl::DataImpl(iotcs_virtual_device_handle handler, const string &alertName) : Data(handler, alertName) {

    }
};
