Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Motion
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Components

Namespace Nexamas.UI.Controls

    Partial Public NotInheritable Class MASTabControl


#Region "Scrolling"

        Private Sub ScrollByNav(kind As MASTabNavButtonKind)
            Dim stepPx As Single = MASTabPremiumVisualPolicy.ResolveNavigationScrollStep(_viewportWidthPx, ResolveCurrentDpi(Nothing))

            Select Case kind
                Case MASTabNavButtonKind.LeftButton
                    AnimateScrollTo(_targetScrollOffsetPx - stepPx)

                Case MASTabNavButtonKind.RightButton
                    AnimateScrollTo(_targetScrollOffsetPx + stepPx)
            End Select
        End Sub

        Private Sub EnsureSelectedVisible()
            _pendingEnsureSelectedVisible = True
            InvalidateVisual()
        End Sub

        Private Sub AnimateScrollTo(targetPx As Single)
            _targetScrollOffsetPx = ClampScroll(targetPx)

            If Math.Abs(_targetScrollOffsetPx - _scrollOffsetPx) <= 0.25F Then
                _scrollOffsetPx = _targetScrollOffsetPx
                StopAnimation()
                InvalidateVisual()
                Return
            End If

            StopAnimation()
            _scrollMotionStartPx = _scrollOffsetPx

            Dim plan As MASMotionTransitionPlan = MASMotionSystem.CreateTransitionPlan(MASMotionTokenId.SelectionMove, 0.0F, 1.0F)
            If Not plan.ShouldAnimate Then
                _scrollOffsetPx = _targetScrollOffsetPx
                InvalidateVisual()
                Return
            End If

            _scrollMotionRunner = MASMotionSystem.CreateTimelineRunner(
                owner:=Me,
                consumerName:="MASTabControl.TabScroll",
                plan:=plan,
                requestFrame:=AddressOf InvalidateVisual,
                applyFrame:=AddressOf ApplyScrollMotionFrame,
                completed:=AddressOf CompleteScrollMotionFrame)
            _scrollMotionRunner.Start()

            InvalidateVisual()
        End Sub

        Private Sub ApplyScrollMotionFrame(frame As MASMotionFrame)
            If frame Is Nothing Then Return

            Dim progress As Single = MASMotionSystem.ClampProgress(frame.Value)
            _scrollOffsetPx = ClampScroll(_scrollMotionStartPx + ((_targetScrollOffsetPx - _scrollMotionStartPx) * progress))
            InvalidateVisual()
        End Sub

        Private Sub CompleteScrollMotionFrame(frame As MASMotionFrame)
            _scrollOffsetPx = _targetScrollOffsetPx
            _scrollMotionRunner = Nothing
            InvalidateVisual()
        End Sub

        Private Sub StopAnimation()
            If _scrollMotionRunner IsNot Nothing Then
                _scrollMotionRunner.Dispose()
                _scrollMotionRunner = Nothing
            End If
        End Sub

        Friend Sub UpdateScrollMetrics(maxScrollOffsetPx As Single,
                                       viewportWidthPx As Single)

            _maxScrollOffsetPx = Math.Max(0.0F, maxScrollOffsetPx)
            _viewportWidthPx = Math.Max(0.0F, viewportWidthPx)

            _scrollOffsetPx = ClampScroll(_scrollOffsetPx)
            _targetScrollOffsetPx = ClampScroll(_targetScrollOffsetPx)
        End Sub

        Friend Sub RequestEnsureSelectedVisible(targetOffsetPx As Single)
            _pendingEnsureSelectedVisible = False
            AnimateScrollTo(targetOffsetPx)
        End Sub

        Friend Function ConsumeEnsureSelectedVisibleRequest() As Boolean
            Return _pendingEnsureSelectedVisible
        End Function

        Friend Function ClampScroll(value As Single) As Single
            If value < 0.0F Then Return 0.0F
            If value > _maxScrollOffsetPx Then Return _maxScrollOffsetPx
            Return value
        End Function

        Private Shared Function ResolveCurrentDpi(ctx As MASThemeContext) As Single
            If ctx IsNot Nothing Then
                Dim ctxDpi As Single = ctx.Dpi
                If ctxDpi > 0.0F AndAlso Not Single.IsNaN(ctxDpi) AndAlso Not Single.IsInfinity(ctxDpi) Then
                    Return ctxDpi
                End If
            End If

            Return 1.0F
        End Function

#End Region


    End Class

End Namespace
