{#
    Generate trampoline classes to be used for two purposes:

    * Allow python programs to override virtual functions
    * Allow python programs access to protected members

    This trampoline is used from two different places:
    - To generate a trampoline usable by the class itself
    - Generate a trampoline usable by child classes

    Sometimes these are the same trampoline. The exception is when
    a 'final' method is in the base class, then a separate

    Each trampoline type is placed in a different namespace
    to make our life easier.

    Trampoline functions can be disabled via RPY_DISABLE_name_[type_type..]
#}

{% if cls.data.ignore or not cls.x_has_trampoline %}
    {{ skip_generation() }}
{% endif %}

// This file is autogenerated. DO NOT EDIT

#pragma once
#include <robotpy_build.h>

#include <{{ header.rel_fname }}>

{# delete any finals #}
{% for fn in cls.methods.public + cls.methods.protected if fn.final %}
#define RPYGEN_DISABLE_{{ trampoline_signature(fn) }}
{% endfor %}

{# include override files for each base -- TODO: exclude some bases? #}
{% if cls.x_inherits %}
{% for base in cls.x_inherits %}
#include <rpygen/{{ base.x_qualname_ }}.hpp>
{% endfor %}
{% endif %}

namespace rpygen {

{% if cls.namespace %}
using namespace {{ cls.namespace }};
{% endif %}
{% for header in headers %}
{% for using in header.using.values() %}
using {{ using.raw_type }};
{% endfor %}
{% endfor %}

{% if cls.x_inherits %}
{# 
    To avoid multiple inheritance here, we define a single base with bases that
    are all template bases.. 
#}
template <typename CxxBase>
using PyBase{{ cls.x_qualname_ }} = 
{% for base in cls.x_inherits %}
    Py{{ base.x_qualname_ }}<
{% endfor %}
        CxxBase
{% for base in cls.x_inherits %}
    >
{% endfor %}
;

template <typename CxxBase>
struct Py{{ cls.x_qualname_ }} : PyBase{{ cls.x_qualname_ }}<CxxBase> {
    using PyBase{{ cls.x_qualname_ }}<CxxBase>::PyBase{{ cls.x_qualname_ }};
{% else %}
template <typename CxxBase>
struct Py{{ cls.x_qualname_ }} : CxxBase {
    using CxxBase::CxxBase;
{% endif %}

{# protected constructors -- only used by the direct child #}
{% for fn in cls.methods.protected if not fn.data.ignore and fn.constructor %}
#ifdef RPYGEN_ENABLE_{{ cls.x_qualname_ }}_PROTECTED_CONSTRUCTORS
    Py{{ cls.x_qualname_ }}({{ fn.parameters | join(', ', attribute='x_decl') }}) :
        {% if cls.x_inherits -%}
             PyBase{{ cls.x_qualname_ }}<CxxBase>
        {%- else -%}
            CxxBase
        {%- endif -%}
        ({{ fn.parameters | join(', ', attribute='x_callname') }})
    {}
#endif
{% endfor %}

{% for typealias in cls.data.typealias %}
    using {{ typealias.split('::')[-1] }} = {{ typealias }};
{% endfor %}
{% for constant in cls.data.constants %}
    static constexpr auto {{ constant.split('::')[-1] }} = {{ constant }};
{% endfor %}

    {# virtual methods (disabled for buffer overrides for now) #}
    {% for fn in cls.methods.public + cls.methods.protected
           if not fn.data.ignore and (fn.virtual or fn.override) and not fn.final and not fn.data.buffers %}
#ifndef RPYGEN_DISABLE_{{ trampoline_signature(fn) }}
    {{ fn.rtnType }} {{ fn.name }}({{ fn.parameters | join(', ', attribute='x_decl') }}){%
        if fn.const %} const{% endif
    %} override {
    {# TODO: probably will break for things like out parameters, etc #}
    {% if fn.pure_virtual -%}
        PYBIND11_OVERLOAD_PURE_NAME
    {%- else -%}
        PYBIND11_OVERLOAD_NAME
    {%- endif -%}
        ({{ fn.rtnType }}, CxxBase, "{{ fn.x_name }}", {{ fn.name }},{{ fn.parameters | join(', ', attribute='name') }});
    }
#endif

    {% endfor %}

    {# non-virtual protected methods/attributes #}
    {% for fn in cls.methods.protected
           if not fn.data.ignore and not (fn.virtual or fn.override or fn.constructor) %}
#ifndef RPYBLD_DISABLE_{{ trampoline_signature(fn) }}
{# hack to ensure we don't do 'using' twice' in the same class, while
   also ensuring that the overrides can be selectively disabled by
   child trampoline functions #}
  #ifndef RPYBLD_UDISABLE_{{ using_signature(fn) }}
    using {{ cls.x_qualname }}::{{ fn.name }};
    #define RPYBLD_UDISABLE_{{ using_signature(fn) }}
  #endif
#endif
    {% endfor %}

    {% for prop in cls.properties.protected if not prop.data.ignore %}
    using {{ cls.x_qualname }}::{{ prop.name }};
    {% endfor %}
};

}; // namespace rpygen
