Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
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.Motion
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 MASContentCarousel
#Region "View state / selection motion"

        Private Sub MoveBy(delta As Integer)
            If _items.Count <= 0 Then Return
            SetSelectedIndex(MASContentCarouselPolicy.MoveIndex(_selectedIndex, delta, _items.Count, _isLooping), True)
        End Sub


        Private Function CanMoveByWheel(delta As Integer) As Boolean
            If _items.Count <= 1 OrElse delta = 0 Then Return False
            If _isLooping Then Return True
            Dim normalized As Integer = MASContentCarouselPolicy.ClampIndex(_selectedIndex, _items.Count)
            If delta < 0 Then Return normalized < _items.Count - 1
            If delta > 0 Then Return normalized > 0
            Return False
        End Function


        Private Sub SetSelectedIndex(index As Integer,
                                     shouldRaiseEvent As Boolean)
            Dim normalized As Integer = MASContentCarouselPolicy.ClampIndex(index, _items.Count)
            Dim oldIndex As Integer = _selectedIndex
            Dim changed As Boolean = (_selectedIndex <> normalized)
            _selectedIndex = normalized
            If changed Then StartSelectionMotion(oldIndex, normalized)
            InvalidateVisual()
            If changed AndAlso shouldRaiseEvent Then RaiseSelectedItemChangedSafe()
        End Sub


        Private Sub NormalizeSelection()
            Dim normalized As Integer = MASContentCarouselPolicy.ClampIndex(_selectedIndex, _items.Count)
            If normalized <> _selectedIndex Then CancelSelectionMotion()
            _selectedIndex = normalized
        End Sub


        Private Function IsSelectionMotionActive() As Boolean
            Return _motionFromIndex >= 0 AndAlso _motionFromIndex < _items.Count AndAlso _
                   _motionToIndex >= 0 AndAlso _motionToIndex < _items.Count AndAlso _
                   _motionProgress < 0.999F
        End Function


        Private Sub StartSelectionMotion(oldIndex As Integer,
                                         newIndex As Integer)
            CancelSelectionMotion()
            If oldIndex < 0 OrElse oldIndex >= _items.Count OrElse newIndex < 0 OrElse newIndex >= _items.Count OrElse oldIndex = newIndex Then
                _motionProgress = 1.0F
                Return
            End If

            _motionFromIndex = oldIndex
            _motionToIndex = newIndex
            _motionProgress = 0.0F
            _motionDirection = ResolveMotionDirection(oldIndex, newIndex)
            Dim plan As MASMotionTransitionPlan = MASMotionSystem.CreateTransitionPlan(MASMotionTokenId.SelectionMove, 0.0F, 1.0F)
            _selectionMotionRunner = MASMotionSystem.CreateTimelineRunner(Me,
                                                                          "MASContentCarousel.SelectionMove",
                                                                          plan,
                                                                          AddressOf RequestSelectionMotionFrame,
                                                                          AddressOf ApplySelectionMotionFrame,
                                                                          AddressOf CompleteSelectionMotionFrame)
            _selectionMotionRunner.Start()
        End Sub


        Private Sub CancelSelectionMotion()
            If _selectionMotionRunner IsNot Nothing Then
                _selectionMotionRunner.Dispose()
                _selectionMotionRunner = Nothing
            End If
            _motionFromIndex = -1
            _motionToIndex = -1
            _motionProgress = 1.0F
        End Sub


        Private Function ResolveMotionDirection(oldIndex As Integer,
                                                newIndex As Integer) As Integer
            If _items.Count > 1 AndAlso _isLooping Then
                If oldIndex = _items.Count - 1 AndAlso newIndex = 0 Then Return 1
                If oldIndex = 0 AndAlso newIndex = _items.Count - 1 Then Return -1
            End If
            If newIndex >= oldIndex Then Return 1
            Return -1
        End Function


        Private Sub RequestSelectionMotionFrame()
            InvalidateVisual()
        End Sub


        Private Sub ApplySelectionMotionFrame(frame As MASMotionFrame)
            If frame Is Nothing Then Return
            _motionProgress = MASMotionSystem.ClampProgress(frame.Value)
            InvalidateVisual()
        End Sub


        Private Sub CompleteSelectionMotionFrame(frame As MASMotionFrame)
            _motionProgress = 1.0F
            _motionFromIndex = -1
            _motionToIndex = -1
            _selectionMotionRunner = Nothing
            InvalidateVisual()
        End Sub


#End Region
    End Class

End Namespace
