Option Strict On
Option Explicit On

Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Linq

Namespace Nexamas.UI.Virtualization

    ''' <summary>
    ''' Immutable index-based selection snapshot. It is independent from realized containers so selection remains stable while
    ''' virtualization recycles off-screen visuals.
    ''' </summary>
    Friend NotInheritable Class MASVirtualizationSelectionState

        Private ReadOnly _selectedIndexes As ReadOnlyCollection(Of Integer)

        Private Sub New(mode As MASVirtualizationSelectionMode,
                        selectedIndexes As IEnumerable(Of Integer),
                        anchorIndex As Integer?)
            Me.Mode = mode
            _selectedIndexes = New ReadOnlyCollection(Of Integer)(If(selectedIndexes, Enumerable.Empty(Of Integer)()).Where(Function(index) index >= 0).Distinct().OrderBy(Function(index) index).ToArray())
            Me.AnchorIndex = anchorIndex
        End Sub

        Friend ReadOnly Property Mode As MASVirtualizationSelectionMode

        Friend ReadOnly Property SelectedIndexes As IReadOnlyList(Of Integer)
            Get
                Return _selectedIndexes
            End Get
        End Property

        Friend ReadOnly Property AnchorIndex As Integer?

        Friend ReadOnly Property SelectedCount As Integer
            Get
                Return _selectedIndexes.Count
            End Get
        End Property

        Friend Shared Function Empty(Optional mode As MASVirtualizationSelectionMode = MASVirtualizationSelectionMode.Multiple) As MASVirtualizationSelectionState
            Return New MASVirtualizationSelectionState(mode, Array.Empty(Of Integer)(), Nothing)
        End Function

        Friend Function SelectSingle(index As Integer) As MASVirtualizationSelectionState
            If Mode = MASVirtualizationSelectionMode.None OrElse index < 0 Then
                Return Me
            End If

            Return New MASVirtualizationSelectionState(Mode, New Integer() {index}, index)
        End Function

        Friend Function Toggle(index As Integer) As MASVirtualizationSelectionState
            If Mode = MASVirtualizationSelectionMode.None OrElse index < 0 Then
                Return Me
            End If

            If Mode = MASVirtualizationSelectionMode.SingleItem Then
                If Contains(index) Then
                    Return Empty(Mode)
                End If

                Return SelectSingle(index)
            End If

            Dim nextSet = New HashSet(Of Integer)(_selectedIndexes)
            If Not nextSet.Add(index) Then
                nextSet.Remove(index)
            End If

            Return New MASVirtualizationSelectionState(Mode, nextSet, index)
        End Function

        Friend Function SelectRange(firstIndex As Integer, lastIndex As Integer) As MASVirtualizationSelectionState
            If Mode = MASVirtualizationSelectionMode.None OrElse (firstIndex < 0 AndAlso lastIndex < 0) Then
                Return Me
            End If

            Dim startIndex = Math.Max(0, Math.Min(firstIndex, lastIndex))
            Dim endIndex = Math.Max(0, Math.Max(firstIndex, lastIndex))

            If Mode = MASVirtualizationSelectionMode.SingleItem Then
                Return SelectSingle(endIndex)
            End If

            Dim selected = New List(Of Integer)()
            For index = startIndex To endIndex
                selected.Add(index)
            Next

            Return New MASVirtualizationSelectionState(Mode, selected, startIndex)
        End Function

        Friend Function Contains(index As Integer) As Boolean
            Return _selectedIndexes.Contains(index)
        End Function

    End Class

End Namespace
