
{% from 'reg_definitions.py.jinja' import register_class_attributes with context %}
{% from 'reg_definitions.py.jinja' import child_writable_register_getter with context %}
{% from 'reg_definitions.py.jinja' import child_readable_register_getter with context %}

{%- macro memory_class(node) %}
    {%- if node.is_sw_readable and node.is_sw_writable %}
class {{get_fully_qualified_type_name(node)}}_cls(MemoryReadWrite):
    {%- elif node.is_sw_readable and not node.is_sw_writable %}
class {{get_fully_qualified_type_name(node)}}_cls(MemoryReadOnly):
    {%- elif not node.is_sw_readable and node.is_sw_writable %}
class {{get_fully_qualified_type_name(node)}}_cls(MemoryWriteOnly):
    {%- endif %}
    """
    Class to represent a memory in the register model

    {{get_table_block(node) | indent}}
    """

    __slots__ : List[str] = [{%- for child_node in node.children(unroll=False) -%}{%- if isinstance(child_node, systemrdlRegNode) -%}'__{{child_node.inst_name}}'{% if not loop.last %}, {% endif %}{% endif %}{%- endfor %}]

    def __init__(self,
                 callbacks: CallbackSet,
                 address: int,
                 logger_handle: str,
                 inst_name: str,
                 parent:AddressMap):

        super().__init__(callbacks=callbacks,
                         address=address,
                         entries={{node.get_property('mementries')}},
                         {% if 'accesswidth' in node.list_properties() -%}accesswidth={{node.get_property('accesswidth')}}{%- else -%}accesswidth={{node.get_property('memwidth')}}{%- endif -%},
                         width={{node.get_property('memwidth')}},
                         logger_handle=logger_handle,
                         inst_name=inst_name,
                         parent=parent)

        {% for child_node in node.children(unroll=False) -%}
            {{ register_class_attributes(child_node) | indent }}
        {% endfor %}

        {%- for child_node in node.children(unroll=False) -%}
            {%- if isinstance(child_node, systemrdlRegNode)  %}
    @property
    def {{safe_node_name(child_node)}}(self) -> {% if child_node.is_array -%}{{get_fully_qualified_type_name(child_node)}}_array_cls{% else %}{{get_fully_qualified_type_name(child_node)}}_cls{%- endif -%}:
        """
        Property to access {{child_node.inst_name}} register {% if child_node.is_array -%}array{% endif %}

        {{get_table_block(child_node) | indent(8)}}
        """
        return self.__{{child_node.inst_name}}
            {% else %}
            {{ raise_template_error('unexpected type') }}
            {%- endif %}
        {% endfor %}

    {% if node.is_sw_readable %}
    {{ child_readable_register_getter(node) }}
    {% endif %}

    {% if node.is_sw_writable %}
    {{ child_writable_register_getter(node) }}
    {% endif %}

    @property
    def systemrdl_python_child_name_map(self) -> Dict[str, str]:
        """
        In some cases systemRDL names need to be converted make them python safe, this dictionary
        is used to map the original systemRDL names to the names of the python attributes of this
        class

        Returns: dictionary whose key is the systemRDL names and value it the property name
        """
        return {
            {%- for child_node in node.children(unroll=False) -%}
            '{{child_node.inst_name}}':'{{safe_node_name(child_node)}}',
            {%- endfor %}
            }

    {%- if node.is_array %}
        {%- if node.is_sw_readable and node.is_sw_writable %}
class {{get_fully_qualified_type_name(node)}}_array_cls(MemoryReadWriteArray):
        {%- elif node.is_sw_readable and not node.is_sw_writable %}
class {{get_fully_qualified_type_name(node)}}_array_cls(MemoryReadOnlyArray):
        {%- elif not node.is_sw_readable and node.is_sw_writable %}
class {{get_fully_qualified_type_name(node)}}_array_cls(MemoryWriteOnlyArray):
        {%- endif %}
    """
    Class to represent a memory array in the register model
    """
    __slots__: List[str] = []

    def __init__(self, logger_handle: str, inst_name: str,
                 parent: AddressMap,
                 address: int,
                 length: int,
                 stride: int,
                 callbacks: CallbackSet):

        elements = tuple([{{get_fully_qualified_type_name(node)}}_cls(callbacks=callbacks,address=address+(index * stride),
                          logger_handle=f'{logger_handle}.{inst_name}[{index:d}]',
                          inst_name=f'{inst_name}[{index:d}]', parent=parent) for index in range(length)])

        super().__init__(logger_handle=logger_handle, inst_name=inst_name,
                         parent=parent, elements=elements)

    def __getitem__(self, item) -> Union[{{get_fully_qualified_type_name(node)}}_cls, Tuple[{{get_fully_qualified_type_name(node)}}_cls, ...]]:
        # this cast is OK because an explict typing check was done in the __init__
        return cast(Union[{{get_fully_qualified_type_name(node)}}_cls, Tuple[{{get_fully_qualified_type_name(node)}}_cls, ...]], super().__getitem__(item))
    {%- endif %}

{%- endmacro %}

