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 "Item model / Transfer"
        Private Sub SetItemsInternal(availableItems As IEnumerable(Of String),
                                     selectedItems As IEnumerable(Of String),
                                     shouldRaise As Boolean)
            _available.Clear()
            _selected.Clear()
            _available.AddRange(MASTransferListPolicy.NormalizeItems(availableItems))
            _selected.AddRange(MASTransferListPolicy.NormalizeItems(selectedItems))
            NormalizeSelectionAfterCollectionChange()
            RequestSizeLayoutRefreshForSizeAffectingChange("MASTransferList.SetItems")
            InvalidateVisual()
            If shouldRaise Then
                RaiseSelectionChangedSafe()
                RaiseItemsTransferredSafe()
            End If
        End Sub

        Private Sub SetAvailableSelection(index As Integer,
                                          shouldRaise As Boolean)
            Dim previousAvailableIndex As Integer = _availableSelectedIndex
            Dim normalized As Integer = MASTransferListPolicy.ClampIndex(index, _available.Count)
            If _availableSelectedIndex = normalized Then Return
            _availableSelectedIndex = normalized
            If normalized >= 0 Then _selectedSelectedIndex = -1
            _availableTopIndex = MASTransferListPolicy.EnsureVisibleTopIndex(_availableSelectedIndex, _availableTopIndex, _available.Count)
            StartTransferListSelectionMotion(True, previousAvailableIndex, _availableSelectedIndex)
            InvalidateVisual()
            If shouldRaise Then RaiseSelectionChangedSafe()
        End Sub

        Private Sub SetSelectedSelection(index As Integer,
                                         shouldRaise As Boolean)
            Dim previousSelectedIndex As Integer = _selectedSelectedIndex
            Dim normalized As Integer = MASTransferListPolicy.ClampIndex(index, _selected.Count)
            If _selectedSelectedIndex = normalized Then Return
            _selectedSelectedIndex = normalized
            If normalized >= 0 Then _availableSelectedIndex = -1
            _selectedTopIndex = MASTransferListPolicy.EnsureVisibleTopIndex(_selectedSelectedIndex, _selectedTopIndex, _selected.Count)
            StartTransferListSelectionMotion(False, previousSelectedIndex, _selectedSelectedIndex)
            InvalidateVisual()
            If shouldRaise Then RaiseSelectionChangedSafe()
        End Sub

        Private Sub MoveOne(source As List(Of String),
                            target As List(Of String),
                            sourceIndex As Integer,
                            movingToTarget As Boolean)
            If source Is Nothing OrElse target Is Nothing Then Return
            If sourceIndex < 0 OrElse sourceIndex >= source.Count Then Return
            If target.Count >= TransferListTokens.MaxStoredItems Then Return
            Dim item As String = source(sourceIndex)
            source.RemoveAt(sourceIndex)
            target.Add(item)
            NormalizeSelectionAfterCollectionChange()
            If movingToTarget Then
                SetSelectedSelection(target.Count - 1, False)
                StartTransferListTransferPulse(False, target.Count - 1)
            Else
                SetAvailableSelection(target.Count - 1, False)
                StartTransferListTransferPulse(True, target.Count - 1)
            End If
            RequestSizeLayoutRefreshForSizeAffectingChange("MASTransferList.MoveOne")
            InvalidateVisual()
            RaiseSelectionChangedSafe()
            RaiseItemsTransferredSafe()
        End Sub

        Private Sub MoveAll(source As List(Of String),
                            target As List(Of String),
                            movingToTarget As Boolean)
            If source Is Nothing OrElse target Is Nothing OrElse source.Count = 0 Then Return
            Dim remainingCapacity As Integer = Math.Max(0, TransferListTokens.MaxStoredItems - target.Count)
            If remainingCapacity <= 0 Then Return
            Dim moveCount As Integer = Math.Min(remainingCapacity, source.Count)
            For i As Integer = 0 To moveCount - 1
                target.Add(source(0))
                source.RemoveAt(0)
            Next
            NormalizeSelectionAfterCollectionChange()
            If target.Count > 0 Then StartTransferListTransferPulse(Not movingToTarget, target.Count - 1)
            RequestSizeLayoutRefreshForSizeAffectingChange("MASTransferList.MoveAll")
            InvalidateVisual()
            RaiseSelectionChangedSafe()
            RaiseItemsTransferredSafe()
        End Sub

        Private Sub NormalizeSelectionAfterCollectionChange()
            _availableSelectedIndex = MASTransferListPolicy.ClampIndex(_availableSelectedIndex, _available.Count)
            _selectedSelectedIndex = MASTransferListPolicy.ClampIndex(_selectedSelectedIndex, _selected.Count)
            If _availableSelectedIndex >= 0 Then _selectedSelectedIndex = -1
            _availableTopIndex = MASTransferListPolicy.EnsureVisibleTopIndex(_availableSelectedIndex, _availableTopIndex, _available.Count)
            _selectedTopIndex = MASTransferListPolicy.EnsureVisibleTopIndex(_selectedSelectedIndex, _selectedTopIndex, _selected.Count)
        End Sub

        Private Function CanAddOne() As Boolean
            Return _availableSelectedIndex >= 0 AndAlso _availableSelectedIndex < _available.Count
        End Function

        Private Function CanRemoveOne() As Boolean
            Return _selectedSelectedIndex >= 0 AndAlso _selectedSelectedIndex < _selected.Count
        End Function

        Private Sub ExecuteAction(action As TransferAction)
            Select Case action
                Case TransferAction.AddOne
                    MoveSelectedToTarget()
                Case TransferAction.AddAll
                    MoveAllToTarget()
                Case TransferAction.RemoveOne
                    MoveTargetToAvailable()
                Case TransferAction.RemoveAll
                    MoveAllToAvailable()
            End Select
        End Sub
#End Region

    End Class

End Namespace
