// 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/bluetooth_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 BluetoothEmulation {

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

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

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






CRDTP_BEGIN_DESERIALIZER(ManufacturerData)
    CRDTP_DESERIALIZE_FIELD("data", m_data),
    CRDTP_DESERIALIZE_FIELD("key", m_key),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ManufacturerData)
    CRDTP_SERIALIZE_FIELD("key", m_key);
    CRDTP_SERIALIZE_FIELD("data", m_data);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(ScanRecord)
    CRDTP_DESERIALIZE_FIELD_OPT("appearance", m_appearance),
    CRDTP_DESERIALIZE_FIELD_OPT("manufacturerData", m_manufacturerData),
    CRDTP_DESERIALIZE_FIELD_OPT("name", m_name),
    CRDTP_DESERIALIZE_FIELD_OPT("txPower", m_txPower),
    CRDTP_DESERIALIZE_FIELD_OPT("uuids", m_uuids),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ScanRecord)
    CRDTP_SERIALIZE_FIELD("name", m_name);
    CRDTP_SERIALIZE_FIELD("uuids", m_uuids);
    CRDTP_SERIALIZE_FIELD("appearance", m_appearance);
    CRDTP_SERIALIZE_FIELD("txPower", m_txPower);
    CRDTP_SERIALIZE_FIELD("manufacturerData", m_manufacturerData);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(ScanEntry)
    CRDTP_DESERIALIZE_FIELD("deviceAddress", m_deviceAddress),
    CRDTP_DESERIALIZE_FIELD("rssi", m_rssi),
    CRDTP_DESERIALIZE_FIELD("scanRecord", m_scanRecord),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ScanEntry)
    CRDTP_SERIALIZE_FIELD("deviceAddress", m_deviceAddress);
    CRDTP_SERIALIZE_FIELD("rssi", m_rssi);
    CRDTP_SERIALIZE_FIELD("scanRecord", m_scanRecord);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(CharacteristicProperties)
    CRDTP_DESERIALIZE_FIELD_OPT("authenticatedSignedWrites", m_authenticatedSignedWrites),
    CRDTP_DESERIALIZE_FIELD_OPT("broadcast", m_broadcast),
    CRDTP_DESERIALIZE_FIELD_OPT("extendedProperties", m_extendedProperties),
    CRDTP_DESERIALIZE_FIELD_OPT("indicate", m_indicate),
    CRDTP_DESERIALIZE_FIELD_OPT("notify", m_notify),
    CRDTP_DESERIALIZE_FIELD_OPT("read", m_read),
    CRDTP_DESERIALIZE_FIELD_OPT("write", m_write),
    CRDTP_DESERIALIZE_FIELD_OPT("writeWithoutResponse", m_writeWithoutResponse),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(CharacteristicProperties)
    CRDTP_SERIALIZE_FIELD("broadcast", m_broadcast);
    CRDTP_SERIALIZE_FIELD("read", m_read);
    CRDTP_SERIALIZE_FIELD("writeWithoutResponse", m_writeWithoutResponse);
    CRDTP_SERIALIZE_FIELD("write", m_write);
    CRDTP_SERIALIZE_FIELD("notify", m_notify);
    CRDTP_SERIALIZE_FIELD("indicate", m_indicate);
    CRDTP_SERIALIZE_FIELD("authenticatedSignedWrites", m_authenticatedSignedWrites);
    CRDTP_SERIALIZE_FIELD("extendedProperties", m_extendedProperties);
CRDTP_END_SERIALIZER();


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


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

void Frontend::GattOperationReceived(const String& address, const String& type)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("address"), address);
    serializer.AddField(crdtp::MakeSpan("type"), type);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("BluetoothEmulation.gattOperationReceived", serializer.Finish()));
}

void Frontend::CharacteristicOperationReceived(const String& characteristicId, const String& type, std::optional<Binary> data, std::optional<String> writeType)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("characteristicId"), characteristicId);
    serializer.AddField(crdtp::MakeSpan("type"), type);
    serializer.AddField(crdtp::MakeSpan("data"), data);
    serializer.AddField(crdtp::MakeSpan("writeType"), writeType);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("BluetoothEmulation.characteristicOperationReceived", serializer.Finish()));
}

void Frontend::DescriptorOperationReceived(const String& descriptorId, const String& type, std::optional<Binary> data)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("descriptorId"), descriptorId);
    serializer.AddField(crdtp::MakeSpan("type"), type);
    serializer.AddField(crdtp::MakeSpan("data"), data);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("BluetoothEmulation.descriptorOperationReceived", 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 setSimulatedCentralState(crdtp::Dispatchable& dispatchable);
    void disable(crdtp::Dispatchable& dispatchable);
    void simulatePreconnectedPeripheral(crdtp::Dispatchable& dispatchable);
    void simulateAdvertisement(crdtp::Dispatchable& dispatchable);
    void simulateGATTOperationResponse(crdtp::Dispatchable& dispatchable);
    void simulateCharacteristicOperationResponse(crdtp::Dispatchable& dispatchable);
    void simulateDescriptorOperationResponse(crdtp::Dispatchable& dispatchable);
    void addService(crdtp::Dispatchable& dispatchable);
    void removeService(crdtp::Dispatchable& dispatchable);
    void addCharacteristic(crdtp::Dispatchable& dispatchable);
    void removeCharacteristic(crdtp::Dispatchable& dispatchable);
    void addDescriptor(crdtp::Dispatchable& dispatchable);
    void removeDescriptor(crdtp::Dispatchable& dispatchable);
    void simulateGATTDisconnection(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("addCharacteristic"),
          &DomainDispatcherImpl::addCharacteristic
    },
    {
          crdtp::SpanFrom("addDescriptor"),
          &DomainDispatcherImpl::addDescriptor
    },
    {
          crdtp::SpanFrom("addService"),
          &DomainDispatcherImpl::addService
    },
    {
          crdtp::SpanFrom("disable"),
          &DomainDispatcherImpl::disable
    },
    {
          crdtp::SpanFrom("enable"),
          &DomainDispatcherImpl::enable
    },
    {
          crdtp::SpanFrom("removeCharacteristic"),
          &DomainDispatcherImpl::removeCharacteristic
    },
    {
          crdtp::SpanFrom("removeDescriptor"),
          &DomainDispatcherImpl::removeDescriptor
    },
    {
          crdtp::SpanFrom("removeService"),
          &DomainDispatcherImpl::removeService
    },
    {
          crdtp::SpanFrom("setSimulatedCentralState"),
          &DomainDispatcherImpl::setSimulatedCentralState
    },
    {
          crdtp::SpanFrom("simulateAdvertisement"),
          &DomainDispatcherImpl::simulateAdvertisement
    },
    {
          crdtp::SpanFrom("simulateCharacteristicOperationResponse"),
          &DomainDispatcherImpl::simulateCharacteristicOperationResponse
    },
    {
          crdtp::SpanFrom("simulateDescriptorOperationResponse"),
          &DomainDispatcherImpl::simulateDescriptorOperationResponse
    },
    {
          crdtp::SpanFrom("simulateGATTDisconnection"),
          &DomainDispatcherImpl::simulateGATTDisconnection
    },
    {
          crdtp::SpanFrom("simulateGATTOperationResponse"),
          &DomainDispatcherImpl::simulateGATTOperationResponse
    },
    {
          crdtp::SpanFrom("simulatePreconnectedPeripheral"),
          &DomainDispatcherImpl::simulatePreconnectedPeripheral
    },
    };
    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 {

struct enableParams : public crdtp::DeserializableProtocolObject<enableParams> {
    String state;
    bool leSupported;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(enableParams)
    CRDTP_DESERIALIZE_FIELD("leSupported", leSupported),
    CRDTP_DESERIALIZE_FIELD("state", state),
CRDTP_END_DESERIALIZER()

}  // namespace

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

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

class SetSimulatedCentralStateCallbackImpl : public Backend::SetSimulatedCentralStateCallback, public DomainDispatcher::Callback {
public:
    SetSimulatedCentralStateCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.setSimulatedCentralState")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct setSimulatedCentralStateParams : public crdtp::DeserializableProtocolObject<setSimulatedCentralStateParams> {
    String state;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(setSimulatedCentralStateParams)
    CRDTP_DESERIALIZE_FIELD("state", state),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->SetSimulatedCentralState(params.state, std::make_unique<SetSimulatedCentralStateCallbackImpl>(weakPtr(), dispatchable));
}

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;
}

class SimulatePreconnectedPeripheralCallbackImpl : public Backend::SimulatePreconnectedPeripheralCallback, public DomainDispatcher::Callback {
public:
    SimulatePreconnectedPeripheralCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.simulatePreconnectedPeripheral")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct simulatePreconnectedPeripheralParams : public crdtp::DeserializableProtocolObject<simulatePreconnectedPeripheralParams> {
    String address;
    String name;
    std::unique_ptr<protocol::Array<protocol::BluetoothEmulation::ManufacturerData>> manufacturerData;
    std::unique_ptr<protocol::Array<String>> knownServiceUuids;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(simulatePreconnectedPeripheralParams)
    CRDTP_DESERIALIZE_FIELD("address", address),
    CRDTP_DESERIALIZE_FIELD("knownServiceUuids", knownServiceUuids),
    CRDTP_DESERIALIZE_FIELD("manufacturerData", manufacturerData),
    CRDTP_DESERIALIZE_FIELD("name", name),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->SimulatePreconnectedPeripheral(params.address, params.name, std::move(params.manufacturerData), std::move(params.knownServiceUuids), std::make_unique<SimulatePreconnectedPeripheralCallbackImpl>(weakPtr(), dispatchable));
}

class SimulateAdvertisementCallbackImpl : public Backend::SimulateAdvertisementCallback, public DomainDispatcher::Callback {
public:
    SimulateAdvertisementCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.simulateAdvertisement")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct simulateAdvertisementParams : public crdtp::DeserializableProtocolObject<simulateAdvertisementParams> {
    std::unique_ptr<protocol::BluetoothEmulation::ScanEntry> entry;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(simulateAdvertisementParams)
    CRDTP_DESERIALIZE_FIELD("entry", entry),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->SimulateAdvertisement(std::move(params.entry), std::make_unique<SimulateAdvertisementCallbackImpl>(weakPtr(), dispatchable));
}

class SimulateGATTOperationResponseCallbackImpl : public Backend::SimulateGATTOperationResponseCallback, public DomainDispatcher::Callback {
public:
    SimulateGATTOperationResponseCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.simulateGATTOperationResponse")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct simulateGATTOperationResponseParams : public crdtp::DeserializableProtocolObject<simulateGATTOperationResponseParams> {
    String address;
    String type;
    int code;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(simulateGATTOperationResponseParams)
    CRDTP_DESERIALIZE_FIELD("address", address),
    CRDTP_DESERIALIZE_FIELD("code", code),
    CRDTP_DESERIALIZE_FIELD("type", type),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->SimulateGATTOperationResponse(params.address, params.type, params.code, std::make_unique<SimulateGATTOperationResponseCallbackImpl>(weakPtr(), dispatchable));
}

class SimulateCharacteristicOperationResponseCallbackImpl : public Backend::SimulateCharacteristicOperationResponseCallback, public DomainDispatcher::Callback {
public:
    SimulateCharacteristicOperationResponseCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.simulateCharacteristicOperationResponse")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct simulateCharacteristicOperationResponseParams : public crdtp::DeserializableProtocolObject<simulateCharacteristicOperationResponseParams> {
    String characteristicId;
    String type;
    int code;
    std::optional<Binary> data;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(simulateCharacteristicOperationResponseParams)
    CRDTP_DESERIALIZE_FIELD("characteristicId", characteristicId),
    CRDTP_DESERIALIZE_FIELD("code", code),
    CRDTP_DESERIALIZE_FIELD_OPT("data", data),
    CRDTP_DESERIALIZE_FIELD("type", type),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->SimulateCharacteristicOperationResponse(params.characteristicId, params.type, params.code, std::move(params.data), std::make_unique<SimulateCharacteristicOperationResponseCallbackImpl>(weakPtr(), dispatchable));
}

class SimulateDescriptorOperationResponseCallbackImpl : public Backend::SimulateDescriptorOperationResponseCallback, public DomainDispatcher::Callback {
public:
    SimulateDescriptorOperationResponseCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.simulateDescriptorOperationResponse")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct simulateDescriptorOperationResponseParams : public crdtp::DeserializableProtocolObject<simulateDescriptorOperationResponseParams> {
    String descriptorId;
    String type;
    int code;
    std::optional<Binary> data;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(simulateDescriptorOperationResponseParams)
    CRDTP_DESERIALIZE_FIELD("code", code),
    CRDTP_DESERIALIZE_FIELD_OPT("data", data),
    CRDTP_DESERIALIZE_FIELD("descriptorId", descriptorId),
    CRDTP_DESERIALIZE_FIELD("type", type),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->SimulateDescriptorOperationResponse(params.descriptorId, params.type, params.code, std::move(params.data), std::make_unique<SimulateDescriptorOperationResponseCallbackImpl>(weakPtr(), dispatchable));
}

class AddServiceCallbackImpl : public Backend::AddServiceCallback, public DomainDispatcher::Callback {
public:
    AddServiceCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.addService")) { }

    void sendSuccess(const String& serviceId) override
    {
        crdtp::ObjectSerializer serializer;
        serializer.AddField(crdtp::MakeSpan("serviceId"), serviceId);
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct addServiceParams : public crdtp::DeserializableProtocolObject<addServiceParams> {
    String address;
    String serviceUuid;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(addServiceParams)
    CRDTP_DESERIALIZE_FIELD("address", address),
    CRDTP_DESERIALIZE_FIELD("serviceUuid", serviceUuid),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->AddService(params.address, params.serviceUuid, std::make_unique<AddServiceCallbackImpl>(weakPtr(), dispatchable));
}

class RemoveServiceCallbackImpl : public Backend::RemoveServiceCallback, public DomainDispatcher::Callback {
public:
    RemoveServiceCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.removeService")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct removeServiceParams : public crdtp::DeserializableProtocolObject<removeServiceParams> {
    String serviceId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(removeServiceParams)
    CRDTP_DESERIALIZE_FIELD("serviceId", serviceId),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->RemoveService(params.serviceId, std::make_unique<RemoveServiceCallbackImpl>(weakPtr(), dispatchable));
}

class AddCharacteristicCallbackImpl : public Backend::AddCharacteristicCallback, public DomainDispatcher::Callback {
public:
    AddCharacteristicCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.addCharacteristic")) { }

    void sendSuccess(const String& characteristicId) override
    {
        crdtp::ObjectSerializer serializer;
        serializer.AddField(crdtp::MakeSpan("characteristicId"), characteristicId);
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct addCharacteristicParams : public crdtp::DeserializableProtocolObject<addCharacteristicParams> {
    String serviceId;
    String characteristicUuid;
    std::unique_ptr<protocol::BluetoothEmulation::CharacteristicProperties> properties;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(addCharacteristicParams)
    CRDTP_DESERIALIZE_FIELD("characteristicUuid", characteristicUuid),
    CRDTP_DESERIALIZE_FIELD("properties", properties),
    CRDTP_DESERIALIZE_FIELD("serviceId", serviceId),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->AddCharacteristic(params.serviceId, params.characteristicUuid, std::move(params.properties), std::make_unique<AddCharacteristicCallbackImpl>(weakPtr(), dispatchable));
}

class RemoveCharacteristicCallbackImpl : public Backend::RemoveCharacteristicCallback, public DomainDispatcher::Callback {
public:
    RemoveCharacteristicCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.removeCharacteristic")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct removeCharacteristicParams : public crdtp::DeserializableProtocolObject<removeCharacteristicParams> {
    String characteristicId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(removeCharacteristicParams)
    CRDTP_DESERIALIZE_FIELD("characteristicId", characteristicId),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->RemoveCharacteristic(params.characteristicId, std::make_unique<RemoveCharacteristicCallbackImpl>(weakPtr(), dispatchable));
}

class AddDescriptorCallbackImpl : public Backend::AddDescriptorCallback, public DomainDispatcher::Callback {
public:
    AddDescriptorCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.addDescriptor")) { }

    void sendSuccess(const String& descriptorId) override
    {
        crdtp::ObjectSerializer serializer;
        serializer.AddField(crdtp::MakeSpan("descriptorId"), descriptorId);
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct addDescriptorParams : public crdtp::DeserializableProtocolObject<addDescriptorParams> {
    String characteristicId;
    String descriptorUuid;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(addDescriptorParams)
    CRDTP_DESERIALIZE_FIELD("characteristicId", characteristicId),
    CRDTP_DESERIALIZE_FIELD("descriptorUuid", descriptorUuid),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->AddDescriptor(params.characteristicId, params.descriptorUuid, std::make_unique<AddDescriptorCallbackImpl>(weakPtr(), dispatchable));
}

class RemoveDescriptorCallbackImpl : public Backend::RemoveDescriptorCallback, public DomainDispatcher::Callback {
public:
    RemoveDescriptorCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.removeDescriptor")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct removeDescriptorParams : public crdtp::DeserializableProtocolObject<removeDescriptorParams> {
    String descriptorId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(removeDescriptorParams)
    CRDTP_DESERIALIZE_FIELD("descriptorId", descriptorId),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->RemoveDescriptor(params.descriptorId, std::make_unique<RemoveDescriptorCallbackImpl>(weakPtr(), dispatchable));
}

class SimulateGATTDisconnectionCallbackImpl : public Backend::SimulateGATTDisconnectionCallback, public DomainDispatcher::Callback {
public:
    SimulateGATTDisconnectionCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("BluetoothEmulation.simulateGATTDisconnection")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct simulateGATTDisconnectionParams : public crdtp::DeserializableProtocolObject<simulateGATTDisconnectionParams> {
    String address;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(simulateGATTDisconnectionParams)
    CRDTP_DESERIALIZE_FIELD("address", address),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    m_backend->SimulateGATTDisconnection(params.address, std::make_unique<SimulateGATTDisconnectionCallbackImpl>(weakPtr(), dispatchable));
}

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("BluetoothEmulation"), SortedRedirects(), std::move(dispatcher));
}

} // BluetoothEmulation
} // namespace content
} // namespace protocol
