/*
 * 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 <string>
#include "ExternalObject.hpp"
#include "StorageObject.hpp"
#include "iotcs_storage_object.h"
#include <util/CPPUtils.hpp>
#include <device_model/ChangeEventImpl.hpp>
#include <scs/StorageObjectImpl.hpp>

#ifdef __MBED__
#include "mbed.h"
#endif

using namespace std;

namespace iotdcl {
    static std::string emptyString = "";

    StorageObject::~StorageObject() {
        if (storage_object_handle) {
            iotcs_free_storage_object_handle(storage_object_handle);
            storage_object_handle = NULL;
        }
        if (name) {
            delete name;
        }
        if (outPath) {
            delete outPath;
        }
        if (inPath) {
            delete inPath;
        }
        if (type) {
            delete type;
        }
        if (encoding) {
            delete encoding;
        }
    }

    const std::string& StorageObject::getName() const {
        return *name;
    }

    const std::string& StorageObject::getType() const {
        return *type;
    }

    const std::string& StorageObject::getEncoding() const {
        if (encoding) {
            return *encoding;
        }
        return emptyString;
    }

    long StorageObject::getLength() const {
        return iotcs_storage_object_get_length(storage_object_handle);
    }

    time_t StorageObject::getDate() const {
        return iotcs_storage_object_get_date(storage_object_handle);
        
    }

    SyncStatus StorageObject::getSyncStatus() const {
        iotcs_storage_object_sync_status status = iotcs_storage_object_get_sync_status(storage_object_handle);

        switch (status) {
            case IOTCS_IN_SYNC:
                return IN_SYNC;
                break;
            case IOTCS_NOT_IN_SYNC:
                return NOT_IN_SYNC;
                break;
            case IOTCS_SYNC_FAILED:
                return SYNC_FAILED;
                break;
            case IOTCS_SYNC_PENDING:
                return SYNC_PENDING;
                break;
            default:
                return NOT_IN_SYNC;
                break;
        }
    }

    const std::string& StorageObject::getInputPath() const {
        if (inPath) {
            return *inPath;
        }
        return emptyString;
    }

    void StorageObject::setInputPath(const std::string& inputPath) throw (GeneralException, std::invalid_argument) {
        inPath = new std::string(inputPath);
        checkResult(iotcs_storage_object_set_input_path(storage_object_handle, inputPath.c_str()),
                    "Can not set input path to storage object");
    }

    const std::string& StorageObject::getOutputPath() const {
        if (outPath) {
            return *outPath;
        }
        return emptyString;
    }

    void StorageObject::setOutputPath(const std::string& outputPath) throw (GeneralException, std::invalid_argument) {
        outPath = new std::string(outputPath);
        checkResult(iotcs_storage_object_set_output_path(storage_object_handle, outputPath.c_str()),
                    "Can not set output path to storage object");

    }

    void StorageObject::sync() throw (GeneralException, std::invalid_argument) {
        checkResult(iotcs_storage_object_sync(storage_object_handle),
                    "Syncronization failed");
    }

    void StorageObject::setOnSync(const SyncCallback *callback) {
        StorageObjectImpl::mapMutex.lock();
        StorageObjectImpl::globalOnSyncCallbacks[storage_object_handle] = callback;
        StorageObjectImpl::mapMutex.unlock();
    }

    void StorageObject::setVirtualDevice(VirtualDevice *vd) {
        this->vd = vd;
    }

    iotcs_storage_object_handle StorageObject::c_handler() const {
        return this->storage_object_handle;
    }
};
