{#
 # Copyright 2017 The Cobalt Authors. All Rights Reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 #
 #     http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #}

{#
 # Checks if object implements interface.
 #}
{% macro check_if_object_implements_interface() %}
  if (!script::v8c::shared_bindings::object_implements_interface({{binding_class}}::GetTemplate(isolate), isolate, object)) {
    return;
  }
{%- endmacro %}

{#
 # Function body for operation bindings.
 # Parameters:
 #     operation: The operation context object
 #}
{% macro function_implementation(operation) %}
  v8::Isolate* isolate = info.GetIsolate();
{% if operation.is_static %}
{{ static_function_prologue() }}
{% else %}
  v8::Local<v8::Object> object = info.Holder();
{{ check_if_object_implements_interface() }}
{{ nonstatic_function_prologue(impl_class) }}
{% endif %}
{% call(arguments_list) extract_arguments(operation) %}
{{ call_cobalt_function(impl_class, operation.type, operation.name,
                         arguments_list, operation.raises_exception,
                         operation.call_with, operation.is_static) }}
{% if operation.type != 'void' %}
  if (!exception_state.is_exception_set()) {
    info.GetReturnValue().Set(result_value);
  }
{% endif %}
{%- endcall %}
{%- endmacro %}

{#
 # Function body for setting an attribute value.
 # Parameters:
 #     attribute: The attribute context object.
 #     impl_class: Cobalt class name of the Cobalt implementation of the
 #         interface on which the attribute is a member.
 #     cobalt_impl_prefix: Variable name prefix of a pointer to a Cobalt
 #         implementation of the interface on which the attribute is a member.
 #}
{% macro set_attribute_implementation(attribute, impl_class,
                                      cobalt_impl_prefix="") %}
{% if attribute.put_forwards %}
  { // Begin scope of {{attribute.type}} forwarded_{{cobalt_impl_prefix}}impl.
    {{attribute.type}} forwarded_{{cobalt_impl_prefix}}impl =
{% if not attribute.is_static %}
       {{cobalt_impl_prefix}}impl->{{attribute.getter_function_name}}();
{% else %}
       {{impl_class}}::{{attribute.getter_function_name}}();
{% endif %}
    if (!forwarded_{{cobalt_impl_prefix}}impl) {
      NOTREACHED();
      return;
    }
    if (!exception_state.is_exception_set()) {
{{ set_attribute_implementation(attribute.put_forwards, attribute.type,
     "forwarded_" + cobalt_impl_prefix) -}}
    }
    return;
  } // End scope of {{attribute.type}} forwarded_{{cobalt_impl_prefix}}impl.
{% else %}
  TypeTraits<{{attribute.type}} >::ConversionType value;
  FromJSValue(isolate, v8_value, {{attribute.conversion_flags}}, &exception_state,
              &value);
  if (exception_state.is_exception_set()) {
    return;
  }
{{ call_cobalt_function(impl_class, "void",
                        attribute.setter_function_name,
                        ["value"], attribute.raises_exception,
                        attribute.call_with, attribute.is_static,
                        cobalt_impl_prefix) }}
  return;
{% endif %} {#- attribute.put_forwards #}
{%- endmacro %}

{#
 # Extract and marshal arguments that will be passed to a function-like call.
 # Parameters:
 #     operation: An IdlOperation object
 # Passed to caller:
 #     A string that can be used as the parameters for a function call. It will
 #     be either empty, or a comma-separated list of variable names.
 #}
{% macro extract_arguments(operation) %}
{% set non_optional_arguments = operation.non_optional_arguments %}
{% set optional_arguments = operation.optional_arguments %}
{% set num_default_arguments = operation.num_default_arguments %}
{% set variadic_argument = operation.variadic_argument %}
{% set has_non_default_optional_arguments =
          operation.has_non_default_optional_arguments %}

{%- if non_optional_arguments|length > 0 %}
  const size_t kMinArguments = {{non_optional_arguments|length}};
  if (info.Length() < kMinArguments) {
    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
    return;
  }
{% endif -%}

{# Declare variables for all arguments #}
{% for argument in non_optional_arguments %}
{% if loop.first %}
  // Non-optional arguments
{% endif %}
  TypeTraits<{{argument.type}} >::ConversionType {{argument.name}};
{% endfor %}
{% for argument in optional_arguments if argument.default_value %}
{% if loop.first %}
  // Optional arguments with default values
{% endif %}
  TypeTraits<{{argument.type}} >::ConversionType {{argument.name}} =
      {{argument.default_value}};
{% endfor %}
{% for argument in optional_arguments if not argument.default_value %}
{% if loop.first %}
  // Optional arguments
{% endif %}
  TypeTraits<{{argument.type}} >::ConversionType {{argument.name}};
{% endfor %}
{% if variadic_argument %}
  // Variadic argument
  TypeTraits<{{variadic_argument.type}} >::ConversionType {{
      variadic_argument.name}};
{% endif -%}

{% for argument in non_optional_arguments %}
  DCHECK_LT({{loop.index0}}, info.Length());
  v8::Local<v8::Value> non_optional_value{{loop.index0}} = info[{{loop.index0}}];
  FromJSValue(isolate,
              non_optional_value{{loop.index0}},
              {{argument.conversion_flags}},
              &exception_state, &{{argument.name}});
  if (exception_state.is_exception_set()) {
    return;
  }
{% endfor -%}
{% for argument in optional_arguments %}
{% if loop.first %}
  size_t num_set_arguments = {{
      non_optional_arguments|length + num_default_arguments}};
{% endif %}
  if (info.Length() > {{loop.index0 + non_optional_arguments|length}}) {
    v8::Local<v8::Value> optional_value{{loop.index0}} = info[{{loop.index0 + non_optional_arguments|length}}];
    FromJSValue(isolate,
                optional_value{{loop.index0}},
                {{argument.conversion_flags}},
                &exception_state,
                &{{argument.name}});
    if (exception_state.is_exception_set()) {
      return;
    }
{% if not argument.default_value %}
    ++num_set_arguments;
{% endif %}
  }
{% endfor %}
{% if variadic_argument %}

  // Get variadic arguments.
{% if optional_arguments|length %}
  const size_t kLastOptionalArgIndex = {{
      non_optional_arguments|length + optional_arguments|length}};
  if (num_set_arguments == kLastOptionalArgIndex) {
    // If the last optional argument has been set, we will call the overload
    // that takes the variadic argument, possibly with an empty vector in the
    // case that there are no more arguments left.
    ++num_set_arguments;
  }
{% endif %}
  const size_t kFirstVariadicArgIndex = {{operation.arguments|length - 1}};
  if (info.Length() > kFirstVariadicArgIndex) {
    {{variadic_argument.name}}.resize(info.Length() - kFirstVariadicArgIndex);
    for (int i = 0; i + kFirstVariadicArgIndex < info.Length(); ++i) {
      v8::Local<v8::Value> variadic_argument_value{{i}} = info[i + kFirstVariadicArgIndex];
      FromJSValue(isolate,
                  variadic_argument_value{{i}},
                  {{variadic_argument.conversion_flags}},
                  &exception_state,
                  &{{variadic_argument.name}}[i]);
      if (exception_state.is_exception_set()) {
        return;
      }
    }
  }
{% endif -%}

{# Call the implementation function, based on the number of set arguments. #}
{% if has_non_default_optional_arguments %}
  switch (num_set_arguments) {
{% for num_arguments in range(
    non_optional_arguments|length + num_default_arguments,
    operation.arguments|length + 1) %}
{# If no variadic arguments have been set, we still call the function with
   signature that has the variadic argument and pass an empty vector. There is
   no such function signature that takes the optional parameter immediately
   preceeding the variadic argument but does not take the variadic arguments. #}
{% if loop.last or not operation.arguments[num_arguments].is_variadic %}
{% set function_arguments =
      operation.arguments[0:num_arguments]|map(attribute='name')|list %}
    case {{num_arguments}}:
      {
        {{- caller(function_arguments)|indent(8, false) }}
      }
      break;
{% endif %}
{% endfor %}
    default:
      NOTREACHED();
      return;
  }
{% else %} {#- has_non_default_optional_arguments #}
{% set function_arguments = operation.arguments|map(attribute='name')|list %}
  {# whitespace control block #}
  {{-caller(function_arguments)}}
{% endif %}
{% endmacro %}

{#
 # Append extra arguments that should be passed to a cobalt function.
 # Specifically, this will prepend parameters specified on IDLs using the
 # [CallWith=] extended attribute.
 # Parameters:
 #     arguments_list: A list of C++ expressions that represent a sequence of
 #         arguments that will be passed to a function.
 #     context: An IDL object that may have the extended attribute that
 #         we are interested in.
 # Passed to caller:
 #     arguments_list, possibly with extra arguments prepended and appended.
 #}
{% macro add_extra_arguments(arguments_list, raises_exception, call_with) %}
{% if call_with %}
  V8cGlobalEnvironment* callwith_global_environment = V8cGlobalEnvironment::GetFromIsolate(isolate);
{% do arguments_list.insert(
    0, 'callwith_global_environment->Get%s()'|format(call_with)) %}
{% endif %}
{% do arguments_list.append('&exception_state') if raises_exception %}
{%- endmacro %}

{% macro call_nonvoid_function_internal(function_name, arguments,
                                impl_class, is_static) %}
{% if not is_static %}
    ToJSValue(isolate,
              impl->{{function_name}}({{arguments|join(", ")}}),
              &result_value);
{% else %}
    ToJSValue(isolate,
              {{impl_class}}::{{function_name}}({{arguments|join(', ')}}),
              &result_value);
{% endif %}
{%- endmacro %}

{% macro call_void_function_internal(function_name, arguments,
                                impl_class, is_static, cobalt_impl_prefix) %}
{% if not is_static %}
  {{cobalt_impl_prefix}}impl->{{function_name}}({{arguments|join(", ")}});
{% else %}
  {{impl_class}}::{{function_name}}({{arguments|join(', ')}});
{% endif %}
{%- endmacro %}

{% macro get_cobalt_value(impl_class, cobalt_type, function_name, arguments,
                                raises_exception, call_with, is_static, cobalt_impl_prefix) %}
  {{ add_extra_arguments(arguments, raises_exception, call_with) }}
{% if cobalt_type == "void" %}
  {{call_void_function_internal(function_name, arguments,
                                impl_class, is_static) -}}
{% else %}
  {{call_nonvoid_function_internal(function_name, arguments,
                                impl_class, is_static) -}}
{% endif %}
{%- endmacro %}

{% macro call_nonvoid_function(return_type, function_name, arguments,
                               impl_class, is_static) %}
  if (!exception_state.is_exception_set()) {

  {{call_nonvoid_function_internal(function_name, arguments,
                                impl_class, is_static) -}}
  }
{%- endmacro %}

{% macro call_void_function(function_name, arguments, impl_class, is_static,
                            cobalt_impl_prefix) %}
{{ call_void_function_internal(function_name, arguments, impl_class, is_static,
                      cobalt_impl_prefix) -}}
  result_value = v8::Undefined(isolate);
{%- endmacro %}

{% macro get_impl_class_instance(impl_class) %}
  {{impl_class}}* impl = script::v8c::shared_bindings::get_impl_from_object<{{impl_class}}>(object);
  if (!impl) {
    return;
  }
{%- endmacro %}

{% macro static_function_prologue() %}
  V8cExceptionState exception_state{isolate};
  v8::Local<v8::Value> result_value;
{% endmacro %}

{% macro nonstatic_function_prologue(impl_class) %}
{{ static_function_prologue() }}
{{ get_impl_class_instance(impl_class) }}
{%- endmacro %}

{#
 # Call a function on an instance of a Cobalt platform object.
 #}
{% macro call_cobalt_function(impl_class, cobalt_type, function_name, arguments,
                              raises_exception, call_with, is_static,
                              cobalt_impl_prefix) %}
{{ add_extra_arguments(arguments, raises_exception, call_with) }}
{% if cobalt_type == "void" %}
{{ call_void_function(function_name, arguments, impl_class, is_static,
                      cobalt_impl_prefix) -}}
{% else %}
{{ call_nonvoid_function(cobalt_type, function_name, arguments, impl_class,
                         is_static) -}}
{% endif %}
{% endmacro %}

{#
 # Function body for constructor bindings.
 # Parameters:
 #     constructor: The constructor context object
 #}
{% macro constructor_implementation(constructor) %}
  V8cExceptionState exception_state(isolate);
{% call(arguments_list) extract_arguments(constructor) %}
  if (!info.IsConstructCall()) {
    exception_state.SetSimpleException(script::kTypeError, "Illegal constructor");
    return;
  }
{{ add_extra_arguments(arguments_list, constructor.raises_exception,
                       constructor.call_with) }}
  scoped_refptr<{{impl_class}}> new_object =
      new {{impl_class}}({{arguments_list|join(', ')}});
{% if constructor.raises_exception %}
  // In case that an exception is thrown from constructor.
  if (exception_state.is_exception_set()) {
    return;
  }
{% endif %}
  v8::Local<v8::Value> result_value;
  ToJSValue(isolate, new_object, &result_value);
  DCHECK(result_value->IsObject());
  info.GetReturnValue().Set(result_value);
{%- endcall %}
{%- endmacro %}

{#
 # Function body for overload resolution function.
 # Parameters:
 #     overload_context: The overload context object.
 #     bound_function_prefix: The prefix of the function to be called on
 #         resolution. The overload index will be appended to this.
 #}
{% macro overload_resolution_implementation(
      overload_context, bound_function_prefix) %}
  v8::Isolate* isolate = info.GetIsolate();

  switch(info.Length()) {
{% for length, distinguishing_argument_index, resolution_tests in
       overload_context.overload_resolution_by_length %}
    case({{length}}): {
      // Overload resolution algorithm details found here:
      //     http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
{# In the case there is only one resolution condition, we do not need the arg. #}
{% if resolution_tests|length > 1 %}
      v8::Local<v8::Value> arg = info[{{distinguishing_argument_index}}];
      WrapperFactory* wrapper_factory = V8cGlobalEnvironment::GetFromIsolate(isolate)->wrapper_factory();
      v8::Local<v8::Object> object;
      if (arg->IsObject()) {
        object = arg->ToObject();
      }
{% endif %}
{% for test, overload in resolution_tests %}
      if ({{test("arg")}}) {
        {{bound_function_prefix}}{{overload.overload_index}}(
                  info);
        return;
      }
{% endfor %}
      break;
    }
{% endfor %}
  }
  // Invalid number of args
  // http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
  // 4. If S is empty, then throw a TypeError.
  V8cExceptionState exception_state(isolate);
  exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
  return;
{%- endmacro %}
