Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Collections.ObjectModel
Imports System.Windows.Forms
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Composition
Imports Nexamas.UI.Controls
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    Partial Public NotInheritable Class MASTransferList

#Region "Geometry / Hit Testing"
        Private Function HitTestAction(pt As SKPoint) As TransferAction
            If _addOneRect.Contains(pt.X, pt.Y) AndAlso CanAddOne() Then Return TransferAction.AddOne
            If _addAllRect.Contains(pt.X, pt.Y) AndAlso _available.Count > 0 Then Return TransferAction.AddAll
            If _removeOneRect.Contains(pt.X, pt.Y) AndAlso CanRemoveOne() Then Return TransferAction.RemoveOne
            If _removeAllRect.Contains(pt.X, pt.Y) AndAlso _selected.Count > 0 Then Return TransferAction.RemoveAll
            Return TransferAction.None
        End Function

        Private Function HitTestRow(pt As SKPoint) As RowHit
            Dim hit As RowHit = HitTestRows(pt, True, _availablePanelRect, _available, _availableTopIndex)
            If hit.Index >= 0 Then Return hit
            Return HitTestRows(pt, False, _selectedPanelRect, _selected, _selectedTopIndex)
        End Function

        Private Function HitTestRows(pt As SKPoint,
                                     availablePanel As Boolean,
                                     panelRect As SKRect,
                                     source As List(Of String),
                                     topIndex As Integer) As RowHit
            If Not panelRect.Contains(pt.X, pt.Y) OrElse source Is Nothing OrElse source.Count = 0 Then Return New RowHit(False, -1)
            Dim dpi As Single = Math.Max(1.0F, _lastDpi)
            Dim plan As MASTransferListLayoutPlan = If(_lastLayoutPlan, MASTransferListLayoutPlan.Create(MASResponsiveLayoutResolver.FromLogicalSize(MASSizeLayoutIntegrationContext.Empty, SKSize.Empty, SizeIntent, MASTransferListLayoutPlan.Thresholds)))
            Dim pad As Single = plan.PanelPaddingPx
            Dim headerHeight As Single = TransferListTokens.HeaderHeightDip * dpi * plan.ResponsiveProfile.ChromeScale
            Dim rowsTop As Single = panelRect.Top + pad + headerHeight + plan.RowGapPx
            If plan.ShowSearch AndAlso plan.SearchHeightPx > 1.0F Then rowsTop += plan.SearchHeightPx + plan.RowGapPx
            Dim rowsLeft As Single = panelRect.Left + pad
            Dim rowsRight As Single = panelRect.Right - pad
            If pt.X < rowsLeft OrElse pt.X > rowsRight OrElse pt.Y < rowsTop Then Return New RowHit(False, -1)
            Dim rowH As Single = plan.RowHeightPx
            Dim gap As Single = plan.RowGapPx
            Dim visual As Integer = CInt(Math.Floor((pt.Y - rowsTop) / Math.Max(1.0F, rowH + gap)))
            Dim visibleIndexes As List(Of Integer) = BuildVisibleIndexes(source, If(availablePanel, _availableFilterText, _selectedFilterText))
            Dim safeTop As Integer = Math.Max(0, Math.Min(topIndex, Math.Max(0, visibleIndexes.Count - 1)))
            If visual < 0 OrElse visual >= plan.MaxVisibleRows OrElse safeTop + visual < 0 OrElse safeTop + visual >= visibleIndexes.Count Then Return New RowHit(False, -1)
            Dim rowTop As Single = rowsTop + CSng(visual) * (rowH + gap)
            If pt.Y > rowTop + rowH Then Return New RowHit(False, -1)
            Return New RowHit(availablePanel, visibleIndexes(safeTop + visual))
        End Function

        Private Function BuildVisibleIndexes(source As List(Of String), filterText As String) As List(Of Integer)
            Dim indexes As New List(Of Integer)()
            If source Is Nothing Then Return indexes
            Dim q As String = If(filterText, String.Empty).Trim()
            For i As Integer = 0 To source.Count - 1
                If q.Length = 0 OrElse source(i).IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0 Then indexes.Add(i)
            Next
            Return indexes
        End Function

        Private Shared Function InsetHorizontal(rect As SKRect,
                                                 insetPx As Single) As SKRect
            Return New SKRect(rect.Left + insetPx, rect.Top, rect.Right - insetPx, rect.Bottom)
        End Function

        Private Shared Function Inset(rect As SKRect,
                                      insetPx As Single) As SKRect
            Return New SKRect(rect.Left + insetPx,
                              rect.Top + insetPx,
                              rect.Right - insetPx,
                              rect.Bottom - insetPx)
        End Function
#End Region

    End Class

End Namespace
