// 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 "chrome/browser/devtools/protocol/emulation.h"

#include "chrome/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 protocol {
namespace Emulation {

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

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

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


const char* ScreenOrientation::TypeEnum::PortraitPrimary = "portraitPrimary";
const char* ScreenOrientation::TypeEnum::PortraitSecondary = "portraitSecondary";
const char* ScreenOrientation::TypeEnum::LandscapePrimary = "landscapePrimary";
const char* ScreenOrientation::TypeEnum::LandscapeSecondary = "landscapeSecondary";
CRDTP_BEGIN_DESERIALIZER(ScreenOrientation)
    CRDTP_DESERIALIZE_FIELD("angle", m_angle),
    CRDTP_DESERIALIZE_FIELD("type", m_type),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ScreenOrientation)
    CRDTP_SERIALIZE_FIELD("type", m_type);
    CRDTP_SERIALIZE_FIELD("angle", m_angle);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(WorkAreaInsets)
    CRDTP_DESERIALIZE_FIELD_OPT("bottom", m_bottom),
    CRDTP_DESERIALIZE_FIELD_OPT("left", m_left),
    CRDTP_DESERIALIZE_FIELD_OPT("right", m_right),
    CRDTP_DESERIALIZE_FIELD_OPT("top", m_top),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(WorkAreaInsets)
    CRDTP_SERIALIZE_FIELD("top", m_top);
    CRDTP_SERIALIZE_FIELD("left", m_left);
    CRDTP_SERIALIZE_FIELD("bottom", m_bottom);
    CRDTP_SERIALIZE_FIELD("right", m_right);
CRDTP_END_SERIALIZER();



CRDTP_BEGIN_DESERIALIZER(ScreenInfo)
    CRDTP_DESERIALIZE_FIELD("availHeight", m_availHeight),
    CRDTP_DESERIALIZE_FIELD("availLeft", m_availLeft),
    CRDTP_DESERIALIZE_FIELD("availTop", m_availTop),
    CRDTP_DESERIALIZE_FIELD("availWidth", m_availWidth),
    CRDTP_DESERIALIZE_FIELD("colorDepth", m_colorDepth),
    CRDTP_DESERIALIZE_FIELD("devicePixelRatio", m_devicePixelRatio),
    CRDTP_DESERIALIZE_FIELD("height", m_height),
    CRDTP_DESERIALIZE_FIELD("id", m_id),
    CRDTP_DESERIALIZE_FIELD("isExtended", m_isExtended),
    CRDTP_DESERIALIZE_FIELD("isInternal", m_isInternal),
    CRDTP_DESERIALIZE_FIELD("isPrimary", m_isPrimary),
    CRDTP_DESERIALIZE_FIELD("label", m_label),
    CRDTP_DESERIALIZE_FIELD("left", m_left),
    CRDTP_DESERIALIZE_FIELD("orientation", m_orientation),
    CRDTP_DESERIALIZE_FIELD("top", m_top),
    CRDTP_DESERIALIZE_FIELD("width", m_width),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ScreenInfo)
    CRDTP_SERIALIZE_FIELD("left", m_left);
    CRDTP_SERIALIZE_FIELD("top", m_top);
    CRDTP_SERIALIZE_FIELD("width", m_width);
    CRDTP_SERIALIZE_FIELD("height", m_height);
    CRDTP_SERIALIZE_FIELD("availLeft", m_availLeft);
    CRDTP_SERIALIZE_FIELD("availTop", m_availTop);
    CRDTP_SERIALIZE_FIELD("availWidth", m_availWidth);
    CRDTP_SERIALIZE_FIELD("availHeight", m_availHeight);
    CRDTP_SERIALIZE_FIELD("devicePixelRatio", m_devicePixelRatio);
    CRDTP_SERIALIZE_FIELD("orientation", m_orientation);
    CRDTP_SERIALIZE_FIELD("colorDepth", m_colorDepth);
    CRDTP_SERIALIZE_FIELD("isExtended", m_isExtended);
    CRDTP_SERIALIZE_FIELD("isInternal", m_isInternal);
    CRDTP_SERIALIZE_FIELD("isPrimary", m_isPrimary);
    CRDTP_SERIALIZE_FIELD("label", m_label);
    CRDTP_SERIALIZE_FIELD("id", m_id);
CRDTP_END_SERIALIZER();


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


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

void Frontend::VirtualTimeBudgetExpired()
{
    if (!frontend_channel_)
        return;
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("Emulation.virtualTimeBudgetExpired"));
}

void Frontend::ScreenOrientationLockChanged(bool locked, std::unique_ptr<protocol::Emulation::ScreenOrientation> orientation)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("locked"), locked);
    serializer.AddField(crdtp::MakeSpan("orientation"), orientation);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("Emulation.screenOrientationLockChanged", 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 setAutomationOverride(crdtp::Dispatchable& dispatchable);
    void getScreenInfos(crdtp::Dispatchable& dispatchable);
    void addScreen(crdtp::Dispatchable& dispatchable);
    void updateScreen(crdtp::Dispatchable& dispatchable);
    void removeScreen(crdtp::Dispatchable& dispatchable);
    void setPrimaryScreen(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("addScreen"),
          &DomainDispatcherImpl::addScreen
    },
    {
          crdtp::SpanFrom("getScreenInfos"),
          &DomainDispatcherImpl::getScreenInfos
    },
    {
          crdtp::SpanFrom("removeScreen"),
          &DomainDispatcherImpl::removeScreen
    },
    {
          crdtp::SpanFrom("setAutomationOverride"),
          &DomainDispatcherImpl::setAutomationOverride
    },
    {
          crdtp::SpanFrom("setPrimaryScreen"),
          &DomainDispatcherImpl::setPrimaryScreen
    },
    {
          crdtp::SpanFrom("updateScreen"),
          &DomainDispatcherImpl::updateScreen
    },
    };
    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 setAutomationOverrideParams : public crdtp::DeserializableProtocolObject<setAutomationOverrideParams> {
    bool enabled;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(setAutomationOverrideParams)
    CRDTP_DESERIALIZE_FIELD("enabled", enabled),
CRDTP_END_DESERIALIZER()

}  // namespace

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

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

namespace {


}  // namespace

void DomainDispatcherImpl::getScreenInfos(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    // Declare output parameters.
    std::unique_ptr<protocol::Array<protocol::Emulation::ScreenInfo>> out_screenInfos;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->GetScreenInfos(&out_screenInfos);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("screenInfos"), out_screenInfos);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct addScreenParams : public crdtp::DeserializableProtocolObject<addScreenParams> {
    int left;
    int top;
    int width;
    int height;
    std::unique_ptr<protocol::Emulation::WorkAreaInsets> workAreaInsets;
    std::optional<double> devicePixelRatio;
    std::optional<int> rotation;
    std::optional<int> colorDepth;
    std::optional<String> label;
    std::optional<bool> isInternal;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(addScreenParams)
    CRDTP_DESERIALIZE_FIELD_OPT("colorDepth", colorDepth),
    CRDTP_DESERIALIZE_FIELD_OPT("devicePixelRatio", devicePixelRatio),
    CRDTP_DESERIALIZE_FIELD("height", height),
    CRDTP_DESERIALIZE_FIELD_OPT("isInternal", isInternal),
    CRDTP_DESERIALIZE_FIELD_OPT("label", label),
    CRDTP_DESERIALIZE_FIELD("left", left),
    CRDTP_DESERIALIZE_FIELD_OPT("rotation", rotation),
    CRDTP_DESERIALIZE_FIELD("top", top),
    CRDTP_DESERIALIZE_FIELD("width", width),
    CRDTP_DESERIALIZE_FIELD_OPT("workAreaInsets", workAreaInsets),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::addScreen(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    addScreenParams params;
    if (!addScreenParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    std::unique_ptr<protocol::Emulation::ScreenInfo> out_screenInfo;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->AddScreen(params.left, params.top, params.width, params.height, std::move(params.workAreaInsets), std::move(params.devicePixelRatio), std::move(params.rotation), std::move(params.colorDepth), std::move(params.label), std::move(params.isInternal), &out_screenInfo);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("screenInfo"), out_screenInfo);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct updateScreenParams : public crdtp::DeserializableProtocolObject<updateScreenParams> {
    String screenId;
    std::optional<int> left;
    std::optional<int> top;
    std::optional<int> width;
    std::optional<int> height;
    std::unique_ptr<protocol::Emulation::WorkAreaInsets> workAreaInsets;
    std::optional<double> devicePixelRatio;
    std::optional<int> rotation;
    std::optional<int> colorDepth;
    std::optional<String> label;
    std::optional<bool> isInternal;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(updateScreenParams)
    CRDTP_DESERIALIZE_FIELD_OPT("colorDepth", colorDepth),
    CRDTP_DESERIALIZE_FIELD_OPT("devicePixelRatio", devicePixelRatio),
    CRDTP_DESERIALIZE_FIELD_OPT("height", height),
    CRDTP_DESERIALIZE_FIELD_OPT("isInternal", isInternal),
    CRDTP_DESERIALIZE_FIELD_OPT("label", label),
    CRDTP_DESERIALIZE_FIELD_OPT("left", left),
    CRDTP_DESERIALIZE_FIELD_OPT("rotation", rotation),
    CRDTP_DESERIALIZE_FIELD("screenId", screenId),
    CRDTP_DESERIALIZE_FIELD_OPT("top", top),
    CRDTP_DESERIALIZE_FIELD_OPT("width", width),
    CRDTP_DESERIALIZE_FIELD_OPT("workAreaInsets", workAreaInsets),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::updateScreen(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    updateScreenParams params;
    if (!updateScreenParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    std::unique_ptr<protocol::Emulation::ScreenInfo> out_screenInfo;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->UpdateScreen(params.screenId, std::move(params.left), std::move(params.top), std::move(params.width), std::move(params.height), std::move(params.workAreaInsets), std::move(params.devicePixelRatio), std::move(params.rotation), std::move(params.colorDepth), std::move(params.label), std::move(params.isInternal), &out_screenInfo);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("screenInfo"), out_screenInfo);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct removeScreenParams : public crdtp::DeserializableProtocolObject<removeScreenParams> {
    String screenId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(removeScreenParams)
    CRDTP_DESERIALIZE_FIELD("screenId", screenId),
CRDTP_END_DESERIALIZER()

}  // namespace

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

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

namespace {

struct setPrimaryScreenParams : public crdtp::DeserializableProtocolObject<setPrimaryScreenParams> {
    String screenId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(setPrimaryScreenParams)
    CRDTP_DESERIALIZE_FIELD("screenId", screenId),
CRDTP_END_DESERIALIZER()

}  // namespace

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

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->SetPrimaryScreen(params.screenId);
    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("Emulation"), SortedRedirects(), std::move(dispatcher));
}

} // Emulation
} // namespace protocol
