// This file is generated by TypeBuilder_cpp.template.

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/devtools/protocol/smart_card_emulation.h"

#include "content/browser/devtools/protocol/protocol.h"

#include "third_party/inspector_protocol/crdtp/cbor.h"
#include "third_party/inspector_protocol/crdtp/find_by_first.h"
#include "third_party/inspector_protocol/crdtp/span.h"

namespace content {
namespace protocol {
namespace SmartCardEmulation {

using crdtp::DeserializerState;
using crdtp::FallthroughCallback;
using crdtp::ProtocolTypeTraits;

// ------------- Enum values from types.

const char Metainfo::domainName[] = "SmartCardEmulation";
const char Metainfo::commandPrefix[] = "SmartCardEmulation.";
const char Metainfo::version[] = "1.3";





CRDTP_BEGIN_DESERIALIZER(ReaderStateFlags)
    CRDTP_DESERIALIZE_FIELD_OPT("changed", m_changed),
    CRDTP_DESERIALIZE_FIELD_OPT("empty", m_empty),
    CRDTP_DESERIALIZE_FIELD_OPT("exclusive", m_exclusive),
    CRDTP_DESERIALIZE_FIELD_OPT("ignore", m_ignore),
    CRDTP_DESERIALIZE_FIELD_OPT("inuse", m_inuse),
    CRDTP_DESERIALIZE_FIELD_OPT("mute", m_mute),
    CRDTP_DESERIALIZE_FIELD_OPT("present", m_present),
    CRDTP_DESERIALIZE_FIELD_OPT("unavailable", m_unavailable),
    CRDTP_DESERIALIZE_FIELD_OPT("unaware", m_unaware),
    CRDTP_DESERIALIZE_FIELD_OPT("unknown", m_unknown),
    CRDTP_DESERIALIZE_FIELD_OPT("unpowered", m_unpowered),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ReaderStateFlags)
    CRDTP_SERIALIZE_FIELD("unaware", m_unaware);
    CRDTP_SERIALIZE_FIELD("ignore", m_ignore);
    CRDTP_SERIALIZE_FIELD("changed", m_changed);
    CRDTP_SERIALIZE_FIELD("unknown", m_unknown);
    CRDTP_SERIALIZE_FIELD("unavailable", m_unavailable);
    CRDTP_SERIALIZE_FIELD("empty", m_empty);
    CRDTP_SERIALIZE_FIELD("present", m_present);
    CRDTP_SERIALIZE_FIELD("exclusive", m_exclusive);
    CRDTP_SERIALIZE_FIELD("inuse", m_inuse);
    CRDTP_SERIALIZE_FIELD("mute", m_mute);
    CRDTP_SERIALIZE_FIELD("unpowered", m_unpowered);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(ProtocolSet)
    CRDTP_DESERIALIZE_FIELD_OPT("raw", m_raw),
    CRDTP_DESERIALIZE_FIELD_OPT("t0", m_t0),
    CRDTP_DESERIALIZE_FIELD_OPT("t1", m_t1),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ProtocolSet)
    CRDTP_SERIALIZE_FIELD("t0", m_t0);
    CRDTP_SERIALIZE_FIELD("t1", m_t1);
    CRDTP_SERIALIZE_FIELD("raw", m_raw);
CRDTP_END_SERIALIZER();



CRDTP_BEGIN_DESERIALIZER(ReaderStateIn)
    CRDTP_DESERIALIZE_FIELD("currentInsertionCount", m_currentInsertionCount),
    CRDTP_DESERIALIZE_FIELD("currentState", m_currentState),
    CRDTP_DESERIALIZE_FIELD("reader", m_reader),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ReaderStateIn)
    CRDTP_SERIALIZE_FIELD("reader", m_reader);
    CRDTP_SERIALIZE_FIELD("currentState", m_currentState);
    CRDTP_SERIALIZE_FIELD("currentInsertionCount", m_currentInsertionCount);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(ReaderStateOut)
    CRDTP_DESERIALIZE_FIELD("atr", m_atr),
    CRDTP_DESERIALIZE_FIELD("eventCount", m_eventCount),
    CRDTP_DESERIALIZE_FIELD("eventState", m_eventState),
    CRDTP_DESERIALIZE_FIELD("reader", m_reader),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ReaderStateOut)
    CRDTP_SERIALIZE_FIELD("reader", m_reader);
    CRDTP_SERIALIZE_FIELD("eventState", m_eventState);
    CRDTP_SERIALIZE_FIELD("eventCount", m_eventCount);
    CRDTP_SERIALIZE_FIELD("atr", m_atr);
CRDTP_END_SERIALIZER();


// ------------- Enum values from params.


// ------------- Frontend notifications.

void Frontend::EstablishContextRequested(const String& requestId)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.establishContextRequested", serializer.Finish()));
}

void Frontend::ReleaseContextRequested(const String& requestId, int contextId)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("contextId"), contextId);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.releaseContextRequested", serializer.Finish()));
}

void Frontend::ListReadersRequested(const String& requestId, int contextId)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("contextId"), contextId);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.listReadersRequested", serializer.Finish()));
}

void Frontend::GetStatusChangeRequested(const String& requestId, int contextId, std::unique_ptr<protocol::Array<protocol::SmartCardEmulation::ReaderStateIn>> readerStates, std::optional<int> timeout)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("contextId"), contextId);
    serializer.AddField(crdtp::MakeSpan("readerStates"), readerStates);
    serializer.AddField(crdtp::MakeSpan("timeout"), timeout);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.getStatusChangeRequested", serializer.Finish()));
}

void Frontend::CancelRequested(const String& requestId, int contextId)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("contextId"), contextId);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.cancelRequested", serializer.Finish()));
}

void Frontend::ConnectRequested(const String& requestId, int contextId, const String& reader, const String& shareMode, std::unique_ptr<protocol::SmartCardEmulation::ProtocolSet> preferredProtocols)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("contextId"), contextId);
    serializer.AddField(crdtp::MakeSpan("reader"), reader);
    serializer.AddField(crdtp::MakeSpan("shareMode"), shareMode);
    serializer.AddField(crdtp::MakeSpan("preferredProtocols"), preferredProtocols);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.connectRequested", serializer.Finish()));
}

void Frontend::DisconnectRequested(const String& requestId, int handle, const String& disposition)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("handle"), handle);
    serializer.AddField(crdtp::MakeSpan("disposition"), disposition);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.disconnectRequested", serializer.Finish()));
}

void Frontend::TransmitRequested(const String& requestId, int handle, const Binary& data, std::optional<String> protocol)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("handle"), handle);
    serializer.AddField(crdtp::MakeSpan("data"), data);
    serializer.AddField(crdtp::MakeSpan("protocol"), protocol);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.transmitRequested", serializer.Finish()));
}

void Frontend::ControlRequested(const String& requestId, int handle, int controlCode, const Binary& data)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("handle"), handle);
    serializer.AddField(crdtp::MakeSpan("controlCode"), controlCode);
    serializer.AddField(crdtp::MakeSpan("data"), data);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.controlRequested", serializer.Finish()));
}

void Frontend::GetAttribRequested(const String& requestId, int handle, int attribId)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("handle"), handle);
    serializer.AddField(crdtp::MakeSpan("attribId"), attribId);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.getAttribRequested", serializer.Finish()));
}

void Frontend::SetAttribRequested(const String& requestId, int handle, int attribId, const Binary& data)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("handle"), handle);
    serializer.AddField(crdtp::MakeSpan("attribId"), attribId);
    serializer.AddField(crdtp::MakeSpan("data"), data);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.setAttribRequested", serializer.Finish()));
}

void Frontend::StatusRequested(const String& requestId, int handle)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("handle"), handle);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.statusRequested", serializer.Finish()));
}

void Frontend::BeginTransactionRequested(const String& requestId, int handle)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("handle"), handle);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.beginTransactionRequested", serializer.Finish()));
}

void Frontend::EndTransactionRequested(const String& requestId, int handle, const String& disposition)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("handle"), handle);
    serializer.AddField(crdtp::MakeSpan("disposition"), disposition);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("SmartCardEmulation.endTransactionRequested", serializer.Finish()));
}

void Frontend::flush()
{
    frontend_channel_->FlushProtocolNotifications();
}

void Frontend::sendRawNotification(std::unique_ptr<Serializable> notification)
{
    frontend_channel_->SendProtocolNotification(std::move(notification));
}

// --------------------- Dispatcher.

class DomainDispatcherImpl : public protocol::DomainDispatcher {
public:
    DomainDispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
        : DomainDispatcher(frontendChannel)
        , m_backend(backend) {}
    ~DomainDispatcherImpl() override { }

    using CallHandler = void (DomainDispatcherImpl::*)(crdtp::Dispatchable& dispatchable);

    bool Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) override;

    void enable(crdtp::Dispatchable& dispatchable);
    void disable(crdtp::Dispatchable& dispatchable);
    void reportEstablishContextResult(crdtp::Dispatchable& dispatchable);
    void reportReleaseContextResult(crdtp::Dispatchable& dispatchable);
    void reportListReadersResult(crdtp::Dispatchable& dispatchable);
    void reportGetStatusChangeResult(crdtp::Dispatchable& dispatchable);
    void reportBeginTransactionResult(crdtp::Dispatchable& dispatchable);
    void reportPlainResult(crdtp::Dispatchable& dispatchable);
    void reportConnectResult(crdtp::Dispatchable& dispatchable);
    void reportDataResult(crdtp::Dispatchable& dispatchable);
    void reportStatusResult(crdtp::Dispatchable& dispatchable);
    void reportError(crdtp::Dispatchable& dispatchable);
 protected:
    Backend* m_backend;
};

namespace {
// This helper method with a static map of command methods (instance methods
// of DomainDispatcherImpl declared just above) by their name is used immediately below,
// in the DomainDispatcherImpl::Dispatch method.
DomainDispatcherImpl::CallHandler CommandByName(crdtp::span<uint8_t> command_name) {
  static auto* commands = [](){
    auto* commands = new std::vector<std::pair<crdtp::span<uint8_t>,
                              DomainDispatcherImpl::CallHandler>>{
    {
          crdtp::SpanFrom("disable"),
          &DomainDispatcherImpl::disable
    },
    {
          crdtp::SpanFrom("enable"),
          &DomainDispatcherImpl::enable
    },
    {
          crdtp::SpanFrom("reportBeginTransactionResult"),
          &DomainDispatcherImpl::reportBeginTransactionResult
    },
    {
          crdtp::SpanFrom("reportConnectResult"),
          &DomainDispatcherImpl::reportConnectResult
    },
    {
          crdtp::SpanFrom("reportDataResult"),
          &DomainDispatcherImpl::reportDataResult
    },
    {
          crdtp::SpanFrom("reportError"),
          &DomainDispatcherImpl::reportError
    },
    {
          crdtp::SpanFrom("reportEstablishContextResult"),
          &DomainDispatcherImpl::reportEstablishContextResult
    },
    {
          crdtp::SpanFrom("reportGetStatusChangeResult"),
          &DomainDispatcherImpl::reportGetStatusChangeResult
    },
    {
          crdtp::SpanFrom("reportListReadersResult"),
          &DomainDispatcherImpl::reportListReadersResult
    },
    {
          crdtp::SpanFrom("reportPlainResult"),
          &DomainDispatcherImpl::reportPlainResult
    },
    {
          crdtp::SpanFrom("reportReleaseContextResult"),
          &DomainDispatcherImpl::reportReleaseContextResult
    },
    {
          crdtp::SpanFrom("reportStatusResult"),
          &DomainDispatcherImpl::reportStatusResult
    },
    };
    return commands;
  }();
  return crdtp::FindByFirst<DomainDispatcherImpl::CallHandler>(*commands, command_name, nullptr);
}
}  // namespace

bool DomainDispatcherImpl::Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) {
  CallHandler handler = CommandByName(command_name);
  if (!handler) return false;

  (this->*handler)(dispatchable);
  return true;
}


namespace {


}  // namespace

void DomainDispatcherImpl::enable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->Enable();
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {


}  // namespace

void DomainDispatcherImpl::disable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->Disable();
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportEstablishContextResultParams : public crdtp::DeserializableProtocolObject<reportEstablishContextResultParams> {
    String requestId;
    int contextId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportEstablishContextResultParams)
    CRDTP_DESERIALIZE_FIELD("contextId", contextId),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportEstablishContextResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportEstablishContextResultParams params;
    if (!reportEstablishContextResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportEstablishContextResult(params.requestId, params.contextId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportReleaseContextResultParams : public crdtp::DeserializableProtocolObject<reportReleaseContextResultParams> {
    String requestId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportReleaseContextResultParams)
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportReleaseContextResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportReleaseContextResultParams params;
    if (!reportReleaseContextResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportReleaseContextResult(params.requestId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportListReadersResultParams : public crdtp::DeserializableProtocolObject<reportListReadersResultParams> {
    String requestId;
    std::unique_ptr<protocol::Array<String>> readers;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportListReadersResultParams)
    CRDTP_DESERIALIZE_FIELD("readers", readers),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportListReadersResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportListReadersResultParams params;
    if (!reportListReadersResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportListReadersResult(params.requestId, std::move(params.readers));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportGetStatusChangeResultParams : public crdtp::DeserializableProtocolObject<reportGetStatusChangeResultParams> {
    String requestId;
    std::unique_ptr<protocol::Array<protocol::SmartCardEmulation::ReaderStateOut>> readerStates;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportGetStatusChangeResultParams)
    CRDTP_DESERIALIZE_FIELD("readerStates", readerStates),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportGetStatusChangeResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportGetStatusChangeResultParams params;
    if (!reportGetStatusChangeResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportGetStatusChangeResult(params.requestId, std::move(params.readerStates));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportBeginTransactionResultParams : public crdtp::DeserializableProtocolObject<reportBeginTransactionResultParams> {
    String requestId;
    int handle;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportBeginTransactionResultParams)
    CRDTP_DESERIALIZE_FIELD("handle", handle),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportBeginTransactionResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportBeginTransactionResultParams params;
    if (!reportBeginTransactionResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportBeginTransactionResult(params.requestId, params.handle);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportPlainResultParams : public crdtp::DeserializableProtocolObject<reportPlainResultParams> {
    String requestId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportPlainResultParams)
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportPlainResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportPlainResultParams params;
    if (!reportPlainResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportPlainResult(params.requestId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportConnectResultParams : public crdtp::DeserializableProtocolObject<reportConnectResultParams> {
    String requestId;
    int handle;
    std::optional<String> activeProtocol;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportConnectResultParams)
    CRDTP_DESERIALIZE_FIELD_OPT("activeProtocol", activeProtocol),
    CRDTP_DESERIALIZE_FIELD("handle", handle),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportConnectResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportConnectResultParams params;
    if (!reportConnectResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportConnectResult(params.requestId, params.handle, std::move(params.activeProtocol));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportDataResultParams : public crdtp::DeserializableProtocolObject<reportDataResultParams> {
    String requestId;
    Binary data;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportDataResultParams)
    CRDTP_DESERIALIZE_FIELD("data", data),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportDataResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportDataResultParams params;
    if (!reportDataResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportDataResult(params.requestId, params.data);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportStatusResultParams : public crdtp::DeserializableProtocolObject<reportStatusResultParams> {
    String requestId;
    String readerName;
    String state;
    Binary atr;
    std::optional<String> protocol;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportStatusResultParams)
    CRDTP_DESERIALIZE_FIELD("atr", atr),
    CRDTP_DESERIALIZE_FIELD_OPT("protocol", protocol),
    CRDTP_DESERIALIZE_FIELD("readerName", readerName),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
    CRDTP_DESERIALIZE_FIELD("state", state),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportStatusResult(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportStatusResultParams params;
    if (!reportStatusResultParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportStatusResult(params.requestId, params.readerName, params.state, params.atr, std::move(params.protocol));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct reportErrorParams : public crdtp::DeserializableProtocolObject<reportErrorParams> {
    String requestId;
    String resultCode;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(reportErrorParams)
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
    CRDTP_DESERIALIZE_FIELD("resultCode", resultCode),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::reportError(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    reportErrorParams params;
    if (!reportErrorParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ReportError(params.requestId, params.resultCode);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {
// This helper method (with a static map of redirects) is used from Dispatcher::wire
// immediately below.
const std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>& SortedRedirects() {
  static auto* redirects = [](){
    auto* redirects = new std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>{
    };
    return redirects;
  }();
  return *redirects;
}
}  // namespace

// static
void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
{
    auto dispatcher = std::make_unique<DomainDispatcherImpl>(uber->channel(), backend);
    uber->WireBackend(crdtp::SpanFrom("SmartCardEmulation"), SortedRedirects(), std::move(dispatcher));
}

} // SmartCardEmulation
} // namespace content
} // namespace protocol
