{# Rendering components recursively. #}
{# Args: #}
{#     component: component dictionary #}
{#     indent_width: indent width #}
{% macro render(component, indent_width=0) %}
{% filter indent(width=indent_width) %}
  {%- if component is not mapping %}
    {{- component }}
  {%- elif "iterable" in component %}
    {{- render_iterable_tag(component) }}
  {%- elif component.name == "match"%}
    {{- render_match_tag(component) }}
  {%- elif "cond" in component %}
    {{- render_condition_tag(component) }}
  {%- elif component.children|length %}
    {{- render_tag(component) }}
  {%- else %}
    {{- render_self_close_tag(component) }}
  {%- endif %}
{% endfilter %}
{% endmacro %}

{# Rendering self close tag. #}
{# Args: #}
{#     component: component dictionary #}
{% macro render_self_close_tag(component) %}
{%- if component.name|length %}
<{{ component.name }} {{- render_props(component.props) }}{% if component.autofocus %} ref={focusRef} {% endif %}/>
{%- else %}
  {{- component.contents }}
{%- endif %}
{% endmacro %}

{# Rendering close tag with args and props. #}
{# Args: #}
{#     component: component dictionary #}
{% macro render_tag(component) %}
<{{component.name}} {{- render_props(component.props) }}>
{%- if component.args is not none -%}
  {{- render_arg_content(component) }}
{%- else -%}
  {{ component.contents }}
  {% for child in component.children %}
  {{ render(child) }}
  {% endfor %}
{%- endif -%}
</{{component.name}}>
{%- endmacro %}


{# Rendering condition component. #}
{# Args: #}
{#     component: component dictionary #}
{% macro render_condition_tag(component) %}
{ {{- component.cond_state }} ? (
  {{ render(component.true_value) }}
) : (
  {{ render(component.false_value) }}
)}
{%- endmacro %}


{# Rendering iterable component. #}
{# Args: #}
{#     component: component dictionary #}
{% macro render_iterable_tag(component) %}
<>{ {%- if component.iterable_type == 'dict' -%}Object.entries({{- component.iterable_state }}){%- else -%}{{- component.iterable_state }}{%- endif -%}.map(({{ component.arg_name }}, {{ component.arg_index }}) => (
  {% for child in component.children %}
  {{ render(child) }}
  {% endfor %}
))}</>
{%- endmacro %}


{# Rendering props of a component. #}
{# Args: #}
{#     component: component dictionary #}
{% macro render_props(props) %}
{% if props|length %} {{ props|join(" ") }}{% endif %}
{% endmacro %}

{# Rendering Match component. #}
{# Args: #}
{#     component: component dictionary #}
{% macro render_match_tag(component) %}
{
    (() => {
        switch (JSON.stringify({{ component.cond._js_expr }})) {
        {% for case in component.match_cases %}
            {% for condition in case[:-1] %}
                case JSON.stringify({{ condition._js_expr }}):
            {% endfor %}
                return {{ case[-1] }};
                break;
        {% endfor %}
            default:
                return {{ component.default }};
                break;
        }
    })()
  }
{%- endmacro %}


{# Rendering content with args. #}
{# Args: #}
{#     component: component dictionary #}
{% macro render_arg_content(component) %}
{% filter indent(width=2) %}
{# no string below for a line break #}

{({ {{component.args|join(", ")}} }) => (
  {% for child in component.children %}
  {{ render(child) }}
  {% endfor %}
)}
{% endfilter %}
{% endmacro %}


{# Get react libraries import . #}
{# Args: #}
{#     module: react module dictionary #}
{% macro get_import(module)%}
{%- if module.default|length and module.rest|length -%}
  import {{module.default}}, { {{module.rest|sort|join(", ")}} } from "{{module.lib}}"
{%- elif module.default|length -%}
  import {{module.default}} from "{{module.lib}}"
{%- elif module.rest|length -%}
  import { {{module.rest|sort|join(", ")}} } from "{{module.lib}}"
{%- else -%}
  import "{{module.lib}}"
{%- endif -%}
{% endmacro %}
