
{% macro ifndef_define(prefix = '', suffix = '') -%}
#ifndef __{{prefix}}__{{suffix}}__
#define __{{prefix}}__{{suffix}}__
{%- endmacro %}

{% macro start_externc() -%}
#if defined(_cplusplus) || defined(__cplusplus)
extern "C" {
#endif
{%- endmacro %}

{% macro end_externc() -%}
#if defined(_cplusplus) || defined(__cplusplus)
}
#endif
{%- endmacro %}

{% macro start_namespace(ns) -%}
{% if ns %}namespace {{ns}} { {% endif %}
{%- endmacro %}

{% macro end_namespace(ns) -%}
{% if ns %}} {% endif %}
{%- endmacro %}

{% macro render_enum(enumtype) -%}
enum class {{enumtype.enum_name}} {
    {% for m in enumtype.enum_vals %}
    {{ m }},
    {% endfor %}
};
{%- endmacro %}

{% macro render_destructor(node, withscope = False) -%}
{% if no_impl %}
    virtual ~{{node.nodeName()}}();
{% else -%}
{% if not node.no_destructor -%}
    {% if withscope %}{{node.nodeName()}}::{%else%}virtual {% endif %}~{{node.nodeName()}}() { }
{%- endif %}
{%- endif %}
{%- endmacro %}

{% macro render_union_property_getter(node, prop_name, prop_type, withscope = False) -%}
{% for uname, utype in prop_type.members.iteritems() %}
{% if no_impl %}
    const {{platform.evalType(utype)}} &get{{camel_case(prop_name)}}_{{camel_case(uname)}}();
{% else %}
    const {{platform.evalType(utype)}} &{% if withscope %}{{node.nodeName()}}::{%endif%}get{{camel_case(prop_name)}}_{{camel_case(uname)}}()
    {
        return (({{node.nodeName()}}_{{camel_case(prop_name)}}_{{camel_case(uname)}} *)this->{{prop_name}})->{{uname}};
    }
{% endif %}
{% endfor %}
{%- endmacro %}

{% macro render_union_property_setter(node, prop_name, prop_type, withscope = False) -%}
{% for uname, utype in prop_type.members.iteritems() %}
{% if no_impl %}
    void set{{camel_case(prop_name)}}_{{camel_case(uname)}}(const {{platform.evalType(utype)}} &value);
{% else %}
    void {% if withscope %}{{node.nodeName()}}::{%endif%}set{{camel_case(prop_name)}}_{{camel_case(uname)}}(const {{platform.evalType(utype)}} &value)
    {
        if (this->{{prop_name}}) delete this->{{prop_name}};
        this->{{prop_name}} = new {{node.nodeName()}}_{{camel_case(prop_name)}}_{{camel_case(uname)}}(value);
    }
{% endif %}
{% endfor %}
{%- endmacro %}

{% macro render_property_getter(node, prop_name, prop_type, withscope = False) -%}
{% if prop_type.__class__.__name__ == "UnionType" -%}
    {{ render_union_property_getter(node, prop_name, prop_type, withscope) }}
{% else %}
    {% if no_impl -%}
        const {{platform.evalType(prop_type)}} &get{{camel_case(prop_name)}}();
    {% else -%}
        const {{platform.evalType(prop_type)}} &{% if withscope %}{{node.nodeName()}}::{%endif%}get{{camel_case(prop_name)}}()
        {
            return this->{{prop_name}};
        }
    {%- endif %}
{%- endif %}
{%- endmacro %}

{% macro render_property_setter(node, prop_name, prop_type, withscope = False) -%}
{% if prop_type.__class__.__name__ == "UnionType" -%}
    {{ render_union_property_setter(node, prop_name, prop_type, withscope) }}
{% else %}
    {% if no_impl -%}
        void set{{camel_case(prop_name)}}(const {{platform.evalType(prop_type)}} &value);
    {% else -%}
        void {% if withscope %}{{node.nodeName()}}::{%endif%}set{{camel_case(prop_name)}}(const {{platform.evalType(prop_type)}} &value)
        {
        {% if prop_type.__class__.__name__ == "ListOf" -%}
            this->{{prop_name}}.clear();
            std::copy(value.begin(), value.end(), back_inserter(this->{{prop_name}}));
        {% else %}
            this->{{prop_name}} = value;
        {%- endif %}
        }
    {% endif -%}
{% endif -%}
{%- endmacro %}

{% macro camel_case(value) -%}{{value[0]|upper}}{{value[1:]}}{%- endmacro %}

{% macro render_property_declaration(node, prop_name, prop_type) -%}
{% if prop_type.__class__.__name__ == "UnionType" %}
    {{ render_union_property_class(node, prop_name, prop_type) }}
{% else %}
{{platform.evalType(prop_type)}} {{prop_name}};
{% endif %}
{%- endmacro %}


{% macro render_node_class(node) -%}
class {{node.nodeName()}} {% if node.parent() %}: public {{ node.parent().nodeName() }}{% endif %}
{
public:
    {{ render_destructor(node) }}
    {% for prop_name, prop_type in node.properties.iteritems() %}
    {{ render_property_getter(node, prop_name, prop_type) }}
    {{ render_property_setter(node, prop_name, prop_type) }}
    {% endfor %}
{% if node.properties %}

protected:
    {% for prop_name, prop_type in node.properties.iteritems() %}
    {{ render_property_declaration(node, prop_name, prop_type)  }}
    {% endfor %}
{% endif %}
};
{%- endmacro %}

{% macro render_union_property_class(node, prop_name, prop_type) %}
    class {{node.nodeName()}}_{{camel_case(prop_name)}} {
    public: 
        virtual ~{{node.nodeName()}}_{{camel_case(prop_name)}}() { }
    };
    {% for uname, utype in prop_type.members.iteritems() %}
    class {{node.nodeName()}}_{{camel_case(prop_name)}}_{{camel_case(uname)}} : public {{node.nodeName()}}_{{camel_case(prop_name)}}
    {
    public: 
        {{node.nodeName()}}_{{camel_case(prop_name)}}_{{camel_case(uname)}}(const {{platform.evalType(utype)}} &{{uname}}_) : {{uname}}({{uname}}_) { }
        {{platform.evalType(utype)}} {{uname}};
    };
    {% endfor %}
    {{node.nodeName()}}_{{camel_case(prop_name)}} *{{prop_name}};
{% endmacro %}
