Option Strict On
Option Explicit On

Imports System
Imports SkiaSharp

Namespace Nexamas.UI.TextInput

    ' CONTRACT:
    ' MASTextMultilineViewport owns pure vertical-scroll calculations for multiline text.
    '
    ' It does not store state and does not mutate MASTextInputState.
    Friend NotInheritable Class MASTextMultilineViewport

        Private Const CARET_PADDING_PX As Single = 4.0F

        Friend Function EnsureScrollInRange(contentR As SKRect,
                                            paragraph As MASTextParagraphLayout,
                                            currentVerticalScrollPx As Single) As Single
            If paragraph Is Nothing Then Return 0.0F
            If contentR.Height <= 1.0F Then Return 0.0F

            Dim maxScroll As Single = Math.Max(0.0F, paragraph.TotalHeight - contentR.Height)
            Dim scroll As Single = NormalizeScroll(currentVerticalScrollPx)

            If scroll < 0.0F Then Return 0.0F
            If scroll > maxScroll Then Return maxScroll

            Return scroll
        End Function

        Friend Function EnsureCaretVisible(contentR As SKRect,
                                           paragraph As MASTextParagraphLayout,
                                           caretIndex As Integer,
                                           currentVerticalScrollPx As Single) As Single
            If paragraph Is Nothing Then Return 0.0F
            If contentR.Height <= 1.0F Then Return 0.0F

            Dim scroll As Single = EnsureScrollInRange(contentR, paragraph, currentVerticalScrollPx)
            Dim line As MASTextWrappedLine = paragraph.GetLineFromTextIndex(caretIndex)
            If line Is Nothing Then Return scroll

            Dim visibleTop As Single = contentR.Top + CARET_PADDING_PX
            Dim visibleBottom As Single = contentR.Bottom - CARET_PADDING_PX

            If line.Bounds.Top < visibleTop Then
                scroll -= (visibleTop - line.Bounds.Top)
            ElseIf line.Bounds.Bottom > visibleBottom Then
                scroll += (line.Bounds.Bottom - visibleBottom)
            End If

            Return EnsureScrollInRange(contentR, paragraph, scroll)
        End Function

        Private Shared Function NormalizeScroll(value As Single) As Single
            If Single.IsNaN(value) OrElse Single.IsInfinity(value) Then Return 0.0F
            If Math.Abs(value) < 0.01F Then Return 0.0F
            Return value
        End Function

    End Class

End Namespace
