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 MASSplitView

#Region "Friend hosted pane content contract"

        Private Const SplitSlotLeft As String = "left"
        Private Const SplitSlotContent As String = "content"
        Private Const SplitSlotRight As String = "right"

        Private ReadOnly _hostedSplitPaneContent As New Dictionary(Of String, MASControlBase)(StringComparer.OrdinalIgnoreCase)
        Private _hostedSplitPaneLifecycleGeneration As Integer

        Friend Function HostPaneContent(paneKey As String,
                                        child As MASControlBase) As Boolean
            If child Is Nothing Then Return False
            Dim key As String = NormalizeSplitPaneKey(paneKey)
            If key.Length = 0 Then Return False

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

            RegisterChild(child)
            If String.IsNullOrWhiteSpace(child.Name) Then child.Name = "SplitViewPaneHost_" & key
            _hostedSplitPaneContent.Add(key, child)
            _hostedSplitPaneLifecycleGeneration += 1
            InvalidateVisual()
            Return True
        End Function

        Friend Function UnhostPaneContent(paneKey As String,
                                          Optional disposeChild As Boolean = False) As Boolean
            Dim key As String = NormalizeSplitPaneKey(paneKey)
            If key.Length = 0 Then Return False
            Dim child As MASControlBase = Nothing
            If Not _hostedSplitPaneContent.TryGetValue(key, child) Then Return False
            _hostedSplitPaneContent.Remove(key)
            If child IsNot Nothing Then
                UnregisterChild(child)
                If disposeChild Then child.Dispose()
            End If
            _hostedSplitPaneLifecycleGeneration += 1
            InvalidateVisual()
            Return True
        End Function

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

        Friend Function CreateHostedPaneContentSnapshot() As MASHostedContentContractSnapshot
            Dim slots As New List(Of MASHostedContentSlotSnapshot)()
            AddSplitPaneSnapshot(slots, SplitSlotLeft, MASHostedContentSlotKind.SplitViewLeftPane, Not _leftPaneCollapsed)
            AddSplitPaneSnapshot(slots, SplitSlotContent, MASHostedContentSlotKind.SplitViewContentPane, True)
            AddSplitPaneSnapshot(slots, SplitSlotRight, MASHostedContentSlotKind.SplitViewRightPane, Not _rightPaneCollapsed)
            Return New MASHostedContentContractSnapshot("splitview", _hostedSplitPaneLifecycleGeneration, slots)
        End Function

        Friend Function HasPaneHostingContractForTests() As Boolean
            Dim left As MASControlBase = MASButton.Create("Left host")
            Dim content As MASControlBase = MASButton.Create("Content host")
            If Not HostPaneContent(SplitSlotLeft, left) Then Return False
            If Not HostPaneContent(SplitSlotContent, content) Then Return False
            PlaceSplitViewHostedContent(SplitSlotLeft, New SKRect(0.0F, 0.0F, 160.0F, 240.0F), 1.0F, True)
            PlaceSplitViewHostedContent(SplitSlotContent, New SKRect(168.0F, 0.0F, 420.0F, 240.0F), 1.0F, True)
            Dim snapshot As MASHostedContentContractSnapshot = CreateHostedPaneContentSnapshot()
            Dim hosted As Boolean = snapshot IsNot Nothing AndAlso
                                     snapshot.IsStructurallyValid AndAlso
                                     snapshot.HasHostedSlot(SplitSlotLeft) AndAlso
                                     snapshot.HasVisibleHostedSlot(SplitSlotLeft) AndAlso
                                     snapshot.HasHostedSlot(SplitSlotContent) AndAlso
                                     snapshot.HasVisibleHostedSlot(SplitSlotContent)
            Dim removed As Boolean = UnhostPaneContent(SplitSlotLeft, disposeChild:=True)
            removed = UnhostPaneContent(SplitSlotContent, disposeChild:=True) AndAlso removed
            Dim after As MASHostedContentContractSnapshot = CreateHostedPaneContentSnapshot()
            Return hosted AndAlso removed AndAlso after IsNot Nothing AndAlso Not after.HasHostedSlot(SplitSlotLeft) AndAlso Not after.HasHostedSlot(SplitSlotContent)
        End Function

        Private Sub AddSplitPaneSnapshot(slots As List(Of MASHostedContentSlotSnapshot),
                                         paneKey As String,
                                         slotKind As MASHostedContentSlotKind,
                                         isVisible As Boolean)
            Dim child As MASControlBase = Nothing
            _hostedSplitPaneContent.TryGetValue(paneKey, child)
            slots.Add(MASHostedContentContractPolicy.CreateSnapshot(
                "splitview",
                paneKey,
                slotKind,
                child,
                isVisible AndAlso child IsNot Nothing AndAlso child.Visible,
                If(child Is Nothing, SKRect.Empty, child.BoundsLogical),
                ResolveHostedContentClip(child),
                _hostedSplitPaneLifecycleGeneration))
        End Sub

        Private Sub PlaceSplitViewHostedContent(paneKey As String,
                                                boundsPx As SKRect,
                                                dpi As Single,
                                                isVisible As Boolean)
            Dim key As String = NormalizeSplitPaneKey(paneKey)
            If key.Length = 0 Then Return
            Dim child As MASControlBase = Nothing
            If Not _hostedSplitPaneContent.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 NormalizeSplitPaneKey(paneKey As String) As String
            Dim key As String = MASHostedContentContractPolicy.NormalizeSlotKey(paneKey, String.Empty).ToLowerInvariant()
            Select Case key
                Case SplitSlotLeft, "l"
                    Return SplitSlotLeft
                Case SplitSlotContent, "center", "middle", "c"
                    Return SplitSlotContent
                Case SplitSlotRight, "r"
                    Return SplitSlotRight
                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
