// This file is generated

// 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 "headless/public/devtools/domains/{{domain.domain | camelcase_to_hacker_style}}.h"

#include "base/functional/bind.h"
#include "headless/public/util/error_reporter.h"

namespace headless {

namespace {{domain.domain | camelcase_to_hacker_style}} {

ExperimentalDomain* Domain::GetExperimental() {
  return static_cast<ExperimentalDomain*>(this);
}

  {% if "events" in domain %}
void Domain::AddObserver(Observer* observer) {
  RegisterEventHandlersIfNeeded();
  observers_.AddObserver(observer);
}

void Domain::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

void Domain::RegisterEventHandlersIfNeeded() {
  if (event_handlers_registered_)
    return;
  event_handlers_registered_ = true;
    {# Register all events in this domain. #}
    {% for event in domain.events %}
  dispatcher_->RegisterEventHandler(
      "{{domain.domain}}.{{event.name}}",
      base::BindRepeating(&Domain::Dispatch{{event.name | to_title_case}}Event,
                          base::Unretained(this)));
    {% endfor %}
}
  {% endif %}

  {% for command in domain.commands %}
    {% set class_name = 'ExperimentalDomain' if command.experimental else 'Domain' %}
    {% set method_name = command.name | sanitize_literal | to_title_case %}
void {{class_name}}::{{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback) {
  dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", params->Serialize(), base::BindOnce(&Domain::Handle{{method_name}}Response, std::move(callback)));
}
    {# Generate convenience methods that take the required parameters directly. #}
    {% if not "parameters" in command %}{% continue %}{% endif %}
    {# Don't generate these for experimental commands. #}
    {% if command.experimental %}{% continue %}{% endif %}

void {{class_name}}::{{method_name}}({##}
    {% for parameter in command.parameters -%}
        {% if parameter.get("optional", False) -%}
          {% break %}
        {% endif %}
        {% if not loop.first %}, {% endif %}
{{resolve_type(parameter).pass_type}} {{parameter.name | camelcase_to_hacker_style -}}
    {% endfor %}
    {% if command.get("parameters", []) and not command.parameters[0].get("optional", False) %}, {% endif %}{# -#}
    {% if command.get("returns", []) -%}
      base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback{##}
    {% else -%}
      base::OnceClosure callback{##}
    {% endif %}) {
    {# Build the parameters object. #}
  std::unique_ptr<{{method_name}}Params> params = {{method_name}}Params::Builder()
    {% for parameter in command.parameters -%}
        {% if parameter.get("optional", False) -%}
          {% break %}
        {% endif %}
      .Set{{parameter.name | to_title_case}}(std::move({{parameter.name | camelcase_to_hacker_style}}))
    {% endfor %}
      .Build();
    {# Send the message. #}
    {% if command.get("returns", []) -%}
  dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", params->Serialize(), base::BindOnce(&Domain::Handle{{method_name}}Response, std::move(callback)));
    {% else %}
  dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", params->Serialize(), std::move(callback));
    {% endif %}
}
    {# If the command has no return value, generate a convenience method that #}
    {# accepts a base::OnceClosure together with the parameters object. #}
    {% if not command.get("returns", []) %}
void {{class_name}}::{{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceClosure callback) {
  dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", params->Serialize(), std::move(callback));
}
    {% endif %}
  {% endfor %}

{# Generate response handlers for commands that need them. #}
{% for command in domain.commands %}
  {% if not "returns" in command %}{% continue %}{% endif %}
  {% set method_name = command.name | sanitize_literal | to_title_case %}

// static
void Domain::Handle{{method_name}}Response(base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback, const base::Value& response) {
  if (callback.is_null())
    return;
  // This is an error response.
  if (response.is_none()) {
    std::move(callback).Run(nullptr);
    return;
  }
  ErrorReporter errors;
  std::unique_ptr<{{method_name}}Result> result = {{method_name}}Result::Parse(response, &errors);
  DCHECK(!errors.HasErrors()) << errors.ToString();
  std::move(callback).Run(std::move(result));
}
{% endfor %}
{% if "events" in domain %}
  {% for event in domain.events %}

{# Generate dispatchers which call registered observers for an event. #}
void Domain::Dispatch{{event.name | to_title_case}}Event(const base::Value& params) {
  ErrorReporter errors;
  std::unique_ptr<{{event.name | to_title_case}}Params> parsed_params({{event.name | to_title_case}}Params::Parse(params, &errors));
  DCHECK(!errors.HasErrors()) << errors.ToString();
  for (ExperimentalObserver& observer : observers_) {
    observer.On{{event.name | to_title_case}}(*parsed_params);
  }
}
  {% endfor %}
{% endif %}

Domain::Domain(internal::MessageDispatcher* dispatcher)
    : dispatcher_(dispatcher) {
}

Domain::~Domain() {}

ExperimentalDomain::ExperimentalDomain(internal::MessageDispatcher* dispatcher)
    : Domain(dispatcher) {}

ExperimentalDomain::~ExperimentalDomain() {}

  {% if "events" in domain %}
void ExperimentalDomain::AddObserver(ExperimentalObserver* observer) {
  RegisterEventHandlersIfNeeded();
  observers_.AddObserver(observer);
}

void ExperimentalDomain::RemoveObserver(ExperimentalObserver* observer) {
  observers_.RemoveObserver(observer);
}
  {% endif %}

}  // namespace {{domain.domain | camelcase_to_hacker_style}}

} // namespace headless