Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Globalization
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 MASKanbanBoard

#Region "Input"


        Protected Overrides Sub OnMouseMove(ctx As MASThemeContext, ptPx As SKPoint)
            Dim hit As KanbanCardHit = HitTestCard(ptPx)
            Dim columnIndex As Integer = If(hit IsNot Nothing, hit.ColumnIndex, HitTestColumn(ptPx))
            Dim cardIndex As Integer = If(hit IsNot Nothing, hit.CardIndex, -1)
            Dim visualChanged As Boolean = False
            If _pressedCardIndex >= 0 AndAlso _pressedColumnIndex >= 0 AndAlso _hasPressedPoint Then
                If Not _draggingCard Then
                    Dim dx As Single = ptPx.X - _pressedPointPx.X
                    Dim dy As Single = ptPx.Y - _pressedPointPx.Y
                    Dim thresholdPx As Single = KanbanBoardTokens.DragStartThresholdDip * Math.Max(0.5F, _lastDpi)
                    _draggingCard = (dx * dx + dy * dy) >= (thresholdPx * thresholdPx)
                    visualChanged = _draggingCard
                End If
                If _draggingCard Then
                    Dim previousTargetColumn As Integer = _dragTargetColumnIndex
                    If columnIndex >= 0 Then _dragTargetColumnIndex = columnIndex
                    If _dragTargetColumnIndex >= 0 AndAlso _dragTargetColumnIndex <> previousTargetColumn Then
                        StartKanbanDragFeedbackMotion(_dragTargetColumnIndex)
                        visualChanged = True
                    End If
                    If TryAutoScrollDragColumn(columnIndex, ptPx) Then visualChanged = True
                End If
            End If
            If columnIndex = _hoverColumnIndex AndAlso cardIndex = _hoverCardIndex AndAlso Not visualChanged Then Return
            _hoverColumnIndex = columnIndex
            _hoverCardIndex = cardIndex
            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 KanbanCardHit = HitTestCard(ptPx)
            If hit IsNot Nothing Then
                _pressedColumnIndex = hit.ColumnIndex
                _pressedCardIndex = hit.CardIndex
                _pressedPointPx = ptPx
                _hasPressedPoint = True
                InvalidateVisual()
                Return True
            End If
            Dim columnIndex As Integer = HitTestColumn(ptPx)
            If columnIndex >= 0 Then
                _pressedColumnIndex = columnIndex
                _pressedCardIndex = -1
                _pressedPointPx = ptPx
                _hasPressedPoint = True
                InvalidateVisual()
                Return True
            End If
            Return _contentRect.Contains(ptPx.X, ptPx.Y)
        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 pressedColumn As Integer = _pressedColumnIndex
            Dim pressedCard As Integer = _pressedCardIndex
            _pressedColumnIndex = -1
            _pressedCardIndex = -1
            _hasPressedPoint = False
            _pressedPointPx = SKPoint.Empty
            Dim hit As KanbanCardHit = HitTestCard(ptPx)
            Dim columnIndex As Integer = HitTestColumn(ptPx)
            Dim dropTarget As Integer = If(_dragTargetColumnIndex >= 0, _dragTargetColumnIndex, columnIndex)
            Dim wasDragging As Boolean = _draggingCard
            _draggingCard = False
            _dragTargetColumnIndex = -1
            If wasDragging Then StopKanbanDragFeedbackMotion(resetState:=True)
            If wasDragging AndAlso pressedCard >= 0 AndAlso pressedColumn >= 0 AndAlso dropTarget >= 0 AndAlso dropTarget < _columns.Count Then
                Dim sourceColumn As KanbanColumnState = If(pressedColumn >= 0 AndAlso pressedColumn < _columns.Count, _columns(pressedColumn), Nothing)
                If sourceColumn IsNot Nothing AndAlso pressedCard >= 0 AndAlso pressedCard < sourceColumn.Cards.Count Then
                    Dim targetIndex As Integer = If(hit IsNot Nothing AndAlso hit.ColumnIndex = dropTarget, hit.CardIndex, _columns(dropTarget).Cards.Count)
                    MoveCardToIndex(sourceColumn.Cards(pressedCard).Key, _columns(dropTarget).Key, targetIndex)
                    Return True
                End If
            End If
            If hit IsNot Nothing AndAlso hit.ColumnIndex = pressedColumn AndAlso hit.CardIndex = pressedCard Then
                SetSelection(hit.ColumnIndex, hit.CardIndex, True)
                Return True
            End If
            If pressedCard < 0 AndAlso columnIndex >= 0 AndAlso columnIndex = pressedColumn Then
                SetSelection(columnIndex, If(_columns(columnIndex).Cards.Count > 0, 0, -1), True)
                Return True
            End If
            If pressedColumn >= 0 Then
                InvalidateVisual()
                Return True
            End If
            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)
            _pressedColumnIndex = -1
            _pressedCardIndex = -1
            _dragTargetColumnIndex = -1
            _draggingCard = False
            _hasPressedPoint = False
            _pressedPointPx = SKPoint.Empty
            StopKanbanDragFeedbackMotion(resetState:=True)
            InvalidateVisual()
        End Sub

        Friend Overrides Function WantsPointerWheel(ctx As MASThemeContext,
                                                      ptPx As SKPoint) As Boolean
            Return Visible AndAlso Enabled AndAlso
                   _boardRect.Contains(ptPx.X, ptPx.Y) AndAlso
                   ResolveWheelColumnIndex(ptPx) >= 0
        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
            Dim columnIndex As Integer = ResolveWheelColumnIndex(ptPx)
            Return CanScrollColumnByWheel(columnIndex, delta)
        End Function

        Protected Overrides Sub OnMouseWheel(ctx As MASThemeContext,
                                             delta As Integer,
                                             ptPx As SKPoint)
            Dim columnIndex As Integer = ResolveWheelColumnIndex(ptPx)
            If Not CanScrollColumnByWheel(columnIndex, delta) Then Return
            Dim column As KanbanColumnState = _columns(columnIndex)
            Dim oldTop As Integer = column.TopCardIndex
            If delta < 0 Then
                column.TopCardIndex = Math.Min(ResolveColumnMaxTop(column), column.TopCardIndex + 1)
            ElseIf delta > 0 Then
                column.TopCardIndex = Math.Max(0, column.TopCardIndex - 1)
            End If
            If oldTop <> column.TopCardIndex Then InvalidateVisual()
        End Sub

        Protected Overrides Function OnKeyDown(ctx As MASThemeContext,
                                               keyCode As Keys) As Boolean
            If Not Enabled OrElse _columns.Count = 0 Then Return False
            NormalizeSelection()
            Select Case keyCode
                Case Keys.Left
                    MoveSelectionToColumn(If(MASKanbanBoardPolicy.ResolveRightToLeft(), 1, -1))
                    Return True
                Case Keys.Right
                    MoveSelectionToColumn(If(MASKanbanBoardPolicy.ResolveRightToLeft(), -1, 1))
                    Return True
                Case Keys.Up
                    If (System.Windows.Forms.Control.ModifierKeys And Keys.Control) = Keys.Control AndAlso MoveSelectedCardBy(-1) Then Return True
                    MoveSelectionWithinColumn(-1)
                    Return True
                Case Keys.Down
                    If (System.Windows.Forms.Control.ModifierKeys And Keys.Control) = Keys.Control AndAlso MoveSelectedCardBy(1) Then Return True
                    MoveSelectionWithinColumn(1)
                    Return True
                Case Keys.Home
                    SetSelection(0, If(_columns(0).Cards.Count > 0, 0, -1), True)
                    Return True
                Case Keys.End
                    Dim lastColumn As Integer = _columns.Count - 1
                    SetSelection(lastColumn, If(_columns(lastColumn).Cards.Count > 0, _columns(lastColumn).Cards.Count - 1, -1), True)
                    Return True
            End Select
            Return False
        End Function

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

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

#End Region

    End Class

End Namespace
