
{% macro invoke_setter(field) %}set{{camel_case(field.name)}}({{caller()}}){% endmacro %}

package {{transformer.namespace}};

import {{source_type.fqn}};
import {{target_type.fqn}};
import java.util.Map;

public class {{transformer.name}} {
    public static void transform({{source_type.name}} source, {{target_type.name}} target) {
        // Pass 1 - Transform fields that are available through name mappings if the types are the same
        {% for source_field in source_type.type_data.fields.itervalues() %}
        {% if field_graph.has_field_edge(source_field, "mapping") %}
        {% with target_field = field_graph.get_field_edges(source_field, "mapping")[0].field %}
        if ({{invoke_checker("source", source_field)}}) {
            target.{% call invoke_setter(target_field) %}{{ invoke_getter("source", source_field) }}{% endcall %};
        }
        {% endwith %}
        {% endif %}
        {% endfor %}

        // Pass 2 - Handle type_change transformations - these should have a default transformer
        {% for source_field in source_type.type_data.fields.itervalues() %}
            {% if field_graph.has_field_edge(source_field, "type_change") %}
                {% with target_field = field_graph.get_field_edges(source_field, "type_change")[0].field %}
                    {{ transform_field("source", source_field, "target", target_field) }}
                {% endwith %}
            {% endif %}
        {% endfor %}

        // Pass 3 - Handle "instance transformer" rules
        {% for rule in transformer.rules %}
        applyRule_{{rule.index}}(source, target);
        {% endfor %}
    }

    {% for rule in transformer.rules %}
    private static void applyRule_{{rule.index}}({{source_type.name}} source, {{target_type.name}} target) {
        {{ generate_rule_code(rule) }}
    }
    {% endfor %}
}

