/*
   Copyright (c) 2018-2019 Nokia.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <sstream>
#include <sys/poll.h>
#include <sdl/asyncstorage.hpp>
#include <sdl/backenderror.hpp>
#include <sdl/errorqueries.hpp>
#include <sdl/invalidnamespace.hpp>
#include <sdl/notconnected.hpp>
#include <sdl/operationinterrupted.hpp>
#include <sdl/rejectedbybackend.hpp>
#include <sdl/rejectedbysdl.hpp>
#include "private/redis/asyncredisstorage.hpp"
#include "private/syncstorageimpl.hpp"
#include "private/system.hpp"

using namespace shareddatalayer;

namespace
{
    void throwExceptionForErrorCode[[ noreturn ]](const std::error_code& ec)
    {
        if (ec == shareddatalayer::Error::BACKEND_FAILURE)
            throw BackendError(ec.message());
        else if (ec == shareddatalayer::Error::NOT_CONNECTED)
            throw NotConnected(ec.message());
        else if (ec == shareddatalayer::Error::OPERATION_INTERRUPTED)
            throw OperationInterrupted(ec.message());
        else if (ec == shareddatalayer::Error::REJECTED_BY_BACKEND)
            throw RejectedByBackend(ec.message());
        else if (ec == AsyncRedisStorage::ErrorCode::INVALID_NAMESPACE)
            throw InvalidNamespace(ec.message());
        else if (ec == shareddatalayer::Error::REJECTED_BY_SDL)
            throw RejectedBySdl(ec.message());

        std::ostringstream os;
        os << "No corresponding SDL exception found for error code: " << ec.category().name() << " " << ec.value();
        throw std::range_error(os.str());
    }
}

SyncStorageImpl::SyncStorageImpl(std::unique_ptr<AsyncStorage> asyncStorage):
    SyncStorageImpl(std::move(asyncStorage), System::getSystem())
{
}

SyncStorageImpl::SyncStorageImpl(std::unique_ptr<AsyncStorage> pAsyncStorage,
                                 System& system):
    asyncStorage(std::move(pAsyncStorage)),
    system(system),
    pFd(asyncStorage->fd()),
    localStatus(false),
    synced(false)
{
}

void SyncStorageImpl::modifyAck(const std::error_code& error)
{
    synced = true;
    localError = error;
}

void SyncStorageImpl::modifyIfAck(const std::error_code& error, bool status)
{
    synced = true;
    localError = error;
    localStatus = status;
}

void SyncStorageImpl::getAck(const std::error_code& error, const DataMap& dataMap)
{
    synced = true;
    localError = error;
    localMap = dataMap;
}

void SyncStorageImpl::findKeysAck(const std::error_code& error, const Keys& keys)
{
    synced = true;
    localError = error;
    localKeys = keys;
}

void SyncStorageImpl::verifyBackendResponse()
{
    if(localError)
        throwExceptionForErrorCode(localError);
}

void SyncStorageImpl::waitForCallback()
{
    struct pollfd events { pFd, POLLIN, 0 };
    while(!synced)
        if (system.poll(&events, 1, -1) > 0 && (events.revents & POLLIN))
            asyncStorage->handleEvents();
}

void SyncStorageImpl::waitSdlToBeReady(const Namespace& ns)
{
    synced = false;
    asyncStorage->waitReadyAsync(ns,
                                 std::bind(&shareddatalayer::SyncStorageImpl::modifyAck,
                                           this,
                                           std::error_code()));
    waitForCallback();
    verifyBackendResponse();
}

void SyncStorageImpl::set(const Namespace& ns, const DataMap& dataMap)
{
    waitSdlToBeReady(ns);
    synced = false;
    asyncStorage->setAsync(ns,
                           dataMap,
                           std::bind(&shareddatalayer::SyncStorageImpl::modifyAck,
                                     this,
                                     std::placeholders::_1));
    waitForCallback();
    verifyBackendResponse();
}

bool SyncStorageImpl::setIf(const Namespace& ns, const Key& key, const Data& oldData, const Data& newData)
{
    waitSdlToBeReady(ns);
    synced = false;
    asyncStorage->setIfAsync(ns,
                             key,
                             oldData,
                             newData,
                             std::bind(&shareddatalayer::SyncStorageImpl::modifyIfAck,
                                       this,
                                       std::placeholders::_1,
                                       std::placeholders::_2));
    waitForCallback();
    verifyBackendResponse();
    return localStatus;
}

bool SyncStorageImpl::setIfNotExists(const Namespace& ns, const Key& key, const Data& data)
{
    waitSdlToBeReady(ns);
    synced = false;
    asyncStorage->setIfNotExistsAsync(ns,
                                      key,
                                      data,
                                      std::bind(&shareddatalayer::SyncStorageImpl::modifyIfAck,
                                                this,
                                                std::placeholders::_1,
                                                std::placeholders::_2));
    waitForCallback();
    verifyBackendResponse();
    return localStatus;
}

SyncStorageImpl::DataMap SyncStorageImpl::get(const Namespace& ns, const Keys& keys)
{
    waitSdlToBeReady(ns);
    synced = false;
    asyncStorage->getAsync(ns,
                           keys,
                           std::bind(&shareddatalayer::SyncStorageImpl::getAck,
                                     this,
                                     std::placeholders::_1,
                                     std::placeholders::_2));
    waitForCallback();
    verifyBackendResponse();
    return localMap;
}

void SyncStorageImpl::remove(const Namespace& ns, const Keys& keys)
{
    waitSdlToBeReady(ns);
    synced = false;
    asyncStorage->removeAsync(ns,
                              keys,
                              std::bind(&shareddatalayer::SyncStorageImpl::modifyAck,
                                        this,
                                        std::placeholders::_1));
    waitForCallback();
    verifyBackendResponse();
}

bool SyncStorageImpl::removeIf(const Namespace& ns, const Key& key, const Data& data)
{
    waitSdlToBeReady(ns);
    synced = false;
    asyncStorage->removeIfAsync(ns,
                                key,
                                data,
                                std::bind(&shareddatalayer::SyncStorageImpl::modifyIfAck,
                                          this,
                                          std::placeholders::_1,
                                          std::placeholders::_2));
    waitForCallback();
    verifyBackendResponse();
    return localStatus;
}

SyncStorageImpl::Keys SyncStorageImpl::findKeys(const Namespace& ns, const std::string& keyPrefix)
{
    waitSdlToBeReady(ns);
    synced = false;
    asyncStorage->findKeysAsync(ns,
                                keyPrefix,
                                std::bind(&shareddatalayer::SyncStorageImpl::findKeysAck,
                                          this,
                                          std::placeholders::_1,
                                          std::placeholders::_2));
    waitForCallback();
    verifyBackendResponse();
    return localKeys;
}

void SyncStorageImpl::removeAll(const Namespace& ns)
{
    waitSdlToBeReady(ns);
    synced = false;
    asyncStorage->removeAllAsync(ns,
                                 std::bind(&shareddatalayer::SyncStorageImpl::modifyAck,
                                           this,
                                           std::placeholders::_1));
    waitForCallback();
    verifyBackendResponse();
}
