Option Strict On
Option Explicit On

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

Namespace Nexamas.UI.Rendering

    Friend NotInheritable Class MASSurfaceFramePainter
        Implements IDisposable

        Private ReadOnly _borderPainter As MASSurfaceFrameBorderPainter
        Private _disposed As Boolean

        Friend Sub New()
            _borderPainter = New MASSurfaceFrameBorderPainter()
        End Sub

        Friend Sub Draw(canvas As SKCanvas,
                        r As SKRect,
                        radius As Single,
                        dpi As Single,
                        surfaceTheme As IMASFrameSurfaceTheme,
                        Optional surfaceStrength As MASSurfaceFrameStrength = MASSurfaceFrameStrength.Level5,
                        Optional borderStrength As MASSurfaceFrameStrength = MASSurfaceFrameStrength.Level5)

            Draw(
                canvas:=canvas,
                r:=r,
                radius:=radius,
                dpi:=dpi,
                surfaceTheme:=surfaceTheme,
                surfaceStrength:=surfaceStrength,
                borderStrength:=borderStrength,
                opacity:=1.0F)
        End Sub

        Friend Sub Draw(canvas As SKCanvas,
                        r As SKRect,
                        radius As Single,
                        dpi As Single,
                        surfaceTheme As IMASFrameSurfaceTheme,
                        surfaceStrength As MASSurfaceFrameStrength,
                        borderStrength As MASSurfaceFrameStrength,
                        opacity As Single)

            If _disposed Then Return
            If canvas Is Nothing Then Return
            If surfaceTheme Is Nothing Then Return
            If r.Width <= 1.0F OrElse r.Height <= 1.0F Then Return

            Dim spec As MASSurfaceFrameSpec =
                MASSurfaceFrameFactory.Build(
                    surfaceTheme:=surfaceTheme,
                    surfaceStrength:=surfaceStrength,
                    borderStrength:=borderStrength,
                    opacity:=opacity)

            Draw(
                canvas:=canvas,
                r:=r,
                radius:=radius,
                dpi:=dpi,
                spec:=spec)
        End Sub

        Friend Sub Draw(canvas As SKCanvas,
                        r As SKRect,
                        radius As Single,
                        dpi As Single,
                        surfaceTheme As MASSurfaceFrameThemeProfile,
                        Optional surfaceStrength As MASSurfaceFrameStrength = MASSurfaceFrameStrength.Level5,
                        Optional borderStrength As MASSurfaceFrameStrength = MASSurfaceFrameStrength.Level5)

            Draw(
                canvas:=canvas,
                r:=r,
                radius:=radius,
                dpi:=dpi,
                surfaceTheme:=surfaceTheme,
                surfaceStrength:=surfaceStrength,
                borderStrength:=borderStrength,
                opacity:=1.0F)
        End Sub

        Friend Sub Draw(canvas As SKCanvas,
                        r As SKRect,
                        radius As Single,
                        dpi As Single,
                        surfaceTheme As MASSurfaceFrameThemeProfile,
                        surfaceStrength As MASSurfaceFrameStrength,
                        borderStrength As MASSurfaceFrameStrength,
                        opacity As Single)

            If _disposed Then Return
            If canvas Is Nothing Then Return
            If r.Width <= 1.0F OrElse r.Height <= 1.0F Then Return

            Dim spec As MASSurfaceFrameSpec =
                MASSurfaceFrameFactory.Build(
                    surfaceTheme:=surfaceTheme,
                    surfaceStrength:=surfaceStrength,
                    borderStrength:=borderStrength,
                    opacity:=opacity)

            Draw(
                canvas:=canvas,
                r:=r,
                radius:=radius,
                dpi:=dpi,
                spec:=spec)
        End Sub

        Friend Sub Draw(canvas As SKCanvas,
                        r As SKRect,
                        radius As Single,
                        dpi As Single,
                        spec As MASSurfaceFrameSpec)

            If _disposed Then Return
            If canvas Is Nothing Then Return
            If r.Width <= 1.0F OrElse r.Height <= 1.0F Then Return

            dpi = PixelSnap.SafeDpi(dpi)
            radius = PixelSnap.SafeRadius(Math.Max(0.0F, radius))

            Dim rm As MASSurfaceInteractionRing.Metrics = MASSurfaceInteractionRing.GetMetrics(dpi)
            Dim baseRect As SKRect = MASSurfaceInteractionRing.SnapBaseRect(r, rm)

            If baseRect.Width <= 1.0F OrElse baseRect.Height <= 1.0F Then Return

            MASSurfaceFrameBodyMaterialRenderer.DrawBody(canvas, baseRect, radius, dpi, spec.Body)
            MASSurfaceFrameBodyMaterialRenderer.DrawLift(canvas, baseRect, radius, dpi, spec.Lift)

            _borderPainter.Draw(
                canvas:=canvas,
                baseRect:=baseRect,
                baseRadiusPx:=radius,
                dpi:=dpi,
                spec:=ScaleBorderSpec(spec.Border, dpi))
        End Sub


        Friend Function TryDrawSwitchableSurface(canvas As SKCanvas,
                                                 ctx As MASThemeContext,
                                                 r As SKRect,
                                                 radius As Single,
                                                 dpi As Single,
                                                 consumerKind As MASSurfaceTreatmentConsumerKind,
                                                 Optional slot As MASSurfaceSlot = MASSurfaceSlot.Root,
                                                 Optional fallbackRole As MASSurfaceRole = MASSurfaceRole.Unknown,
                                                 Optional surfaceStrength As MASSurfaceFrameStrength = MASSurfaceFrameStrength.Level5,
                                                 Optional borderStrength As MASSurfaceFrameStrength = MASSurfaceFrameStrength.Level5,
                                                 Optional opacity As Single = 1.0F) As Boolean

            If _disposed Then Return False
            If Not MASSurfaceMaterialRuntimeSwitch.IsActive Then Return False
            If canvas Is Nothing OrElse ctx Is Nothing Then Return False
            If r.Width <= 1.0F OrElse r.Height <= 1.0F Then Return False

            Return MASSurfaceTreatmentRuntimeSurfaceVisual.TryDrawMaterialSlotSurfaceVisual(
                canvas:=canvas,
                ctx:=ctx,
                boundsPx:=r,
                consumerKind:=consumerKind,
                slot:=slot,
                materialKey:=MASSurfaceMaterialIds.Auto,
                dpi:=dpi,
                cornerRadiusPx:=radius,
                opacity:=opacity,
                fallbackRole:=fallbackRole,
                surfaceStrengthLevel:=CInt(surfaceStrength),
                borderStrengthLevel:=CInt(borderStrength),
                frameStrength:=surfaceStrength,
                requestedFrameStrength:=borderStrength,
                drawFrame:=True)
        End Function

        Friend Function TryDrawSwitchableViewportCardSurface(canvas As SKCanvas,
                                                               ctx As MASThemeContext,
                                                               r As SKRect,
                                                               radius As Single,
                                                               dpi As Single,
                                                               Optional opacity As Single = 1.0F) As Boolean

            Return TryDrawSwitchableSurface(
                canvas:=canvas,
                ctx:=ctx,
                r:=r,
                radius:=radius,
                dpi:=dpi,
                consumerKind:=MASSurfaceTreatmentConsumerKind.CardSurface,
                slot:=MASSurfaceSlot.Viewport,
                fallbackRole:=MASSurfaceRole.Card,
                opacity:=opacity)
        End Function

        Friend Function TryDrawSwitchableFloatingPopupSurface(canvas As SKCanvas,
                                                              ctx As MASThemeContext,
                                                              r As SKRect,
                                                              radius As Single,
                                                              dpi As Single,
                                                              Optional opacity As Single = 1.0F) As Boolean

            Return TryDrawSwitchableSurface(
                canvas:=canvas,
                ctx:=ctx,
                r:=r,
                radius:=radius,
                dpi:=dpi,
                consumerKind:=MASSurfaceTreatmentConsumerKind.TooltipSurface,
                slot:=MASSurfaceSlot.Floating,
                fallbackRole:=MASSurfaceRole.Popup,
                opacity:=opacity)
        End Function

        Friend Function TryDrawSwitchableFloatingToastSurface(canvas As SKCanvas,
                                                              ctx As MASThemeContext,
                                                              r As SKRect,
                                                              radius As Single,
                                                              dpi As Single,
                                                              Optional surfaceStrength As MASSurfaceFrameStrength = MASSurfaceFrameStrength.Level6,
                                                              Optional borderStrength As MASSurfaceFrameStrength = MASSurfaceFrameStrength.Level6,
                                                              Optional opacity As Single = 1.0F) As Boolean

            Return TryDrawSwitchableSurface(
                canvas:=canvas,
                ctx:=ctx,
                r:=r,
                radius:=radius,
                dpi:=dpi,
                consumerKind:=MASSurfaceTreatmentConsumerKind.ToastSurface,
                slot:=MASSurfaceSlot.Floating,
                fallbackRole:=MASSurfaceRole.Toast,
                surfaceStrength:=surfaceStrength,
                borderStrength:=borderStrength,
                opacity:=opacity)
        End Function

        Friend Shared Function ScaleBorderSpec(spec As MASSurfaceFrameBorderSpec,
                                               dpi As Single) As MASSurfaceFrameBorderSpec

            dpi = PixelSnap.SafeDpi(dpi)

            spec.OuterStrokePx = Math.Max(0.55F, spec.OuterStrokePx * dpi)
            spec.InnerStrokePx = Math.Max(0.5F, spec.InnerStrokePx * dpi)
            spec.HairlineStrokePx = Math.Max(0.6F, spec.HairlineStrokePx * dpi)
            spec.GlowStrokePx = Math.Max(0.55F, spec.GlowStrokePx * dpi)
            spec.InnerInsetPx = Math.Max(0.5F, spec.InnerInsetPx * dpi)
            spec.GlowBlurSigmaPx = Math.Max(0.0F, spec.GlowBlurSigmaPx * dpi)

            Return spec
        End Function

        Public Sub Dispose() Implements IDisposable.Dispose
            If _disposed Then Return
            _disposed = True

            Try
                _borderPainter.Dispose()
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException1)
            End Try
        End Sub

    End Class

End Namespace
