
{% 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 {{child_node.inst_name}}(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}}
            {%- endif %}
        {% endfor %}

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

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

    {%- 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,
                 elements: Tuple[{{get_fully_qualified_type_name(node)}}_cls, ...]):

        for element in elements:
            if not isinstance(element, {{get_fully_qualified_type_name(node)}}_cls):
                raise TypeError(f'All Elements should be of type {{get_fully_qualified_type_name(node)}}_cls, '
                                f'found {type(element)}')

        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 %}
