Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Controls
Imports SkiaSharp

Namespace Nexamas.UI.Components

    Partial Public NotInheritable Class MASAppLayout

#Region "Friend hosted slot content contract"

        Private Const AppSlotHeader As String = "header"
        Private Const AppSlotNavigation As String = "navigation"
        Private Const AppSlotContent As String = "content"
        Private Const AppSlotDetails As String = "details"
        Private Const AppSlotStatus As String = "status"

        Private ReadOnly _hostedAppLayoutContent As New Dictionary(Of String, MASControlBase)(StringComparer.OrdinalIgnoreCase)
        Private _hostedAppLayoutLifecycleGeneration As Integer

        Friend Function HostSlotContent(slotKey As String,
                                        child As MASControlBase) As Boolean
            If child Is Nothing Then Return False
            Dim key As String = NormalizeAppLayoutSlotKey(slotKey)
            If key.Length = 0 Then Return False

            Dim existing As MASControlBase = Nothing
            If _hostedAppLayoutContent.TryGetValue(key, existing) Then
                If Object.ReferenceEquals(existing, child) Then Return True
                If existing IsNot Nothing Then UnregisterChild(existing)
                _hostedAppLayoutContent.Remove(key)
            End If

            RegisterChild(child)
            If String.IsNullOrWhiteSpace(child.Name) Then child.Name = "AppLayoutSlotHost_" & key
            _hostedAppLayoutContent.Add(key, child)
            _hostedAppLayoutLifecycleGeneration += 1
            InvalidateVisual()
            Return True
        End Function

        Friend Function UnhostSlotContent(slotKey As String,
                                          Optional disposeChild As Boolean = False) As Boolean
            Dim key As String = NormalizeAppLayoutSlotKey(slotKey)
            If key.Length = 0 Then Return False
            Dim child As MASControlBase = Nothing
            If Not _hostedAppLayoutContent.TryGetValue(key, child) Then Return False
            _hostedAppLayoutContent.Remove(key)
            If child IsNot Nothing Then
                UnregisterChild(child)
                If disposeChild Then child.Dispose()
            End If
            _hostedAppLayoutLifecycleGeneration += 1
            InvalidateVisual()
            Return True
        End Function

        Friend Function ClearHostedSlotContent(Optional disposeChildren As Boolean = False) As Boolean
            If _hostedAppLayoutContent.Count = 0 Then Return True
            Dim children As New List(Of MASControlBase)(_hostedAppLayoutContent.Values)
            _hostedAppLayoutContent.Clear()
            For Each child As MASControlBase In children
                If child Is Nothing Then Continue For
                UnregisterChild(child)
                If disposeChildren Then child.Dispose()
            Next
            _hostedAppLayoutLifecycleGeneration += 1
            InvalidateVisual()
            Return True
        End Function

        Friend Function CreateHostedSlotContentSnapshot() As MASHostedContentContractSnapshot
            Dim slots As New List(Of MASHostedContentSlotSnapshot)()
            AddAppLayoutSlotSnapshot(slots, AppSlotHeader, MASHostedContentSlotKind.AppLayoutHeader, True)
            AddAppLayoutSlotSnapshot(slots, AppSlotNavigation, MASHostedContentSlotKind.AppLayoutNavigation, _showNavigation)
            AddAppLayoutSlotSnapshot(slots, AppSlotContent, MASHostedContentSlotKind.AppLayoutContent, True)
            AddAppLayoutSlotSnapshot(slots, AppSlotDetails, MASHostedContentSlotKind.AppLayoutDetails, _showDetails)
            AddAppLayoutSlotSnapshot(slots, AppSlotStatus, MASHostedContentSlotKind.AppLayoutStatus, _showStatusBar)
            Return New MASHostedContentContractSnapshot("applayout", _hostedAppLayoutLifecycleGeneration, slots)
        End Function

        Friend Function HasSlotHostingContractForTests() As Boolean
            Dim header As MASControlBase = MASButton.Create("Header host")
            Dim content As MASControlBase = MASButton.Create("Content host")
            If Not HostSlotContent(AppSlotHeader, header) Then Return False
            If Not HostSlotContent(AppSlotContent, content) Then Return False
            PlaceAppLayoutHostedContent(AppSlotHeader, New SKRect(0.0F, 0.0F, 260.0F, 56.0F), 1.0F, True)
            PlaceAppLayoutHostedContent(AppSlotContent, New SKRect(0.0F, 64.0F, 320.0F, 240.0F), 1.0F, True)
            Dim snapshot As MASHostedContentContractSnapshot = CreateHostedSlotContentSnapshot()
            Dim hosted As Boolean = snapshot IsNot Nothing AndAlso
                                     snapshot.IsStructurallyValid AndAlso
                                     snapshot.HasHostedSlot(AppSlotHeader) AndAlso
                                     snapshot.HasVisibleHostedSlot(AppSlotHeader) AndAlso
                                     snapshot.HasHostedSlot(AppSlotContent) AndAlso
                                     snapshot.HasVisibleHostedSlot(AppSlotContent)
            Dim removed As Boolean = UnhostSlotContent(AppSlotHeader, disposeChild:=True)
            removed = UnhostSlotContent(AppSlotContent, disposeChild:=True) AndAlso removed
            Dim after As MASHostedContentContractSnapshot = CreateHostedSlotContentSnapshot()
            Return hosted AndAlso removed AndAlso after IsNot Nothing AndAlso Not after.HasHostedSlot(AppSlotHeader) AndAlso Not after.HasHostedSlot(AppSlotContent)
        End Function

        Private Sub AddAppLayoutSlotSnapshot(slots As List(Of MASHostedContentSlotSnapshot),
                                             slotKey As String,
                                             slotKind As MASHostedContentSlotKind,
                                             isVisible As Boolean)
            Dim child As MASControlBase = Nothing
            _hostedAppLayoutContent.TryGetValue(slotKey, child)
            slots.Add(MASHostedContentContractPolicy.CreateSnapshot(
                "applayout",
                slotKey,
                slotKind,
                child,
                isVisible AndAlso child IsNot Nothing AndAlso child.Visible,
                If(child Is Nothing, SKRect.Empty, child.BoundsLogical),
                ResolveHostedContentClip(child),
                _hostedAppLayoutLifecycleGeneration))
        End Sub

        Private Sub PlaceAppLayoutHostedContent(slotKey As String,
                                                boundsPx As SKRect,
                                                dpi As Single,
                                                isVisible As Boolean)
            Dim key As String = NormalizeAppLayoutSlotKey(slotKey)
            If key.Length = 0 Then Return
            Dim child As MASControlBase = Nothing
            If Not _hostedAppLayoutContent.TryGetValue(key, child) Then Return
            If Not isVisible Then
                child.Visible = False
                Return
            End If
            MASHostedContentContractPolicy.PlaceChild(child, boundsPx, dpi, boundsPx)
        End Sub

        Private Shared Function NormalizeAppLayoutSlotKey(slotKey As String) As String
            Dim key As String = MASHostedContentContractPolicy.NormalizeSlotKey(slotKey, String.Empty).ToLowerInvariant()
            Select Case key
                Case AppSlotHeader, AppSlotNavigation, AppSlotContent, AppSlotDetails, AppSlotStatus
                    Return key
                Case "nav"
                    Return AppSlotNavigation
                Case "detail", "right"
                    Return AppSlotDetails
                Case "footer", "statusbar"
                    Return AppSlotStatus
                Case Else
                    Return String.Empty
            End Select
        End Function

        Private Shared Function ResolveHostedContentClip(child As MASControlBase) As System.Nullable(Of SKRect)
            If child Is Nothing Then Return Nothing
            Return child.ClipBoundsLogicalInternal
        End Function


#End Region

    End Class

End Namespace
