Option Strict On
Option Explicit On

Imports System

Namespace Nexamas.UI.Components

    Friend Enum MASSplitViewKeyboardSplitterTarget
        LeftDivider = 1
        RightDivider = 2
    End Enum

    Friend Enum MASSplitViewKeyboardSplitterCommand
        FocusLeftDivider = 1
        FocusRightDivider = 2
        MoveNegativeSmall = 3
        MovePositiveSmall = 4
        MoveNegativeLarge = 5
        MovePositiveLarge = 6
        CollapseFocusedPane = 7
        ExpandFocusedPane = 8
        ResetLayout = 9
    End Enum

    ''' <summary>
    ''' Friend-only snapshot of the keyboard splitter state. It proves that keyboard
    ''' resizing has an owned focus target, bounded ratios, deterministic increments,
    ''' and explicit collapsed-state semantics without becoming a shell integration
    ''' or native panel system.
    ''' </summary>
    Friend NotInheritable Class MASSplitViewKeyboardSplitterSnapshot
        Friend Sub New(version As Integer,
                       focusedTarget As MASSplitViewKeyboardSplitterTarget,
                       leftPaneRatio As Single,
                       rightPaneRatio As Single,
                       leftPaneCollapsed As Boolean,
                       rightPaneCollapsed As Boolean,
                       smallStep As Single,
                       largeStep As Single)
            Me.Version = Math.Max(1, version)
            Me.FocusedTarget = focusedTarget
            Dim leftRatio As Single = MASSplitViewPolicy.ClampRatio(leftPaneRatio)
            Dim rightRatio As Single = MASSplitViewPolicy.ClampRatio(rightPaneRatio)
            MASSplitViewPolicy.NormalizeSideRatios(leftRatio, rightRatio)
            Me.LeftPaneRatio = leftRatio
            Me.RightPaneRatio = rightRatio
            Me.LeftPaneCollapsed = leftPaneCollapsed
            Me.RightPaneCollapsed = rightPaneCollapsed
            Me.SmallStep = Math.Max(0.001F, smallStep)
            Me.LargeStep = Math.Max(Me.SmallStep, largeStep)
        End Sub

        Friend ReadOnly Property Version As Integer
        Friend ReadOnly Property FocusedTarget As MASSplitViewKeyboardSplitterTarget
        Friend ReadOnly Property LeftPaneRatio As Single
        Friend ReadOnly Property RightPaneRatio As Single
        Friend ReadOnly Property LeftPaneCollapsed As Boolean
        Friend ReadOnly Property RightPaneCollapsed As Boolean
        Friend ReadOnly Property SmallStep As Single
        Friend ReadOnly Property LargeStep As Single

        Friend ReadOnly Property HasBoundedRatios As Boolean
            Get
                Return LeftPaneRatio >= SplitViewTokens.MinPaneRatio AndAlso
                       LeftPaneRatio <= SplitViewTokens.MaxPaneRatio AndAlso
                       RightPaneRatio >= SplitViewTokens.MinPaneRatio AndAlso
                       RightPaneRatio <= SplitViewTokens.MaxPaneRatio AndAlso
                       LeftPaneRatio + RightPaneRatio <= SplitViewTokens.MaxCombinedSideRatio + 0.001F
            End Get
        End Property

        Friend ReadOnly Property HasKeyboardSplitterContract As Boolean
            Get
                Return HasBoundedRatios AndAlso
                       SmallStep > 0.0F AndAlso
                       LargeStep >= SmallStep AndAlso
                       (FocusedTarget = MASSplitViewKeyboardSplitterTarget.LeftDivider OrElse FocusedTarget = MASSplitViewKeyboardSplitterTarget.RightDivider)
            End Get
        End Property
    End Class

    Partial Public NotInheritable Class MASSplitView

        Friend Function CreateKeyboardSplitterSnapshot() As MASSplitViewKeyboardSplitterSnapshot
            Return New MASSplitViewKeyboardSplitterSnapshot(
                1,
                ResolveKeyboardSplitterTarget(),
                _leftPaneRatio,
                _rightPaneRatio,
                _leftPaneCollapsed,
                _rightPaneCollapsed,
                SplitViewTokens.KeyboardRatioStep,
                SplitViewTokens.KeyboardLargeRatioStep)
        End Function

        Friend Function ApplyKeyboardSplitterCommand(command As MASSplitViewKeyboardSplitterCommand) As Boolean
            Select Case command
                Case MASSplitViewKeyboardSplitterCommand.FocusLeftDivider
                    Return SetKeyboardDivider(SplitDividerSide.Left)
                Case MASSplitViewKeyboardSplitterCommand.FocusRightDivider
                    Return SetKeyboardDivider(SplitDividerSide.Right)
                Case MASSplitViewKeyboardSplitterCommand.MoveNegativeSmall
                    Return ApplyKeyboardSplitterDelta(-SplitViewTokens.KeyboardRatioStep)
                Case MASSplitViewKeyboardSplitterCommand.MovePositiveSmall
                    Return ApplyKeyboardSplitterDelta(SplitViewTokens.KeyboardRatioStep)
                Case MASSplitViewKeyboardSplitterCommand.MoveNegativeLarge
                    Return ApplyKeyboardSplitterDelta(-SplitViewTokens.KeyboardLargeRatioStep)
                Case MASSplitViewKeyboardSplitterCommand.MovePositiveLarge
                    Return ApplyKeyboardSplitterDelta(SplitViewTokens.KeyboardLargeRatioStep)
                Case MASSplitViewKeyboardSplitterCommand.CollapseFocusedPane
                    Return SetKeyboardSplitterCollapsed(True)
                Case MASSplitViewKeyboardSplitterCommand.ExpandFocusedPane
                    Return SetKeyboardSplitterCollapsed(False)
                Case MASSplitViewKeyboardSplitterCommand.ResetLayout
                    Dim snapshot As MASSplitViewKeyboardSplitterSnapshot = CreateKeyboardSplitterSnapshot()
                    ResetPaneLayout()
                    Return snapshot IsNot Nothing AndAlso CreateKeyboardSplitterSnapshot().HasKeyboardSplitterContract
            End Select

            Return False
        End Function

        Friend Function HasKeyboardSplitterContractForTests() As Boolean
            ResetPaneLayout()
            If Not MASSplitViewPolicy.HasKeyboardSplitterContractPath() Then Return False
            Dim initial As MASSplitViewKeyboardSplitterSnapshot = CreateKeyboardSplitterSnapshot()
            If initial Is Nothing OrElse Not initial.HasKeyboardSplitterContract Then Return False

            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.FocusLeftDivider) Then Return False
            Dim leftBefore As Single = _leftPaneRatio
            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.MovePositiveSmall) Then Return False
            Dim afterSmall As MASSplitViewKeyboardSplitterSnapshot = CreateKeyboardSplitterSnapshot()
            If afterSmall Is Nothing OrElse Not afterSmall.HasKeyboardSplitterContract Then Return False
            If _leftPaneRatio <= leftBefore Then Return False

            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.MoveNegativeLarge) Then Return False
            Dim afterLarge As MASSplitViewKeyboardSplitterSnapshot = CreateKeyboardSplitterSnapshot()
            If afterLarge Is Nothing OrElse Not afterLarge.HasKeyboardSplitterContract Then Return False
            If _leftPaneRatio >= afterSmall.LeftPaneRatio Then Return False

            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.CollapseFocusedPane) Then Return False
            If Not _leftPaneCollapsed Then Return False
            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.ExpandFocusedPane) Then Return False
            If _leftPaneCollapsed Then Return False

            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.FocusRightDivider) Then Return False
            Dim rightBefore As Single = _rightPaneRatio
            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.MovePositiveSmall) Then Return False
            If _rightPaneRatio <= rightBefore Then Return False
            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.CollapseFocusedPane) Then Return False
            If Not _rightPaneCollapsed Then Return False
            If Not ApplyKeyboardSplitterCommand(MASSplitViewKeyboardSplitterCommand.ExpandFocusedPane) Then Return False
            If _rightPaneCollapsed Then Return False

            Dim finalSnapshot As MASSplitViewKeyboardSplitterSnapshot = CreateKeyboardSplitterSnapshot()
            If finalSnapshot Is Nothing OrElse Not finalSnapshot.HasKeyboardSplitterContract Then Return False

            Return True
        End Function

        Private Function SetKeyboardDivider(side As SplitDividerSide) As Boolean
            If side <> SplitDividerSide.Left AndAlso side <> SplitDividerSide.Right Then Return False
            Dim changed As Boolean = _keyboardDivider <> side
            _keyboardDivider = side
            _hoverDivider = side
            If changed Then InvalidateVisual()
            Return True
        End Function

        Private Function ApplyKeyboardSplitterDelta(delta As Single) As Boolean
            If delta = 0.0F Then Return False
            Dim oldLeft As Single = _leftPaneRatio
            Dim oldRight As Single = _rightPaneRatio
            Dim oldLeftCollapsed As Boolean = _leftPaneCollapsed
            Dim oldRightCollapsed As Boolean = _rightPaneCollapsed

            If _keyboardDivider = SplitDividerSide.Right Then
                _rightPaneCollapsed = False
                _rightPaneRatio = MASSplitViewPolicy.ClampRatio(_rightPaneRatio + delta)
            Else
                _keyboardDivider = SplitDividerSide.Left
                _leftPaneCollapsed = False
                _leftPaneRatio = MASSplitViewPolicy.ClampRatio(_leftPaneRatio + delta)
            End If
            MASSplitViewPolicy.NormalizeSideRatios(_leftPaneRatio, _rightPaneRatio)

            Dim changed As Boolean =
                oldLeftCollapsed <> _leftPaneCollapsed OrElse
                oldRightCollapsed <> _rightPaneCollapsed OrElse
                MASResizeInteractionPolicy.HasMeaningfulRatioChange(oldLeft, _leftPaneRatio) OrElse
                MASResizeInteractionPolicy.HasMeaningfulRatioChange(oldRight, _rightPaneRatio)
            If Not changed Then Return False

            RequestSizeLayoutRefreshForSizeAffectingChange("MASSplitView.KeyboardSplitter")
            InvalidateVisual()
            RaiseSplitViewChangedSafe()
            Return True
        End Function

        Private Function SetKeyboardSplitterCollapsed(collapsed As Boolean) As Boolean
            Dim changed As Boolean = False
            If _keyboardDivider = SplitDividerSide.Right Then
                changed = _rightPaneCollapsed <> collapsed
                _rightPaneCollapsed = collapsed
            Else
                _keyboardDivider = SplitDividerSide.Left
                changed = _leftPaneCollapsed <> collapsed
                _leftPaneCollapsed = collapsed
            End If
            If Not changed Then Return False
            RequestSizeLayoutRefreshForSizeAffectingChange("MASSplitView.KeyboardSplitterCollapse")
            InvalidateVisual()
            RaiseSplitViewChangedSafe()
            Return True
        End Function

        Private Function ResolveKeyboardSplitterTarget() As MASSplitViewKeyboardSplitterTarget
            If _keyboardDivider = SplitDividerSide.Right Then Return MASSplitViewKeyboardSplitterTarget.RightDivider
            Return MASSplitViewKeyboardSplitterTarget.LeftDivider
        End Function

    End Class

End Namespace
