Option Strict On
Option Explicit On

Imports System.Collections.Generic
Imports System.Windows.Forms

Namespace Nexamas.UI.Components

    Friend Enum MASTreeKeyboardAction
        None = 0
        SelectionChanged = 1
        ExpansionChanged = 2
        Activated = 3
    End Enum

    Friend Structure MASTreeKeyboardResult
        Friend Action As MASTreeKeyboardAction
        Friend SelectedNode As MASTreeNode
    End Structure

    Friend NotInheritable Class MASTreeKeyboardNavigator

        Private Sub New()
        End Sub

        Friend Shared Function HandleKeyFromFlattened(
            visible As IReadOnlyList(Of MASTreeLayoutEngine.VisibleNodeEntry),
            currentSelectedNode As MASTreeNode,
            keyCode As Keys
        ) As MASTreeKeyboardResult

            Dim result As New MASTreeKeyboardResult With {
                .Action = MASTreeKeyboardAction.None,
                .SelectedNode = currentSelectedNode
            }

            If visible Is Nothing OrElse visible.Count = 0 Then Return result

            Dim currentIndex As Integer = IndexOfNode(visible, currentSelectedNode)
            If currentIndex < 0 Then currentIndex = 0

            Select Case keyCode

                Case Keys.Up
                    currentIndex = Math.Max(0, currentIndex - 1)
                    result.SelectedNode = visible(currentIndex).Node
                    result.Action = MASTreeKeyboardAction.SelectionChanged
                    Return result

                Case Keys.Down
                    currentIndex = Math.Min(visible.Count - 1, currentIndex + 1)
                    result.SelectedNode = visible(currentIndex).Node
                    result.Action = MASTreeKeyboardAction.SelectionChanged
                    Return result

                Case Keys.Left
                    If currentSelectedNode Is Nothing Then
                        result.SelectedNode = visible(0).Node
                        result.Action = MASTreeKeyboardAction.SelectionChanged
                        Return result
                    End If

                    If currentSelectedNode.HasChildren AndAlso currentSelectedNode.IsExpanded Then
                        If currentSelectedNode.SetExpandedFromOwner(False) Then
                            result.Action = MASTreeKeyboardAction.ExpansionChanged
                            Return result
                        End If
                    End If

                    If currentSelectedNode.Parent IsNot Nothing Then
                        result.SelectedNode = currentSelectedNode.Parent
                        result.Action = MASTreeKeyboardAction.SelectionChanged
                        Return result
                    End If

                Case Keys.Right
                    If currentSelectedNode Is Nothing Then
                        result.SelectedNode = visible(0).Node
                        result.Action = MASTreeKeyboardAction.SelectionChanged
                        Return result
                    End If

                    If currentSelectedNode.HasChildren Then
                        If Not currentSelectedNode.IsExpanded Then
                            If currentSelectedNode.SetExpandedFromOwner(True) Then
                                result.Action = MASTreeKeyboardAction.ExpansionChanged
                                Return result
                            End If
                        End If

                        If currentSelectedNode.Children.Count > 0 Then
                            result.SelectedNode = currentSelectedNode.Children(0)
                            result.Action = MASTreeKeyboardAction.SelectionChanged
                            Return result
                        End If
                    End If

                Case Keys.Home
                    result.SelectedNode = visible(0).Node
                    result.Action = MASTreeKeyboardAction.SelectionChanged
                    Return result

                Case Keys.End
                    result.SelectedNode = visible(visible.Count - 1).Node
                    result.Action = MASTreeKeyboardAction.SelectionChanged
                    Return result

                Case Keys.Enter
                    If currentSelectedNode IsNot Nothing Then
                        result.Action = MASTreeKeyboardAction.Activated
                        Return result
                    End If

                Case Keys.Space
                    ' Space is intentionally not an activation/expansion key.
                    ' FileExplorer-style navigation activates only with Enter.
                    Return result
            End Select

            Return result
        End Function

        Private Shared Function IndexOfNode(
            items As IReadOnlyList(Of MASTreeLayoutEngine.VisibleNodeEntry),
            node As MASTreeNode
        ) As Integer

            If items Is Nothing OrElse node Is Nothing Then Return -1

            For i As Integer = 0 To items.Count - 1
                If Object.ReferenceEquals(items(i).Node, node) Then
                    Return i
                End If
            Next

            Return -1
        End Function

    End Class

End Namespace