Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.General
Imports SkiaSharp

Namespace Nexamas.UI.Scroll

    Friend NotInheritable Class ScrollbarLayout

        Friend Structure Geometry
            Friend Thickness As Single
            Friend UpRect As SKRect
            Friend DownRect As SKRect
            Friend TrackRect As SKRect
            Friend ThumbRect As SKRect
        End Structure

        Private ReadOnly _metrics As ScrollMetrics

        Friend Sub New(metrics As ScrollMetrics)
            If metrics Is Nothing Then Throw New ArgumentNullException(NameOf(metrics))
            _metrics = metrics
        End Sub

        Friend Function Compute(hostRect As SKRect,
                                contentHeight As Single,
                                viewportHeight As Single,
                                model As ScrollModel) As Geometry

            hostRect = PixelSnap.SnapRectHalf(hostRect)

            Dim g As New Geometry()

            If hostRect.IsEmpty OrElse viewportHeight <= 0 OrElse contentHeight <= viewportHeight OrElse model Is Nothing Then
                g.Thickness = 0
                g.UpRect = SKRect.Empty
                g.DownRect = SKRect.Empty
                g.TrackRect = SKRect.Empty
                g.ThumbRect = SKRect.Empty
                Return g
            End If

            Dim thickness As Single = Math.Max(1.0F, CSng(_metrics.TrackThickness))
            thickness = PixelSnap.SnapHalf(thickness)
            g.Thickness = thickness

            g.UpRect = PixelSnap.SnapRectHalf(
    New SKRect(hostRect.Right - thickness, hostRect.Top, hostRect.Right, hostRect.Top + thickness)
)

            g.DownRect = PixelSnap.SnapRectHalf(
    New SKRect(hostRect.Right - thickness, hostRect.Bottom - thickness, hostRect.Right, hostRect.Bottom)
)

            g.TrackRect = PixelSnap.SnapRectHalf(
    New SKRect(hostRect.Right - thickness,
               hostRect.Top + thickness,
               hostRect.Right,
               hostRect.Bottom - thickness)
)


            g.ThumbRect = ComputeThumbRect(g.TrackRect, contentHeight, viewportHeight, model.Position, model.MaxPosition)
            Return g
        End Function

        Friend Function ComputeThumbRect(track As SKRect,
                                         contentHeight As Single,
                                         viewportHeight As Single,
                                         position As Integer,
                                         maxPosition As Integer) As SKRect

            If track.Height <= 0 OrElse contentHeight <= 0 OrElse viewportHeight <= 0 Then Return SKRect.Empty

            Dim ratio As Single = viewportHeight / contentHeight
            ratio = Clamp01(ratio)

            Dim thumbSize As Single = track.Height * ratio
            Dim minSize As Single = CSng(_metrics.ThumbMinSize)

            If thumbSize < minSize Then thumbSize = minSize
            If thumbSize > track.Height Then thumbSize = track.Height

            Dim maxTravel As Single = track.Height - thumbSize
            Dim posRatio As Single = 0.0F

            If maxPosition > 0 Then posRatio = CSng(position) / CSng(maxPosition)
            posRatio = Clamp01(posRatio)

            thumbSize = PixelSnap.SnapHalf(thumbSize)
            Dim thumbY As Single = PixelSnap.SnapHalf(track.Top + (maxTravel * posRatio))

            Return PixelSnap.SnapRectHalf(
    New SKRect(track.Left, thumbY, track.Right, thumbY + thumbSize)
)
        End Function

        Private Shared Function Clamp01(v As Single) As Single
            If v < 0.0F Then Return 0.0F
            If v > 1.0F Then Return 1.0F
            Return v
        End Function

    End Class

End Namespace
