#!/usr/bin/env python3
# This file is a part of marzer/soagen and is subject to the the terms of the MIT license.
# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
# See https://github.com/marzer/soagen/blob/master/LICENSE for the full license text.
# SPDX-License-Identifier: MIT

from xml.sax.saxutils import escape

from . import utils
from .column import *
from .configurable import Configurable
from .metavars import *
from .writer import *
from .version import *


class NatvisFile(Configurable):
    def __init__(self, config, structs):
        super().__init__(config)
        self.path = self.config.path.with_suffix('.natvis')
        self.structs = structs if utils.is_collection(structs) else [structs]

    def write(self, o: Writer):
        o(
            rf'''
		<?xml version="1.0" encoding="utf-8"?>
		<!--
		// This file was generated by soagen v{VERSION_STRING} - do not modify it directly
		// https://marzer.github.io/soagen
		-->
		<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
		'''
        )

        with Indent(o):
            for struct in self.structs:
                with MetaScope(self.config.meta_stack, struct.meta):
                    o(
                        rf'''
					<!--{"="*(120 - o.indent_width - 4)}
					{struct.name}
					{"="*(120 - o.indent_width - 3)}-->'''
                    )
                    with Indent(o, pre=f'\n\n<Type Name="{escape(struct.qualified_type)}">', post='</Type>'):
                        o(
                            r'''
						<Intrinsic Name="size" Expression="table_.count_" />
						<Intrinsic Name="size_bytes" Expression="table_.alloc_.size_in_bytes" />
						<Intrinsic Name="capacity" Expression="table_.capacity_.first_" />
						'''
                        )
                        for col in struct.columns:
                            o(
                                rf'''
							<Intrinsic
								Name="get_{col.index}"
								Expression="reinterpret_cast&lt;{escape(col.type)}*&gt;(table_.alloc_.columns[{col.index}])"
							/>
							'''
                            )
                        o(r'<DisplayString>{{ size={size()} }}</DisplayString>')
                        with Indent(o, pre='<Expand>', post='</Expand>\n'):
                            o(
                                r'''
							<Item Name="[size]">size()</Item>
							<Item Name="[capacity]">capacity()</Item>
							<Item Name="[allocation_size]">size_bytes()</Item>
							'''
                            )
                            for col in struct.columns:
                                get = rf'get_{col.index}()'
                                o(
                                    rf'''
								<Synthetic Name="{col.name}">
									<DisplayString Condition="size() &gt; 3u">{{{{ {{*({get})}}, {{*({get} + 1)}}, {{*({get} + 2)}}, ... }}}}</DisplayString>
									<DisplayString Condition="size() == 3u">{{{{ {{*({get})}}, {{*({get} + 1)}}, {{*({get} + 2)}} }}}}</DisplayString>
									<DisplayString Condition="size() == 2u">{{{{ {{*({get})}}, {{*({get} + 1)}} }}}}</DisplayString>
									<DisplayString Condition="size() == 1u">{{{{ {{*({get})}} }}}}</DisplayString>
									<DisplayString Condition="size() == 0u"></DisplayString>
									<Expand>
										<ArrayItems>
											<Size>size()</Size>
											<ValuePointer>{get}</ValuePointer>
										</ArrayItems>
									</Expand>
								</Synthetic>
								'''
                                )

                    row_types = [
                        rf'soagen::row<{struct.qualified_type}, {struct.column_indices}>',
                        rf'soagen::row<{struct.qualified_type}&, {struct.column_indices}>',
                        rf'soagen::row<{struct.qualified_type}&&, {struct.column_indices}>',
                        rf'soagen::row<const {struct.qualified_type}, {struct.column_indices}>',
                        rf'soagen::row<const {struct.qualified_type}&, {struct.column_indices}>',
                        rf'soagen::row<const {struct.qualified_type}&&, {struct.column_indices}>',
                    ]
                    with Indent(o, pre=f'\n\n<Type Name="{escape(row_types[0])}">', post='</Type>'):
                        for i in range(1, len(row_types)):
                            o(rf'<AlternativeType Name="{escape(row_types[i])}" />')

                        s = r''
                        if len(struct.columns) > 1:
                            s += r'{{ '
                        s += r'{'
                        s += r'}, {'.join(col.name for col in struct.columns[:8])
                        s += r'}'
                        if len(struct.columns) > 8:
                            s += r', ...'
                        if len(struct.columns) > 1:
                            s += r' }}'
                        o(rf'<DisplayString>{s}</DisplayString>')
                        with Indent(o, pre='<Expand>', post='</Expand>\n'):
                            for col in struct.columns:
                                o(rf'<Item Name="{col.name}">{col.name}</Item>')

        o(r'</AutoVisualizer>')


__all__ = [r'NatvisFile']
