
{% macro render_enum(enumtype, is_static = False) -%}
    public {% if is_static %}static {%endif%}enum {{enumtype.enum_name}} {
        {% for m in enumtype.enum_vals %}
        {{ m }},
        {% endfor %}
    }
{%- endmacro %}

{% macro render_property_getter(node, prop_name, prop_type) -%}
{% if prop_type.__class__.__name__ == "UnionType" -%}
    {% for uname, utype in prop_type.members.iteritems() %}
    {% if no_implementation -%}
        {{platform.evalType(utype)}} get{{camel_case(prop_name)}}_{{camel_case(uname)}}();
    {% else -%}
        {{platform.evalType(utype)}} get{{camel_case(prop_name)}}_{{camel_case(uname)}}()
        {
            return ({{platform.evalType(utype)}})this.{{prop_name}};
        }
    {%- endif %}
    {% endfor %}
{% else %}
    {% if no_implementation -%}
        {{platform.evalType(prop_type)}} get{{camel_case(prop_name)}}();
    {% else -%}
        {{platform.evalType(prop_type)}} get{{camel_case(prop_name)}}()
        {
            return this.{{prop_name}};
        }
    {%- endif %}
{%- endif %}
{%- endmacro %}

{% macro render_property_setter(node, prop_name, prop_type) -%}
    {% if no_implementation -%}
        void set{{camel_case(prop_name)}}({{platform.evalType(prop_type)}} value);
    {% else -%}
        void set{{camel_case(prop_name)}}({{platform.evalType(prop_type)}} value)
        {
            this.{{prop_name}} = value;
        }
    {% 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" %}
Object {{prop_name}};
{% else %}
{{platform.evalType(prop_type)}} {{prop_name}};
{% endif %}
{%- endmacro %}

{% macro render_pair_class(is_static = False) -%}
    public {% if is_static %}static {%endif%}class Pair<T1, T2> implements Comparable<Pair<T1, T2>> {
        public final T1 first;
        public final T2 second;

        private Pair(T1 first, T2 second) {
            this.first = first;
            this.second = second;
        }

        public static <T1, T2> Pair<T1, T2> of(T1 first,
                T2 second) {
            return new Pair<T1, T2>(first, second);
        }

        @Override
        public int compareTo(Pair<T1, T2> o) {
            int cmp = compare(first, o.first);
            return cmp == 0 ? compare(second, o.second) : cmp;
        }

        // todo move this to a helper class.
        private static int compare(Object o1, Object o2) {
            return o1 == null ? o2 == null ? 0 : -1 : o2 == null ? +1
                    : ((Comparable) o1).compareTo(o2);
        }

        @Override
        public int hashCode() {
            return 31 * hashcode(first) + hashcode(second);
        }

        // todo move this to a helper class.
        private static int hashcode(Object o) {
            return o == null ? 0 : o.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Pair))
                return false;
            if (this == obj)
                return true;
            return equal(first, ((Pair) obj).first)
                    && equal(second, ((Pair) obj).second);
        }

        // todo move this to a helper class.
        private boolean equal(Object o1, Object o2) {
            return o1 == null ? o2 == null : (o1 == o2 || o1.equals(o2));
        }

        @Override
        public String toString() {
            return "(" + first + ", " + second + ')';
        }
    }
{%- endmacro %}
