/**
 * @file clprotoHandshakeResponseHandler.h
 * @author Bartek Kryza
 * @copyright (C) 2018 ACK CYFRONET AGH
 * @copyright This software is released under the MIT license cited in
 * 'LICENSE.txt'
 */

#pragma once

#include <folly/io/Cursor.h>
#include <wangle/channel/Handler.h>

namespace one {
namespace communication {
namespace codec {

/**
 * @c CLProtoHandshakeResponseHandler is responsible for awaiting on a clproto
 * handshake response message from the server.
 */
class CLProtoHandshakeResponseHandler
    : public wangle::InboundHandler<std::string> {
public:
    CLProtoHandshakeResponseHandler(std::function<std::string()> getHandshake,
        std::function<std::error_code(std::string)> onHandshakeResponse,
        std::function<void(std::error_code)> onHandshakeDone)
        : m_getHandshake{std::move(getHandshake)}
        , m_onHandshakeResponse{std::move(onHandshakeResponse)}
        , m_onHandshakeDone{std::move(onHandshakeDone)}
    {
    }

    void read(Context *ctx, std::string message) override
    {
        LOG_DBG(1) << "Received clproto handshake response";

        if (m_promise.isFulfilled()) {
            ctx->fireRead(std::move(message));
            return;
        }

        auto handshakeResponseError = m_onHandshakeResponse(message);
        if (!handshakeResponseError) {
            m_onHandshakeDone(std::error_code{});
            m_promise.setValue();
        }
        else {
            LOG(ERROR) << "Error during handshake: " << handshakeResponseError;
            m_onHandshakeDone(handshakeResponseError);
            m_promise.setException(
                std::runtime_error("Error during handshake."));
            return;
        }
        ctx->fireRead(std::move(message));
    }

    folly::Future<folly::Unit> done() { return m_promise.getFuture(); }

    std::string getHandshake() { return m_getHandshake(); }

private:
    folly::Promise<folly::Unit> m_promise;
    std::function<std::string()> m_getHandshake;
    std::function<std::error_code(std::string)> m_onHandshakeResponse;
    std::function<void(std::error_code)> m_onHandshakeDone;
};
} // namespace codec
} // namespace communication
} // namespace one
