Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Motion
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Controls

    Partial Public NotInheritable Class MASStepper

#Region "Current step motion"

        Private _currentStepRunner As MASMotionTimelineRunner
        Private _currentStepMotionFromIndex As Integer = -1
        Private _currentStepMotionToIndex As Integer = -1
        Private _currentStepMotionProgress As Single = 1.0F
        Private _hasCurrentStepMotion As Boolean

        Private Sub StartCurrentStepMotion(previousIndex As Integer,
                                           nextIndex As Integer)
            StopCurrentStepMotion(resetState:=False)

            If previousIndex < 0 OrElse nextIndex < 0 OrElse previousIndex = nextIndex Then
                _hasCurrentStepMotion = False
                _currentStepMotionProgress = 1.0F
                Return
            End If

            _currentStepMotionFromIndex = previousIndex
            _currentStepMotionToIndex = nextIndex
            _currentStepMotionProgress = 0.0F
            _hasCurrentStepMotion = True

            Dim plan As MASMotionTransitionPlan = MASMotionSystem.CreateTransitionPlan(MASMotionTokenId.IndicatorMove, 0.0F, 1.0F)
            If Not plan.ShouldAnimate Then
                CompleteCurrentStepMotionFrame(Nothing)
                Return
            End If

            _currentStepRunner = MASMotionSystem.CreateTimelineRunner(
                owner:=Me,
                consumerName:="MASStepper.CurrentStep",
                plan:=plan,
                requestFrame:=AddressOf InvalidateVisual,
                applyFrame:=AddressOf ApplyCurrentStepMotionFrame,
                completed:=AddressOf CompleteCurrentStepMotionFrame)
            _currentStepRunner.Start()

            InvalidateVisual()
        End Sub

        Private Sub ApplyCurrentStepMotionFrame(frame As MASMotionFrame)
            If frame Is Nothing Then Return
            _currentStepMotionProgress = MASMotionSystem.ClampProgress(frame.Value)
            _hasCurrentStepMotion = True
            InvalidateVisual()
        End Sub

        Private Sub CompleteCurrentStepMotionFrame(frame As MASMotionFrame)
            StopCurrentStepMotion(resetState:=True)
            InvalidateVisual()
        End Sub

        Private Sub StopCurrentStepMotion(resetState As Boolean)
            If _currentStepRunner IsNot Nothing Then
                _currentStepRunner.Dispose()
                _currentStepRunner = Nothing
            End If

            If resetState Then
                _currentStepMotionFromIndex = -1
                _currentStepMotionToIndex = -1
                _currentStepMotionProgress = 1.0F
                _hasCurrentStepMotion = False
            End If
        End Sub

        Private Function IsCurrentStepMotionActive() As Boolean
            Return _hasCurrentStepMotion AndAlso _currentStepRunner IsNot Nothing AndAlso _currentStepRunner.IsRunning
        End Function

        Private Sub DrawCurrentStepMotionOverlay(canvas As SKCanvas,
                                                 ctx As MASThemeContext,
                                                 bounds As SKRect,
                                                 plan As MASStepperLayoutPlan)
            If canvas Is Nothing OrElse plan Is Nothing OrElse Not IsCurrentStepMotionActive() Then Return
            If _currentStepMotionFromIndex < 0 OrElse _currentStepMotionFromIndex >= _steps.Count Then Return
            If _currentStepMotionToIndex < 0 OrElse _currentStepMotionToIndex >= _steps.Count Then Return

            Dim fromPoint As SKPoint = ResolveStepNodePoint(bounds, plan, _currentStepMotionFromIndex)
            Dim toPoint As SKPoint = ResolveStepNodePoint(bounds, plan, _currentStepMotionToIndex)
            If Single.IsNaN(fromPoint.X) OrElse Single.IsNaN(fromPoint.Y) OrElse Single.IsNaN(toPoint.X) OrElse Single.IsNaN(toPoint.Y) Then Return

            Dim progress As Single = MASMotionSystem.ClampProgress(_currentStepMotionProgress)
            Dim x As Single = fromPoint.X + ((toPoint.X - fromPoint.X) * progress)
            Dim y As Single = fromPoint.Y + ((toPoint.Y - fromPoint.Y) * progress)
            Dim radius As Single = plan.RadiusPx + (2.0F * plan.Dpi)

            Using paint As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(1.0F, plan.ConnectorStrokePx),
                .Color = ResolveAccentColor(ctx).WithAlpha(StepperTokens.CurrentAlpha),
                .BlendMode = SKBlendMode.SrcOver
            }
                canvas.DrawCircle(x, y, radius, paint)
            End Using
        End Sub

        Private Function ResolveStepNodePoint(bounds As SKRect,
                                              plan As MASStepperLayoutPlan,
                                              index As Integer) As SKPoint
            If plan Is Nothing OrElse bounds.Width <= 1.0F OrElse bounds.Height <= 1.0F OrElse index < 0 OrElse index >= _steps.Count Then
                Return New SKPoint(Single.NaN, Single.NaN)
            End If

            If _orientation = MASStepperOrientation.Vertical Then
                Dim left As Single = bounds.Left + plan.RadiusPx + plan.HorizontalEdgeInsetPx
                Dim top As Single = bounds.Top + plan.RadiusPx + plan.VerticalEdgeInsetPx
                Return New SKPoint(left, top + plan.VerticalStepHeightPx * index)
            End If

            Dim count As Integer = _steps.Count
            Dim radius As Single = plan.RadiusPx
            Dim topY As Single = bounds.Top + plan.VerticalEdgeInsetPx
            Dim centerY As Single = topY + radius
            Dim leftX As Single = bounds.Left + radius + plan.HorizontalEdgeInsetPx
            Dim rightX As Single = bounds.Right - radius - plan.HorizontalEdgeInsetPx
            Dim usableWidth As Single = Math.Max(1.0F, rightX - leftX)
            Dim stepGap As Single = If(count = 1, 0.0F, usableWidth / CSng(count - 1))
            Dim visualIndex As Integer = If(MASStepperFlowPolicy.ResolveRightToLeft(), count - 1 - index, index)
            Return New SKPoint(leftX + stepGap * visualIndex, centerY)
        End Function

#End Region

    End Class

End Namespace
