Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Windows.Forms
Imports Nexamas.UI.FloatRuntime
Imports Nexamas.UI.General
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports Nexamas.UI.Layout
Imports SkiaSharp

Namespace Nexamas.UI.Components.DropDownMenu

    Friend Partial NotInheritable Class DropDownMenuFloatContent
        Implements IMASFloatContent
        Implements IMASFloatInputPolicy
        Implements IMASFloatRenderableContent
        Implements IMASFloatRoutedInputContent
        Implements IMASFloatPointerMoveChangeAwareContent
        Implements IMASFloatSurfaceSizeContract
        Implements IDisposable

        Private ReadOnly _contextProvider As Func(Of MASThemeContext)
        Private ReadOnly _fallbackCtx As MASThemeContext
        Private ReadOnly _model As MASDropDownMenuModel
        Private ReadOnly _executeCommand As Action(Of String)
        Private ReadOnly _renderer As DropDownMenuRenderer
        Private ReadOnly _controller As New DropDownMenuController()
        Private ReadOnly _m As New DropDownMenuState()

        Private _session As IMASFloatSession
        Private _pendingCommand As String = String.Empty

        Private _anchorRectPx As SKRect
        Private _lastBoundsPx As SKRect = SKRect.Empty
        Private _dpi As Single = 1.0F
        Private _disposed As Boolean
        Private _closed As Boolean

        Friend Sub New(ctx As MASThemeContext,
                       model As MASDropDownMenuModel,
                       anchorRectPx As SKRect,
                       executeCommand As Action(Of String),
                       Optional contextProvider As Func(Of MASThemeContext) = Nothing)

            If ctx Is Nothing Then Throw New ArgumentNullException(NameOf(ctx))
            If model Is Nothing Then Throw New ArgumentNullException(NameOf(model))
            If executeCommand Is Nothing Then Throw New ArgumentNullException(NameOf(executeCommand))

            _fallbackCtx = ctx
            _contextProvider = contextProvider
            _model = model
            _anchorRectPx = anchorRectPx
            _executeCommand = executeCommand
            _renderer = New DropDownMenuRenderer()

            _dpi = PixelSnap.SafeDpi(ctx.Dpi)

            _m.Enabled = True
            _m.IsOpen = True
            _m.Model = _model
            _m.AnchorRectPx = _anchorRectPx
        End Sub

#Region "IMASFloatContent"

        Friend ReadOnly Property Name As String Implements IMASFloatContent.Name
            Get
                Return "DropDownMenuFloatContent"
            End Get
        End Property

        Friend Sub AttachSession(session As IMASFloatSession) Implements IMASFloatContent.AttachSession
            If session Is Nothing Then Throw New ArgumentNullException(NameOf(session))

            _session = session
            _closed = False

            _m.IsOpen = True
            _m.ResetInteractionState()
            StopDropDownContentMotion(resetState:=True)
        End Sub

        Friend Sub DetachSession() Implements IMASFloatContent.DetachSession
            If _disposed Then
                _session = Nothing
                Return
            End If

            CancelInteraction()
            StopDropDownContentMotion(resetState:=True)
            _m.IsOpen = False
            _closed = True
            _session = Nothing

            CommitPendingCommand()
        End Sub

#End Region


#Region "Size/Layout Surface Contract"

        Private Function MeasureFloatSurface(context As MASSizeContext,
                                             availableSize As SKSize,
                                             intent As MASSize) As MASSizeResult _
            Implements IMASFloatSurfaceSizeContract.MeasureFloatSurface

            Return MASFloatSurfaceSizeResolver.ResolveStandardSurface(
                kind:=MASFloatSurfaceKind.DropDownMenu,
                context:=context,
                availableSize:=availableSize,
                intent:=MASSize.Normalize(intent))
        End Function

#End Region

#Region "Input Policy"

        Friend ReadOnly Property AcceptsPointerInput As Boolean Implements IMASFloatInputPolicy.AcceptsPointerInput
            Get
                Return True
            End Get
        End Property

        Friend ReadOnly Property AcceptsKeyboardInput As Boolean Implements IMASFloatInputPolicy.AcceptsKeyboardInput
            Get
                Return True
            End Get
        End Property

        Friend ReadOnly Property AcceptsTextInput As Boolean Implements IMASFloatInputPolicy.AcceptsTextInput
            Get
                Return False
            End Get
        End Property

        Friend ReadOnly Property CloseOnOutsidePointer As Boolean Implements IMASFloatInputPolicy.CloseOnOutsidePointer
            Get
                Return True
            End Get
        End Property

        Friend ReadOnly Property SwallowOutsidePointer As Boolean Implements IMASFloatInputPolicy.SwallowOutsidePointer
            Get
                Return True
            End Get
        End Property

        Friend ReadOnly Property CloseOnEscape As Boolean Implements IMASFloatInputPolicy.CloseOnEscape
            Get
                Return True
            End Get
        End Property

#End Region

#Region "Render"

        Friend Sub RenderFloat(canvas As SKCanvas,
                               ctx As MASThemeContext,
                               boundsPx As SKRect) Implements IMASFloatRenderableContent.RenderFloat

            If _disposed Then Return
            If _closed Then Return
            If canvas Is Nothing Then Return
            If ctx Is Nothing Then Return
            If _model Is Nothing OrElse _model.Root Is Nothing Then Return
            If boundsPx.IsEmpty OrElse boundsPx.Width <= 1.0F OrElse boundsPx.Height <= 1.0F Then Return

            _lastBoundsPx = boundsPx
            Dim plan As DropDownMenuLayoutPlan = DropDownMenuLayoutPlan.Create(ctx, boundsPx, MASSize.Default)
            _dpi = PixelSnap.SafeDpi(plan.MetricDpi)
            _m.AnchorRectPx = _anchorRectPx

            NormalizePaths()

            _controller.UpdateLayout(
                m:=_m,
                viewportBoundsPx:=boundsPx,
                dpi:=_dpi)

            _renderer.Render(
                canvas:=canvas,
                ctx:=ctx,
                dpi:=_dpi,
                m:=_m)
        End Sub

#End Region

#Region "Routed Input"

        Friend Function HitTestFloat(ctx As MASThemeContext,
                             boundsPx As SKRect,
                             ptPx As SKPoint) As Boolean Implements IMASFloatRoutedInputContent.HitTestFloat

            If _disposed OrElse _closed Then Return False
            If Not _m.IsOpen Then Return False

            If boundsPx.IsEmpty OrElse boundsPx.Width <= 0.0F OrElse boundsPx.Height <= 0.0F Then
                Return False
            End If

            If Not boundsPx.Contains(ptPx.X, ptPx.Y) Then
                Return False
            End If

            If _lastBoundsPx.IsEmpty OrElse _lastBoundsPx.Width <= 1.0F OrElse _lastBoundsPx.Height <= 1.0F Then
                _lastBoundsPx = boundsPx
            End If

            EnsureLayout(ctx)

            If _m.HitTestAnyPanel(ptPx) Then
                Return True
            End If

            If _controller.IsPointInsideAnySubMenuBridge(_m, ptPx, _dpi) Then
                Return True
            End If

            Return False

        End Function

        Friend Sub PointerMoveFloat(ctx As MASThemeContext,
                                    ptPx As SKPoint) Implements IMASFloatRoutedInputContent.PointerMoveFloat

            PointerMoveFloatVisualChanged(ctx, ptPx)
        End Sub

        Friend Function PointerMoveFloatVisualChanged(ctx As MASThemeContext,
                                                      ptPx As SKPoint) As Boolean Implements IMASFloatPointerMoveChangeAwareContent.PointerMoveFloatVisualChanged

            If _disposed OrElse _closed Then Return False
            If Not _m.IsOpen Then Return False

            Dim oldHoverPath As Integer() = _m.HoverPath.ToArray()
            Dim oldOpenPath As Integer() = _m.OpenPath.ToArray()

            EnsureLayout(ctx)
            NormalizePaths()

            Dim levelHit As Integer = _controller.HitTestLevelOrBridge(_m, ptPx, _dpi)

            If levelHit >= 0 Then
                HandlePanelMove(levelHit, ptPx)

                Dim changed As Boolean = Not PathsEqual(oldHoverPath, _m.HoverPath) OrElse
                                         Not PathsEqual(oldOpenPath, _m.OpenPath)
                If changed Then StartDropDownInteractionMotion(oldHoverPath, oldOpenPath)
                Return changed
            End If

            If levelHit = -2 Then
                Return False
            End If

            _m.HoverPath.Clear()
            _m.OpenPath.Clear()

            Dim cleared As Boolean = Not PathsEqual(oldHoverPath, _m.HoverPath) OrElse
                                     Not PathsEqual(oldOpenPath, _m.OpenPath)
            If cleared Then StopDropDownContentMotion(resetState:=True)
            Return cleared
        End Function

        Friend Function PointerDownFloat(ctx As MASThemeContext,
                                 ptPx As SKPoint,
                                 button As MouseButtons) As Boolean Implements IMASFloatRoutedInputContent.PointerDownFloat

            If _disposed OrElse _closed Then Return True
            If Not _m.IsOpen Then Return True

            EnsureLayout(ctx)
            NormalizePaths()

            Dim insidePanel As Boolean = _m.HitTestAnyPanel(ptPx)
            Dim insideBridge As Boolean = _controller.IsPointInsideAnySubMenuBridge(_m, ptPx, _dpi)

            If Not insidePanel AndAlso Not insideBridge Then
                RequestClose(MASFloatCloseReason.OutsidePointer)
                Return True
            End If

            ' داخل القائمة: لا تسمح لأي زر غير اليسار أن يسقط للـ controls تحت القائمة.
            If button <> MouseButtons.Left Then
                Return True
            End If

            Dim level As Integer = _controller.HitTestLevel(_m, ptPx)
            If level < 0 Then Return True

            Dim idx As Integer = _controller.HitTestRowAtLevel(_m, level, ptPx, _dpi)

            If level < 0 OrElse level >= _m.LevelRows.Count Then Return True

            Dim rows As List(Of MASDropDownMenuNode) = _m.LevelRows(level)
            If rows Is Nothing OrElse idx < 0 OrElse idx >= rows.Count Then Return True

            Dim node As MASDropDownMenuNode = rows(idx)
            If node Is Nothing Then Return True

            If Not node.Enabled Then
                Return True
            End If

            EnsureListSize(_m.HoverPath, level + 1, -1)
            _m.HoverPath(level) = idx
            TrimList(_m.HoverPath, level + 1)

            If node.Kind = MASDropDownMenuNodeKind.ActionItem Then
                FireCommandAndClose(node.CommandId)
                Return True
            End If

            If node.Kind = MASDropDownMenuNodeKind.SubMenu Then
                OpenSubMenuAt(level, idx)
                Return True
            End If

            Return True
        End Function

        Friend Function PointerUpFloat(ctx As MASThemeContext,
                               ptPx As SKPoint,
                               button As MouseButtons) As Boolean Implements IMASFloatRoutedInputContent.PointerUpFloat

            If _disposed OrElse _closed Then Return True
            If Not _m.IsOpen Then Return True

            EnsureLayout(ctx)

            Dim insidePanel As Boolean = _m.HitTestAnyPanel(ptPx)
            Dim insideBridge As Boolean = _controller.IsPointInsideAnySubMenuBridge(_m, ptPx, _dpi)

            If insidePanel OrElse insideBridge Then
                Return True
            End If

            Return True
        End Function

        Friend Function PointerWheelFloat(ctx As MASThemeContext,
                                  ptPx As SKPoint,
                                  delta As Integer) As Boolean Implements IMASFloatRoutedInputContent.PointerWheelFloat

            If _disposed OrElse _closed Then Return True
            If Not _m.IsOpen Then Return True

            EnsureLayout(ctx)

            Dim level As Integer = _controller.HitTestLevel(_m, ptPx)

            If level >= 0 Then
                Dim rowStepPx As Single = Math.Max(12.0F, MenuTokens.DropDownRowHeight * _dpi)
                Dim wheelUnits As Single = If(delta = 0, 0.0F, CSng(delta) / 120.0F)
                Dim scrollDeltaPx As Single = -(wheelUnits * rowStepPx * 3.0F)

                If Math.Abs(scrollDeltaPx) > 0.01F Then
                    _controller.ScrollLevel(_m, level, scrollDeltaPx, _dpi)
                End If

                Return True
            End If

            If _controller.IsPointInsideAnySubMenuBridge(_m, ptPx, _dpi) Then
                Return True
            End If

            Return False
        End Function

        Friend Function KeyDownFloat(ctx As MASThemeContext,
                                     keyCode As Keys) As Boolean Implements IMASFloatRoutedInputContent.KeyDownFloat

            If _disposed OrElse _closed Then Return False
            If Not _m.IsOpen Then Return False

            EnsureLayout(ctx)

            Select Case keyCode
                Case Keys.Escape
                    RequestClose(MASFloatCloseReason.EscapeKey)
                    Return True

                Case Keys.Down
                    MoveHover(+1)
                    Return True

                Case Keys.Up
                    MoveHover(-1)
                    Return True

                Case Keys.Home
                    MoveHoverToBoundary(True)
                    Return True

                Case Keys.End
                    MoveHoverToBoundary(False)
                    Return True

                Case Keys.Right
                    OpenHoveredSubMenu()
                    Return True

                Case Keys.Left
                    Return CloseCurrentSubMenu()

                Case Keys.Enter, Keys.Space
                    Return InvokeHovered()
            End Select

            Return False
        End Function

        Friend Function KeyUpFloat(ctx As MASThemeContext,
                                   keyCode As Keys) As Boolean Implements IMASFloatRoutedInputContent.KeyUpFloat

            Return False
        End Function

        Friend Function TextInputFloat(ctx As MASThemeContext,
                                       text As String) As Boolean Implements IMASFloatRoutedInputContent.TextInputFloat

            Return False
        End Function

        Friend Function Win32ImeMessageFloat(ctx As MASThemeContext,
                                             hwnd As IntPtr,
                                             message As Integer,
                                             wParam As IntPtr,
                                             lParam As IntPtr) As Boolean Implements IMASFloatRoutedInputContent.Win32ImeMessageFloat

            Return False
        End Function

#End Region

        Private Sub EnsureLayout(ctx As MASThemeContext)
            If _disposed OrElse _closed Then Return
            If ctx Is Nothing Then ctx = ResolveContext()
            If ctx Is Nothing Then Return

            If _lastBoundsPx.IsEmpty OrElse _lastBoundsPx.Width <= 1.0F OrElse _lastBoundsPx.Height <= 1.0F Then
                Return
            End If

            Dim plan As DropDownMenuLayoutPlan = DropDownMenuLayoutPlan.Create(ctx, _lastBoundsPx, MASSize.Default)
            _dpi = PixelSnap.SafeDpi(plan.MetricDpi)
            _m.AnchorRectPx = _anchorRectPx

            _controller.UpdateLayout(
                m:=_m,
                viewportBoundsPx:=_lastBoundsPx,
                dpi:=_dpi)
        End Sub

        Private Function ResolveContext() As MASThemeContext
            If _contextProvider IsNot Nothing Then
                Try
                    Dim current As MASThemeContext = _contextProvider.Invoke()
                    If current IsNot Nothing Then Return current
                Catch masCaughtException1 As Exception
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRecoverable(masCaughtException1)
                End Try
            End If

            Return _fallbackCtx
        End Function

        Private Sub CancelInteraction()
            If _disposed Then Return

            _m.ResetInteractionState()
        End Sub

        Private Sub HandlePanelMove(levelHit As Integer, pt As SKPoint)
            Dim idx As Integer = _controller.HitTestRowAtLevel(_m, levelHit, pt, _dpi)

            EnsureListSize(_m.HoverPath, levelHit + 1, -1)
            _m.HoverPath(levelHit) = idx
            TrimList(_m.HoverPath, levelHit + 1)

            Dim rows As List(Of MASDropDownMenuNode) = Nothing

            If levelHit >= 0 AndAlso levelHit < _m.LevelRows.Count Then
                rows = _m.LevelRows(levelHit)
            End If

            Dim node As MASDropDownMenuNode = Nothing

            If rows IsNot Nothing AndAlso idx >= 0 AndAlso idx < rows.Count Then
                node = rows(idx)
            End If

            If node IsNot Nothing AndAlso node.Enabled AndAlso node.Kind = MASDropDownMenuNodeKind.SubMenu Then
                OpenSubMenuAt(levelHit, idx)
            ElseIf _m.OpenPath.Count > levelHit Then
                TrimList(_m.OpenPath, levelHit)
            End If
        End Sub

        Private Sub MoveHover(direction As Integer)
            Dim oldHoverPath As Integer() = _m.HoverPath.ToArray()
            Dim oldOpenPath As Integer() = _m.OpenPath.ToArray()
            Dim level As Integer = Math.Max(0, _m.LevelRows.Count - 1)
            If level < 0 OrElse level >= _m.LevelRows.Count Then Return

            Dim rows As List(Of MASDropDownMenuNode) = _m.LevelRows(level)
            If rows Is Nothing OrElse rows.Count = 0 Then Return

            EnsureListSize(_m.HoverPath, level + 1, -1)

            Dim start As Integer = _m.HoverPath(level)
            Dim nextIdx As Integer = FindNextAction(rows, start, direction)

            If nextIdx < 0 Then
                nextIdx = If(direction >= 0,
                             FindNextAction(rows, -1, +1),
                             FindNextAction(rows, rows.Count, -1))
            End If

            If nextIdx >= 0 Then
                _m.HoverPath(level) = nextIdx
                TrimList(_m.HoverPath, level + 1)

                If _m.OpenPath.Count > level Then
                    TrimList(_m.OpenPath, level)
                End If

                _controller.EnsureRowVisible(_m, level, nextIdx, _dpi)
                StartDropDownInteractionMotion(oldHoverPath, oldOpenPath)
            End If
        End Sub

        Private Sub MoveHoverToBoundary(first As Boolean)
            Dim oldHoverPath As Integer() = _m.HoverPath.ToArray()
            Dim oldOpenPath As Integer() = _m.OpenPath.ToArray()
            Dim level As Integer = Math.Max(0, _m.LevelRows.Count - 1)
            If level < 0 OrElse level >= _m.LevelRows.Count Then Return

            Dim rows As List(Of MASDropDownMenuNode) = _m.LevelRows(level)
            If rows Is Nothing OrElse rows.Count = 0 Then Return

            Dim idx As Integer = If(first,
                                    FindNextAction(rows, -1, +1),
                                    FindNextAction(rows, rows.Count, -1))

            If idx >= 0 Then
                EnsureListSize(_m.HoverPath, level + 1, -1)
                _m.HoverPath(level) = idx
                TrimList(_m.HoverPath, level + 1)
                _controller.EnsureRowVisible(_m, level, idx, _dpi)
                StartDropDownInteractionMotion(oldHoverPath, oldOpenPath)
            End If
        End Sub

        Private Sub OpenHoveredSubMenu()
            Dim level As Integer = Math.Max(0, _m.LevelRows.Count - 1)
            If level < 0 OrElse level >= _m.LevelRows.Count Then Return
            If level >= _m.HoverPath.Count Then Return

            Dim idx As Integer = _m.HoverPath(level)
            Dim rows As List(Of MASDropDownMenuNode) = _m.LevelRows(level)

            If rows Is Nothing OrElse idx < 0 OrElse idx >= rows.Count Then Return

            Dim node As MASDropDownMenuNode = rows(idx)

            If node Is Nothing Then Return
            If Not node.Enabled Then Return
            If node.Kind <> MASDropDownMenuNodeKind.SubMenu Then Return

            OpenSubMenuAt(level, idx)
        End Sub

        Private Sub OpenSubMenuAt(level As Integer, idx As Integer)
            Dim oldHoverPath As Integer() = _m.HoverPath.ToArray()
            Dim oldOpenPath As Integer() = _m.OpenPath.ToArray()
            EnsureListSize(_m.OpenPath, level + 1, -1)
            _m.OpenPath(level) = idx
            TrimList(_m.OpenPath, level + 1)
            _controller.EnsureRowVisible(_m, level, idx, _dpi)
            StartDropDownInteractionMotion(oldHoverPath, oldOpenPath)
        End Sub

        Private Function CloseCurrentSubMenu() As Boolean
            Dim oldHoverPath As Integer() = _m.HoverPath.ToArray()
            Dim oldOpenPath As Integer() = _m.OpenPath.ToArray()
            If _m.OpenPath.Count <= 0 Then Return False

            Dim newSize As Integer = Math.Max(0, _m.OpenPath.Count - 1)
            TrimList(_m.OpenPath, newSize)
            TrimList(_m.HoverPath, Math.Max(1, newSize + 1))
            StartDropDownInteractionMotion(oldHoverPath, oldOpenPath)

            Return True
        End Function

        Private Function InvokeHovered() As Boolean
            Dim level As Integer = Math.Max(0, _m.LevelRows.Count - 1)
            If level < 0 OrElse level >= _m.LevelRows.Count Then Return False
            If level >= _m.HoverPath.Count Then Return False

            Dim idx As Integer = _m.HoverPath(level)
            Dim rows As List(Of MASDropDownMenuNode) = _m.LevelRows(level)

            If rows Is Nothing OrElse idx < 0 OrElse idx >= rows.Count Then Return False

            Dim node As MASDropDownMenuNode = rows(idx)
            If node Is Nothing Then Return False
            If Not node.Enabled Then Return True

            If node.Kind = MASDropDownMenuNodeKind.ActionItem Then
                FireCommandAndClose(node.CommandId)
                Return True
            End If

            If node.Kind = MASDropDownMenuNodeKind.SubMenu Then
                OpenSubMenuAt(level, idx)
                Return True
            End If

            Return False
        End Function

        Private Shared Function FindNextAction(rows As List(Of MASDropDownMenuNode),
                                               startIndex As Integer,
                                               direction As Integer) As Integer

            If rows Is Nothing OrElse rows.Count = 0 Then Return -1
            If direction = 0 Then Return -1

            Dim i As Integer = startIndex

            Do
                i += direction

                If i < 0 OrElse i >= rows.Count Then Exit Do

                Dim node As MASDropDownMenuNode = rows(i)
                If node Is Nothing Then Continue Do
                If node.Kind = MASDropDownMenuNodeKind.Separator Then Continue Do
                If Not node.Enabled Then Continue Do

                Return i
            Loop

            Return -1
        End Function

        Private Sub FireCommandAndClose(commandId As String)
            Dim key As String = If(commandId, String.Empty).Trim()
            If key.Length = 0 Then Return

            _pendingCommand = key
            RequestClose(MASFloatCloseReason.Programmatic)
        End Sub

        Private Sub RequestClose(reason As MASFloatCloseReason)
            If _closed Then Return

            Dim session As IMASFloatSession = _session

            If session Is Nothing Then
                _closed = True
                CommitPendingCommand()
                Return
            End If

            Try
                session.Close(reason)
            Catch masCaughtException2 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRecoverable(masCaughtException2)
            End Try
        End Sub

        Private Sub CommitPendingCommand()
            Dim commandToRun As String = If(_pendingCommand, String.Empty).Trim()
            _pendingCommand = String.Empty

            If commandToRun.Length <= 0 Then Return

            Try
                _executeCommand.Invoke(commandToRun)
            Catch masCaughtException3 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowRecoverable(masCaughtException3)
            End Try
        End Sub

        Private Sub NormalizePaths()
            If Not _m.IsOpen Then
                _m.ResetInteractionState()
                Return
            End If
        End Sub

        Private Shared Sub EnsureListSize(list As List(Of Integer),
                                          size As Integer,
                                          fillValue As Integer)

            If list Is Nothing Then Return

            While list.Count < size
                list.Add(fillValue)
            End While
        End Sub

        Private Shared Sub TrimList(list As List(Of Integer), size As Integer)
            If list Is Nothing Then Return
            If size < 0 Then size = 0

            While list.Count > size
                list.RemoveAt(list.Count - 1)
            End While
        End Sub

        Private Shared Function PathsEqual(before As Integer(), afterPath As List(Of Integer)) As Boolean
            Dim afterCount As Integer = If(afterPath Is Nothing, 0, afterPath.Count)
            Dim beforeCount As Integer = If(before Is Nothing, 0, before.Length)

            If beforeCount <> afterCount Then Return False

            For i As Integer = 0 To beforeCount - 1
                If before(i) <> afterPath(i) Then Return False
            Next

            Return True
        End Function

        Public Sub Dispose() Implements IDisposable.Dispose
            If _disposed Then Return
            _disposed = True

            StopDropDownContentMotion(resetState:=True)

            _session = Nothing
            _pendingCommand = String.Empty

            Try
                _renderer.Dispose()
            Catch masCaughtException4 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDisposeCleanup(masCaughtException4)
            End Try
        End Sub

    End Class

End Namespace