Option Strict On
Option Explicit On

Imports Nexamas.UI.General
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Rendering

    ''' <summary>
    ''' Material-owned painter for the reusable body/lift portion of framed surfaces.
    ''' It intentionally preserves the previous framed-surface body output byte-for-byte
    ''' in formula and inputs while moving the surface body responsibility out of Frame painting.
    ''' Frame painting remains responsible only for frame/border composition.
    ''' </summary>
    Friend NotInheritable Class MASSurfaceFrameBodyMaterialRenderer
        Private Sub New()
        End Sub

        Friend Shared Sub DrawBody(canvas As SKCanvas,
                                   r As SKRect,
                                   radius As Single,
                                   dpi As Single,
                                   spec As MASSurfaceFrameBodySpec)

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

            Using fillPaint As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Fill
            }
                fillPaint.Shader =
                    SKShader.CreateLinearGradient(
                        New SKPoint(r.Left, r.Top),
                        New SKPoint(r.Left, r.Bottom),
                        New SKColor() {
                            spec.TopColor,
                            spec.MidColor,
                            spec.BottomColor
                        },
                        New Single() {0.0F, 0.46F, 1.0F},
                        SKShaderTileMode.Clamp)

                canvas.DrawRoundRect(r, radius, radius, fillPaint)
            End Using

            If spec.WashColor.Alpha > 0 Then
                Using washPaint As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .BlendMode = SKBlendMode.SoftLight
                }
                    washPaint.Shader =
                        SKShader.CreateLinearGradient(
                            New SKPoint(r.Left, r.Top),
                            New SKPoint(r.Right, r.Bottom),
                            New SKColor() {
                                spec.WashColor,
                                SKColors.Transparent
                            },
                            New Single() {0.0F, 1.0F},
                            SKShaderTileMode.Clamp)

                    canvas.DrawRoundRect(r, radius, radius, washPaint)
                End Using
            End If

            If spec.DrawColdTint AndAlso spec.ColdTintColor.Alpha > 0 AndAlso spec.ColdTintAlpha > 0 Then
                Using tintPaint As New SKPaint With {
                    .IsAntialias = True,
                    .IsDither = True,
                    .Style = SKPaintStyle.Fill,
                    .BlendMode = SKBlendMode.Screen,
                    .Color = ColorMath.WithAlpha(spec.ColdTintColor, spec.ColdTintAlpha)
                }
                    Dim tintRect As New SKRect(
                        r.Left,
                        r.Top,
                        r.Right,
                        r.Top + Math.Max(8.0F * dpi, r.Height * 0.42F))

                    canvas.Save()

                    Using clip As New SKPath()
                        clip.AddRoundRect(r, radius, radius)
                        canvas.ClipPath(clip, SKClipOperation.Intersect, True)

                        Dim rr As Single =
                            Math.Max(1.0F, Math.Min(radius, tintRect.Height * 0.35F))

                        canvas.DrawRoundRect(tintRect, rr, rr, tintPaint)
                    End Using

                    canvas.Restore()
                End Using
            End If
        End Sub

        Friend Shared Sub DrawLift(canvas As SKCanvas,
                                   r As SKRect,
                                   radius As Single,
                                   dpi As Single,
                                   spec As MASSurfaceFrameLiftSpec)

            If canvas Is Nothing Then Return
            If Not spec.Draw Then Return
            If spec.TopColor.Alpha = 0 AndAlso spec.MidColor.Alpha = 0 Then Return
            If r.Width <= 8.0F OrElse r.Height <= 8.0F Then Return

            Dim insetX As Single = Math.Max(spec.InsetXPx * dpi, 5.0F)
            Dim insetTop As Single = Math.Max(spec.InsetTopPx * dpi, 2.0F)

            Dim liftH As Single

            If spec.HeightPx > 0.0F Then
                liftH = spec.HeightPx * dpi
            Else
                liftH = Math.Max(8.0F * dpi, r.Height * 0.12F)
                liftH = Math.Min(liftH, r.Height * 0.18F)
            End If

            Dim liftRect As New SKRect(
                r.Left + insetX,
                r.Top + insetTop,
                r.Right - insetX,
                r.Top + insetTop + liftH)

            If liftRect.Width <= 4.0F OrElse liftRect.Height <= 2.0F Then Return

            Dim liftTop As SKColor =
                ColorMath.WithAlpha(
                    spec.TopColor,
                    CByte(Math.Min(255, Math.Max(0, CInt(spec.TopColor.Alpha) \ 3))))

            Dim liftMid As SKColor =
                ColorMath.WithAlpha(
                    spec.MidColor,
                    CByte(Math.Min(255, Math.Max(0, CInt(spec.MidColor.Alpha) \ 4))))

            Using p As New SKPaint With {
                .IsAntialias = True,
                .IsDither = True,
                .Style = SKPaintStyle.Fill
            }
                p.Shader =
                    SKShader.CreateLinearGradient(
                        New SKPoint(liftRect.Left, liftRect.Top),
                        New SKPoint(liftRect.Left, liftRect.Bottom),
                        New SKColor() {
                            liftTop,
                            liftMid,
                            SKColors.Transparent
                        },
                        New Single() {0.0F, 0.42F, 1.0F},
                        SKShaderTileMode.Clamp)

                canvas.Save()

                Using clip As New SKPath()
                    clip.AddRoundRect(r, radius, radius)
                    canvas.ClipPath(clip, SKClipOperation.Intersect, True)

                    Dim rr As Single =
                        Math.Max(1.0F, Math.Min(radius * 0.72F, liftRect.Height * 0.45F))

                    canvas.DrawRoundRect(liftRect, rr, rr, p)
                End Using

                canvas.Restore()
            End Using
        End Sub
    End Class

End Namespace
