Option Strict On
Option Explicit On

Namespace Nexamas.UI.Components

    Friend NotInheritable Class MASTreeInteractionController

        Private _hoverNode As MASTreeNode = Nothing
        Private _pressedNode As MASTreeNode = Nothing

        Friend ReadOnly Property HoverNode As MASTreeNode
            Get
                Return _hoverNode
            End Get
        End Property

        Friend ReadOnly Property PressedNode As MASTreeNode
            Get
                Return _pressedNode
            End Get
        End Property

        Friend Function SetHover(node As MASTreeNode) As Boolean
            If Object.ReferenceEquals(_hoverNode, node) Then Return False
            _hoverNode = node
            Return True
        End Function

        Friend Function SetPressed(node As MASTreeNode) As Boolean
            If Object.ReferenceEquals(_pressedNode, node) Then Return False
            _pressedNode = node
            Return True
        End Function

        Friend Function ClearHover() As Boolean
            If _hoverNode Is Nothing Then Return False
            _hoverNode = Nothing
            Return True
        End Function

        Friend Function ClearPressed() As Boolean
            If _pressedNode Is Nothing Then Return False
            _pressedNode = Nothing
            Return True
        End Function

        Friend Function ClearAll() As Boolean
            Dim changed As Boolean = False

            If _hoverNode IsNot Nothing Then
                _hoverNode = Nothing
                changed = True
            End If

            If _pressedNode IsNot Nothing Then
                _pressedNode = Nothing
                changed = True
            End If

            Return changed
        End Function

        Friend Sub NormalizeAfterNodesChanged(rootNodes As IReadOnlyList(Of MASTreeNode))
            If _hoverNode IsNot Nothing AndAlso Not ContainsNode(rootNodes, _hoverNode) Then
                _hoverNode = Nothing
            End If

            If _pressedNode IsNot Nothing AndAlso Not ContainsNode(rootNodes, _pressedNode) Then
                _pressedNode = Nothing
            End If
        End Sub

        Private Shared Function ContainsNode(nodes As IReadOnlyList(Of MASTreeNode),
                                             target As MASTreeNode) As Boolean

            If nodes Is Nothing OrElse target Is Nothing Then Return False

            For Each n As MASTreeNode In nodes
                If ContainsNodeRecursive(n, target) Then Return True
            Next

            Return False
        End Function

        Private Shared Function ContainsNodeRecursive(node As MASTreeNode,
                                                      target As MASTreeNode) As Boolean

            If node Is Nothing OrElse target Is Nothing Then Return False
            If Object.ReferenceEquals(node, target) Then Return True

            For Each c As MASTreeNode In node.Children
                If ContainsNodeRecursive(c, target) Then Return True
            Next

            Return False
        End Function

    End Class

End Namespace