{% import "class_parameters.py.j2" as class_parameters -%}
from datetime import datetime, date, time
{%- set ns = namespace(abstract_found=false) %}
{%- for class in domain.classes_sorted_by_inheritance() -%}
    {%- if class.is_abstract -%}
        {%- set ns.abstract_found = true -%}
    {% endif -%}    
{% endfor -%}
{%- if ns.abstract_found %}
from abc import ABC, abstractmethod
{% endif %}
{%- if domain.get_enumerations() %}
from enum import Enum

############################################
# Definition of Enumerations
############################################

{% for enum in domain.get_enumerations() -%}
class {{ enum.name }}(Enum):
{%- for literal in sort_by_timestamp(enum.literals) %}
    {{ literal.name }} = "{{ literal.name }}"
{%- endfor %}
{% endfor -%}
{% endif %}

############################################
# Definition of Classes
############################################
{% for class in domain.classes_sorted_by_inheritance() %}
class {{ class.name }}{% if class.parents() %}({% for parent in class.parents() %}{{parent.name}}{{ ", " if not loop.last else "" }}{% endfor %}){% elif class.is_abstract %}(ABC){% endif %}:
{% if class.all_attributes() or class.methods %}
    def __init__({{ class_parameters.init_parameters(class, sort_by_timestamp) }}):
        {{ class_parameters.init_parameters_definition(class, sort_by_timestamp) }}

    {%- for attribute in class.attributes %}
    @property
    def {{ attribute.name }}(self) -> {{ attribute.type.name }}:
        return self.__{{ attribute.name }}

    @{{ attribute.name }}.setter
    def {{ attribute.name }}(self, {{ attribute.name }}: {{ attribute.type.name }}):
        self.__{{ attribute.name }} = {{ attribute.name }}
{% endfor -%}

    {% for end in class.association_ends() %}{% if end.is_navigable == True %}
    @property
    def {{ end.name }}(self):
        return self.__{{ end.name }}

    @{{ end.name }}.setter
    def {{ end.name }}(self, {{ end.name }}):
        self.__{{ end.name }} = {{ end.name }}
{% endif -%}{% endfor -%}

    {%- for method in class.methods %}
    {%- if method.is_abstract %}
    @abstractmethod
    {%- endif %}
    def {{ method.name }}(self{% if method.parameters %}, {% for param in method.parameters %}{{ param.name }}: {{ param.type.name }}{% if param.default_value %} = "{{ param.default_value }}"{% endif %}{{ ", " if not loop.last else "" }}{% endfor %}{% endif %}){%- if method.type %} -> {{ method.type.name }}{% endif %}:
        {%- if method.is_abstract %}
        pass
        {%- else %}
        # TODO: Implement {{ method.name }} method
        pass
        {%- endif %}
{% endfor -%}
{%- else %}
    pass
{%- endif %}
{% endfor %}
