/*
 * 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 <DirectlyConnectedDevice.hpp>
#include <DeviceModel.hpp>
#include <VirtualDevice.hpp>
#include <Exception.hpp>
#include "iotcs_virtual_device.h"
#include "iotcs_device.h"
#include <device_model/DeviceModelImpl.hpp>
#include <scs/StorageObjectImpl.hpp>
#include <iotcs/VirtualDeviceImpl.hpp>
#include <util/CPPUtils.hpp>
#include <string>
#include <vector>
#include <utility>
#include <memory>
#include <initializer_list>

namespace iotdcl {
    DirectlyConnectedDevice::DirectlyConnectedDevice(const std::string &filePath, const std::string &password) throw (GeneralException, std::invalid_argument) {
        iotcs_result rv = iotcs_init(filePath.c_str(), password.c_str());
        if (isActivated()) {
            endpointId = std::string(iotcs_get_endpoint_id());
        }
        checkResult(rv);
    }

    DirectlyConnectedDevice::~DirectlyConnectedDevice() {
        std::for_each(vd_list.begin(), vd_list.end(), delete_pointer_element<VirtualDevice*>());
        std::for_each(dm_list.begin(), dm_list.end(), delete_pointer_element<DeviceModel*>());
        std::for_each(eo_list.begin(), eo_list.end(), delete_pointer_element<StorageObject*>());
        vd_list.clear();
        dm_list.clear();
        eo_list.clear();
        iotcs_finalize();
    }

    const std::string& DirectlyConnectedDevice::getEndpointId(void) const {
        return endpointId;
    }

    bool DirectlyConnectedDevice::isActivated() {
        return (bool)iotcs_is_activated();
    }

    void DirectlyConnectedDevice::activate(const std::initializer_list<std::string> &deviceModelUrls) throw (GeneralException, CanNotAuthorizeException, std::invalid_argument) {
        std::vector<std::string> urns(deviceModelUrls);
        const char **device_models = new const char*[urns.size() + 1];

        for (int i = 0; i < urns.size(); i++) {
            device_models[i] = urns[i].c_str();
        }
        device_models[urns.size()] = NULL;
        iotcs_result rv = iotcs_activate(device_models);
        delete[] device_models;
        endpointId = std::string(iotcs_get_endpoint_id());
        checkResult(rv);
    }

    DeviceModel& DirectlyConnectedDevice::getDeviceModel(const std::string &deviceModelUrl) throw (GeneralException, CanNotAuthorizeException, std::invalid_argument) {
        DeviceModel* result = new DeviceModelImpl(deviceModelUrl);
        dm_list.push_back(result);
        return *result;
    }

    VirtualDevice& DirectlyConnectedDevice::createVirtualDevice(const std::string &endpointId, DeviceModel &model) throw (GeneralException, CanNotAuthorizeException, std::invalid_argument) {
        VirtualDevice* result = new VirtualDeviceImpl(endpointId, static_cast<DeviceModelImpl&> (model));
        vd_list.push_back(result);
        return *result;
    }

    StorageObject& DirectlyConnectedDevice::createStorageObject(const std::string &name, const std::string &contentType) throw (GeneralException, CanNotAuthorizeException) {
        StorageObject* result = new StorageObjectImpl(name, contentType);
        eo_list.push_back(result);
        return *result;
    }

    StorageObject& DirectlyConnectedDevice::createStorageObject(const std::string &uri) throw (GeneralException, CanNotAuthorizeException) {
        StorageObject* result = new StorageObjectImpl(uri);
        eo_list.push_back(result);
        return *result;
    }
};
