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 MASCallout

#Region "Callout reveal motion"

        Private _calloutRevealRunner As MASMotionTimelineRunner
        Private _calloutRevealProgress As Single = 1.0F
        Private _hasCalloutRevealMotion As Boolean

        Friend Sub StartCalloutRevealMotion()
            If _disposedLocal Then Return

            StopCalloutRevealMotion(resetState:=False)
            _calloutRevealProgress = 0.0F
            _hasCalloutRevealMotion = True

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

            _calloutRevealRunner = MASMotionSystem.CreateTimelineRunner(
                owner:=Me,
                consumerName:="MASCallout.PanelReveal",
                plan:=plan,
                requestFrame:=AddressOf InvalidateVisual,
                applyFrame:=AddressOf ApplyCalloutRevealMotionFrame,
                completed:=AddressOf CompleteCalloutRevealMotionFrame)
            _calloutRevealRunner.Start()

            InvalidateVisual()
        End Sub

        Private Sub ApplyCalloutRevealMotionFrame(frame As MASMotionFrame)
            If frame Is Nothing Then Return
            _calloutRevealProgress = MASMotionSystem.ClampProgress(frame.EasedProgress)
            _hasCalloutRevealMotion = True
            InvalidateVisual()
        End Sub

        Private Sub CompleteCalloutRevealMotionFrame(frame As MASMotionFrame)
            StopCalloutRevealMotion(resetState:=True)
            InvalidateVisual()
        End Sub

        Private Sub StopCalloutRevealMotion(resetState As Boolean)
            If _calloutRevealRunner IsNot Nothing Then
                _calloutRevealRunner.Dispose()
                _calloutRevealRunner = Nothing
            End If

            If resetState Then
                _calloutRevealProgress = 1.0F
                _hasCalloutRevealMotion = False
            End If
        End Sub

        Private Function IsCalloutRevealMotionActive() As Boolean
            Return _hasCalloutRevealMotion AndAlso _calloutRevealRunner IsNot Nothing AndAlso _calloutRevealRunner.IsRunning
        End Function

        Private Sub DrawCalloutRevealMotionOverlay(canvas As SKCanvas,
                                                   ctx As MASThemeContext,
                                                   bounds As SKRect,
                                                   dpi As Single)
            If canvas Is Nothing OrElse Not IsCalloutRevealMotionActive() Then Return
            If bounds.Width <= 1.0F OrElse bounds.Height <= 1.0F Then Return

            Dim progress As Single = MASMotionSystem.ClampProgress(_calloutRevealProgress)
            Dim fade As Single = 1.0F - progress
            If fade <= 0.001F Then Return

            Dim inset As Single = progress * 3.0F * dpi
            Dim overlayBounds As New SKRect(bounds.Left + inset,
                                            bounds.Top + inset,
                                            bounds.Right - inset,
                                            bounds.Bottom - inset)
            If overlayBounds.Width <= 1.0F OrElse overlayBounds.Height <= 1.0F Then Return

            Dim alpha As Byte = CByte(Math.Max(0, Math.Min(80, CInt(Math.Round(58.0R * CDbl(fade))))))
            Dim radius As Single = Math.Max(8.0F * dpi, 1.0F)

            Using paint As New SKPaint With {
                .IsAntialias = True,
                .Style = SKPaintStyle.Stroke,
                .StrokeWidth = Math.Max(1.0F, 1.25F * dpi),
                .Color = ResolveCalloutMotionAccent(ctx).WithAlpha(alpha),
                .BlendMode = SKBlendMode.SrcOver
            }
                canvas.DrawRoundRect(overlayBounds, radius, radius, paint)
            End Using
        End Sub

        Private Shared Function ResolveCalloutMotionAccent(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.BrandTheme IsNot Nothing Then Return ctx.BrandTheme.BrandPrimary
            If ctx IsNot Nothing AndAlso ctx.SemanticTheme IsNot Nothing Then Return ctx.SemanticTheme.Info
            Return Nexamas.UI.Values.Color.Accent.Accent2
        End Function

#End Region

    End Class

End Namespace
