Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.General

    Partial Friend NotInheritable Class MASSurfaceInteractionRing

#Region "Shader helpers"

        Private Shared Function CreateOpenSidesFillShader(rPx As SKRect,
                                                          fillColor As SKColor,
                                                          dpi As Single) As SKShader

            dpi = PixelSnap.SafeDpi(dpi)

            Dim w As Single = rPx.Width

            If w <= 1.0F Then Return Nothing
            If fillColor.Alpha = 0 Then Return Nothing

            Dim softenPx As Single = 16.0F * dpi

            Dim maxSoft As Single = w * 0.24F
            If softenPx > maxSoft Then softenPx = maxSoft
            If softenPx < 1.0F Then Return Nothing

            Dim t As Single = softenPx / w

            Dim t0 As Single = 0.0F
            Dim t1 As Single = t * 0.42F
            Dim t2 As Single = t
            Dim t3 As Single = 1.0F - t
            Dim t4 As Single = 1.0F - t * 0.42F
            Dim t5 As Single = 1.0F

            If t1 <= t0 Then t1 = 0.04F
            If t2 <= t1 Then t2 = 0.1F
            If t3 >= 1.0F Then t3 = 0.9F
            If t4 <= t3 Then t4 = 0.96F

            Dim a As Integer = CInt(fillColor.Alpha)

            Dim edgeA As Byte =
                CByte(Math.Max(0, Math.Min(255, CInt(a * 0.58F))))

            Dim midA1 As Byte =
                CByte(Math.Max(0, Math.Min(255, CInt(a * 0.78F))))

            Dim fullA As Byte = fillColor.Alpha

            Return SKShader.CreateLinearGradient(
                New SKPoint(rPx.Left, rPx.Top),
                New SKPoint(rPx.Right, rPx.Top),
                New SKColor() {
                    fillColor.WithAlpha(edgeA),
                    fillColor.WithAlpha(midA1),
                    fillColor.WithAlpha(fullA),
                    fillColor.WithAlpha(fullA),
                    fillColor.WithAlpha(midA1),
                    fillColor.WithAlpha(edgeA)
                },
                New Single() {t0, t1, t2, t3, t4, t5},
                SKShaderTileMode.Clamp)

        End Function

#End Region

#Region "Shape realization"

        Private Shared Function BuildOverlayRoundRect(rPx As SKRect,
                                                      radiusPx As Single,
                                                      shape As MASVisualInteractionOverlayShape) As SKRoundRect

            Dim rr As New SKRoundRect()
            Dim rad As Single = PixelSnap.SafeRadius(radiusPx)

            Select Case shape

                Case MASVisualInteractionOverlayShape.Closed
                    rr.SetRectRadii(rPx, {
                        New SKPoint(rad, rad),
                        New SKPoint(rad, rad),
                        New SKPoint(rad, rad),
                        New SKPoint(rad, rad)
                    })

                Case MASVisualInteractionOverlayShape.OpenSides
                    rr.SetRectRadii(rPx, {
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F)
                    })

                Case MASVisualInteractionOverlayShape.OpenTop
                    rr.SetRectRadii(rPx, {
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(rad, rad),
                        New SKPoint(rad, rad)
                    })

                Case MASVisualInteractionOverlayShape.OpenBottom
                    rr.SetRectRadii(rPx, {
                        New SKPoint(rad, rad),
                        New SKPoint(rad, rad),
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F)
                    })

                Case MASVisualInteractionOverlayShape.SegmentLeft
                    rr.SetRectRadii(rPx, {
                        New SKPoint(rad, rad),
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(rad, rad)
                    })

                Case MASVisualInteractionOverlayShape.SegmentMiddle
                    rr.SetRectRadii(rPx, {
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(0.0F, 0.0F)
                    })

                Case MASVisualInteractionOverlayShape.SegmentRight
                    rr.SetRectRadii(rPx, {
                        New SKPoint(0.0F, 0.0F),
                        New SKPoint(rad, rad),
                        New SKPoint(rad, rad),
                        New SKPoint(0.0F, 0.0F)
                    })

                Case Else
                    Throw New NotSupportedException(
                        "Unsupported MASVisualInteractionOverlayShape: " & CInt(shape).ToString())

            End Select

            Return rr

        End Function

        Private Shared Function IsPathOnlyShape(shape As MASVisualInteractionOverlayShape) As Boolean
            Select Case shape
                Case MASVisualInteractionOverlayShape.OpenSides,
                     MASVisualInteractionOverlayShape.OpenTop,
                     MASVisualInteractionOverlayShape.OpenBottom

                    Return True

                Case Else
                    Return False
            End Select
        End Function

        Private Shared Function BuildOpenShapeFillPath(rPx As SKRect,
                                                       radiusPx As Single,
                                                       shape As MASVisualInteractionOverlayShape) As SKPath

            Dim path As New SKPath()
            Dim rad As Single = PixelSnap.SafeRadius(radiusPx)

            Select Case shape

                Case MASVisualInteractionOverlayShape.OpenSides
                    path.AddRoundRect(BuildOverlayRoundRect(rPx, 0.0F, MASVisualInteractionOverlayShape.OpenSides))

                Case MASVisualInteractionOverlayShape.OpenTop
                    path.AddRoundRect(BuildOverlayRoundRect(rPx, rad, MASVisualInteractionOverlayShape.OpenTop))

                Case MASVisualInteractionOverlayShape.OpenBottom
                    path.AddRoundRect(BuildOverlayRoundRect(rPx, rad, MASVisualInteractionOverlayShape.OpenBottom))

                Case Else
                    Throw New NotSupportedException(
                        "BuildOpenShapeFillPath does not support shape: " & CInt(shape).ToString())

            End Select

            Return path

        End Function

        Private Shared Function BuildOpenShapeRingPath(rPx As SKRect,
                                                       radiusPx As Single,
                                                       shape As MASVisualInteractionOverlayShape) As SKPath

            Dim path As New SKPath()
            Dim rad As Single = PixelSnap.SafeRadius(radiusPx)

            Select Case shape

                Case MASVisualInteractionOverlayShape.OpenSides
                    path.MoveTo(rPx.Left, rPx.Top)
                    path.LineTo(rPx.Right, rPx.Top)

                    path.MoveTo(rPx.Left, rPx.Bottom)
                    path.LineTo(rPx.Right, rPx.Bottom)

                Case MASVisualInteractionOverlayShape.OpenTop
                    path.MoveTo(rPx.Left + rad, rPx.Top)
                    path.LineTo(rPx.Right - rad, rPx.Top)

                    path.ArcTo(rad, rad, 0.0F, SKPathArcSize.Small, SKPathDirection.Clockwise, rPx.Right, rPx.Top + rad)
                    path.LineTo(rPx.Right, rPx.Bottom - rad)
                    path.ArcTo(rad, rad, 0.0F, SKPathArcSize.Small, SKPathDirection.Clockwise, rPx.Right - rad, rPx.Bottom)
                    path.LineTo(rPx.Left + rad, rPx.Bottom)
                    path.ArcTo(rad, rad, 0.0F, SKPathArcSize.Small, SKPathDirection.Clockwise, rPx.Left, rPx.Bottom - rad)
                    path.LineTo(rPx.Left, rPx.Top + rad)
                    path.ArcTo(rad, rad, 0.0F, SKPathArcSize.Small, SKPathDirection.Clockwise, rPx.Left + rad, rPx.Top)

                Case MASVisualInteractionOverlayShape.OpenBottom
                    path.MoveTo(rPx.Left + rad, rPx.Bottom)
                    path.LineTo(rPx.Right - rad, rPx.Bottom)

                    path.ArcTo(rad, rad, 0.0F, SKPathArcSize.Small, SKPathDirection.CounterClockwise, rPx.Right, rPx.Bottom - rad)
                    path.LineTo(rPx.Right, rPx.Top + rad)
                    path.ArcTo(rad, rad, 0.0F, SKPathArcSize.Small, SKPathDirection.CounterClockwise, rPx.Right - rad, rPx.Top)
                    path.LineTo(rPx.Left + rad, rPx.Top)
                    path.ArcTo(rad, rad, 0.0F, SKPathArcSize.Small, SKPathDirection.CounterClockwise, rPx.Left, rPx.Top + rad)
                    path.LineTo(rPx.Left, rPx.Bottom - rad)
                    path.ArcTo(rad, rad, 0.0F, SKPathArcSize.Small, SKPathDirection.CounterClockwise, rPx.Left + rad, rPx.Bottom)

                Case Else
                    Throw New NotSupportedException(
                        "BuildOpenShapeRingPath does not support shape: " & CInt(shape).ToString())

            End Select

            Return path

        End Function

#End Region

    End Class

End Namespace
