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 "Input"

        Protected Overrides Sub OnMouseMove(ctx As MASThemeContext, ptPx As SKPoint)
            Dim hit As CarouselHit = HitTest(ptPx)
            Dim kind As CarouselHitKind = If(hit Is Nothing, CarouselHitKind.None, hit.Kind)
            Dim index As Integer = If(hit Is Nothing, -1, hit.Index)
            If kind = _hoverKind AndAlso index = _hoverIndex Then Return
            _hoverKind = kind
            _hoverIndex = index
            InvalidateVisual()
        End Sub

        Protected Overrides Function OnMouseDown(ctx As MASThemeContext,
                                                 ptPx As SKPoint,
                                                 button As Integer) As Boolean
            If button <> CInt(MouseButtons.Left) Then Return False
            Dim hit As CarouselHit = HitTest(ptPx)
            If hit Is Nothing Then Return _stageRect.Contains(ptPx.X, ptPx.Y)
            _pressedKind = hit.Kind
            _pressedIndex = hit.Index
            InvalidateVisual()
            Return True
        End Function

        Protected Overrides Function OnMouseUp(ctx As MASThemeContext,
                                               ptPx As SKPoint,
                                               button As Integer) As Boolean
            If button <> CInt(MouseButtons.Left) Then Return False
            Dim pressedKind As CarouselHitKind = _pressedKind
            Dim pressedIndex As Integer = _pressedIndex
            _pressedKind = CarouselHitKind.None
            _pressedIndex = -1
            Dim hit As CarouselHit = HitTest(ptPx)
            If hit IsNot Nothing AndAlso hit.Kind = pressedKind AndAlso (hit.Index = pressedIndex OrElse pressedKind = CarouselHitKind.PreviousButton OrElse pressedKind = CarouselHitKind.NextButton) Then
                Select Case pressedKind
                    Case CarouselHitKind.PreviousButton
                        MovePrevious()
                    Case CarouselHitKind.NextButton
                        MoveNext()
                    Case CarouselHitKind.Item, CarouselHitKind.Indicator
                        If hit.Index >= 0 Then SetSelectedIndex(hit.Index, True)
                End Select
                Return True
            End If
            InvalidateVisual()
            Return False
        End Function

        Protected Overrides Sub OnMouseLeave(ctx As MASThemeContext)
            ResetPointerState()
        End Sub

        Protected Overrides Sub OnMouseCancel(ctx As MASThemeContext)
            ResetPointerState()
        End Sub

        Protected Overrides Sub OnHostLostFocus(ctx As MASThemeContext)
            _pressedKind = CarouselHitKind.None
            _pressedIndex = -1
            InvalidateVisual()
        End Sub

        Friend Overrides Function WantsPointerWheel(ctx As MASThemeContext,
                                                      ptPx As SKPoint) As Boolean
            ' Do not steal the page/workspace mouse wheel merely because the pointer is hovering the
            ' carousel. Wheel navigation is available once the carousel has keyboard focus (click or tab),
            ' while parent scroll surfaces keep ownership during casual page scrolling.
            Return Visible AndAlso Enabled AndAlso HasKeyboardFocus AndAlso
                   _stageRect.Contains(ptPx.X, ptPx.Y) AndAlso
                   _items.Count > 1
        End Function

        Friend Overrides Function CanHandlePointerWheel(ctx As MASThemeContext,
                                                        delta As Integer,
                                                        ptPx As SKPoint) As Boolean
            If delta = 0 OrElse Not WantsPointerWheel(ctx, ptPx) Then Return False
            Return CanMoveByWheel(delta)
        End Function

        Protected Overrides Sub OnMouseWheel(ctx As MASThemeContext,
                                             delta As Integer,
                                             ptPx As SKPoint)
            If Not CanMoveByWheel(delta) Then Return
            If delta < 0 Then
                MoveNext()
            ElseIf delta > 0 Then
                MovePrevious()
            End If
        End Sub

        Protected Overrides Function OnKeyDown(ctx As MASThemeContext,
                                               keyCode As Keys) As Boolean
            If Not Enabled OrElse _items.Count = 0 Then Return False
            Select Case keyCode
                Case Keys.Left
                    If MASContentCarouselPolicy.ResolveRightToLeft() Then MoveBy(1) Else MoveBy(-1)
                    Return True
                Case Keys.Right
                    If MASContentCarouselPolicy.ResolveRightToLeft() Then MoveBy(-1) Else MoveBy(1)
                    Return True
                Case Keys.Home
                    SetSelectedIndex(0, True)
                    Return True
                Case Keys.End
                    SetSelectedIndex(_items.Count - 1, True)
                    Return True
                Case Keys.PageUp
                    MoveBy(-1)
                    Return True
                Case Keys.PageDown, Keys.Space, Keys.Enter
                    MoveBy(1)
                    Return True
            End Select
            Return False
        End Function

        Protected Overrides Function WantsKeyboardFocus() As Boolean
            Return MASCompositeContentFocusPolicy.CanReceiveKeyboardFocus(_contract, Visible, Enabled)
        End Function

        Protected Overrides Function WantsPointerFocus() As Boolean
            Return MASCompositeContentFocusPolicy.AllowsPointerFocusForCompositeContent(_contract, Visible, Enabled)
        End Function

#End Region
    End Class

End Namespace
