// 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.

#ifndef HEADLESS_PUBLIC_DEVTOOLS_DOMAINS_{{domain.domain | camelcase_to_hacker_style | upper}}_H_
#define HEADLESS_PUBLIC_DEVTOOLS_DOMAINS_{{domain.domain | camelcase_to_hacker_style | upper}}_H_

#include "base/functional/callback.h"
#include "base/observer_list.h"
#include "base/values.h"
{% for domain_name in domain.dependencies %}
#include "headless/public/devtools/domains/types_{{domain_name | camelcase_to_hacker_style}}.h"
{% endfor %}
#include "headless/public/headless_export.h"
#include "headless/public/internal/message_dispatcher.h"

{# Macro for defining a member function for a given command. #}
{% macro command_decl(command) %}
  {% set method_name = command.name | sanitize_literal | to_title_case %}
  {% if command.description %}
  // {{ command.description.replace('\n', '\n  // ') }}
  {% endif %}
  void {{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)>());
  {# Generate convenience methods that take the required parameters directly. #}
  {# Don't generate these for experimental commands. #}
  {% if "parameters" in command and not command.experimental %}
  void {{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 = base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)>(){##}
    {% else -%}
      base::OnceClosure callback = base::OnceClosure(){##}
    {% 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 {{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceClosure callback);
    {% endif %}
  {% endif %}
{% endmacro %}

namespace headless {
namespace {{domain.domain | camelcase_to_hacker_style}} {
class HEADLESS_EXPORT ExperimentalDomain;
class HEADLESS_EXPORT ExperimentalObserver;
{% if "events" in domain %}

class HEADLESS_EXPORT ExperimentalObserver {
 public:
  virtual ~ExperimentalObserver() {}
  {% for event in domain.events %}
    {% if event.description %}
  // {{event.description.replace('\n', '\n  // ')}}
    {% endif %}
  virtual void On{{event.name | to_title_case}}(const {{event.name | to_title_case}}Params& params) {}
  {% endfor %}
};

class HEADLESS_EXPORT Observer : public ExperimentalObserver {
 public:
  virtual ~Observer() {}
  {% for event in domain.events %}
    {% if event.description %}
  // {% if event.experimental %}Experimental: {% endif %}{{event.description.replace('\n', '\n  // ')}}
    {% endif %}
  virtual void On{{event.name | to_title_case}}(const {{event.name | to_title_case}}Params& params) {% if event.experimental %}final {% endif %}{}
  {% endfor %}
};
{% endif %}

{% if domain.description %}
// {{domain.description.replace('\n', '\n// ')}}
{% endif %}
class HEADLESS_EXPORT Domain {
 public:
  Domain(const Domain&) = delete;
  Domain& operator=(const Domain&) = delete;

  {% if "events" in domain %}
  // Add or remove an observer. |observer| must be removed before being
  // destroyed.
  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);
  {% endif %}

  // Return the experimental interface for this domain. Note that experimental
  // commands may be changed or removed at any time.
  ExperimentalDomain* GetExperimental();

  {# Generate methods for each command. #}
  {% for command in domain.commands %}
    {# Skip experimental commands. #}
    {% if command.experimental %}{% continue %}{% endif %}
{{ command_decl(command) }}
  {% endfor %}
 protected:
  Domain(internal::MessageDispatcher* dispatcher);
  ~Domain();

  {# 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 Handle{{method_name}}Response(base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback, const base::Value& response);
  {% endfor %}

  {# Generate event dispatchers. #}
  {% for event in domain.events %}
  void Dispatch{{event.name | to_title_case}}Event(const base::Value& params);
  {% endfor %}

  internal::MessageDispatcher* dispatcher_;  // Not owned.
  {% if "events" in domain %}
  base::ObserverList<ExperimentalObserver>::Unchecked observers_;
  {% endif %}

  {% if "events" in domain %}
 protected:
  void RegisterEventHandlersIfNeeded();

  {% endif %}
 private:
  {% if "events" in domain %}
  bool event_handlers_registered_ = false;

  {% endif %}
};

class ExperimentalDomain : public Domain {
 public:
  ExperimentalDomain(internal::MessageDispatcher* dispatcher);

  ExperimentalDomain(const ExperimentalDomain&) = delete;
  ExperimentalDomain& operator=(const ExperimentalDomain&) = delete;

  ~ExperimentalDomain();

  {% if "events" in domain %}
  // Add or remove an observer. |observer| must be removed before being
  // destroyed.
  void AddObserver(ExperimentalObserver* observer);
  void RemoveObserver(ExperimentalObserver* observer);
  {% endif %}

  {# Generate methods for each experimental command. #}
  {% for command in domain.commands %}
    {# Skip non-experimental commands. #}
    {% if not command.experimental %}{% continue %}{% endif %}
{{ command_decl(command) }}
  {% endfor %}
};

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

#endif  // HEADLESS_PUBLIC_DEVTOOLS_DOMAINS_{{domain.domain | camelcase_to_hacker_style | upper}}_H_