Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports SkiaSharp

Namespace Nexamas.UI.TextInput

    ' CONTRACT:
    ' MASTextMultilineSelectionGeometry converts a selection range into
    ' per-visual-line spans and rectangles.
    '
    ' It must not mutate state, render directly, or know UI controls.
    Friend NotInheritable Class MASTextMultilineSelectionGeometry

        Friend Function BuildSpans(layout As MASTextParagraphLayout,
                                   selectionStart As Integer,
                                   selectionLength As Integer) As IReadOnlyList(Of MASTextMultilineSelectionSpan)
            Dim result As New List(Of MASTextMultilineSelectionSpan)()

            If layout Is Nothing OrElse layout.LineCount <= 0 Then Return result
            If selectionLength <= 0 Then Return result

            Dim safeStart As Integer = Clamp(selectionStart, 0, layout.Text.Length)
            Dim safeEnd As Integer = Clamp(selectionStart + selectionLength, safeStart, layout.Text.Length)
            If safeEnd <= safeStart Then Return result

            For i As Integer = 0 To layout.LineCount - 1
                Dim line As MASTextWrappedLine = layout.Lines(i)
                If line Is Nothing Then Continue For

                Dim lineStart As Integer = line.StartIndex
                Dim lineEnd As Integer = line.EndIndexExclusive

                If safeEnd < lineStart Then Exit For
                If safeStart > lineEnd Then Continue For

                Dim spanStart As Integer = Math.Max(safeStart, lineStart)
                Dim spanEnd As Integer = Math.Min(safeEnd, lineEnd)

                If spanEnd > spanStart Then
                    result.Add(New MASTextMultilineSelectionSpan(line, spanStart, spanEnd))
                End If
            Next

            Return result
        End Function

        Friend Function BuildRects(layout As MASTextParagraphLayout,
                                   selectionStart As Integer,
                                   selectionLength As Integer,
                                   paint As SKPaint) As IReadOnlyList(Of SKRect)
            Dim rects As New List(Of SKRect)()

            If layout Is Nothing OrElse paint Is Nothing Then Return rects

            Dim spans As IReadOnlyList(Of MASTextMultilineSelectionSpan) =
                BuildSpans(layout, selectionStart, selectionLength)

            For Each span As MASTextMultilineSelectionSpan In spans
                If span Is Nothing OrElse span.Line Is Nothing Then Continue For
                If span.Line.InlineLayout Is Nothing Then Continue For

                Dim x1 As Single = span.Line.InlineLayout.GetCaretX(span.LocalStart)
                Dim x2 As Single = span.Line.InlineLayout.GetCaretX(span.LocalEndExclusive)

                Dim left As Single = Math.Min(x1, x2)
                Dim right As Single = Math.Max(x1, x2)

                If right <= left Then Continue For

                rects.Add(New SKRect(left, span.Line.Bounds.Top, right, span.Line.Bounds.Bottom))
            Next

            Return rects
        End Function

        Private Shared Function Clamp(value As Integer, minValue As Integer, maxValue As Integer) As Integer
            If value < minValue Then Return minValue
            If value > maxValue Then Return maxValue
            Return value
        End Function

    End Class

End Namespace
