Option Strict On
Option Explicit On

Imports System
Imports System.Windows.Forms
Imports Nexamas.UI.Host

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Beginner-facing input API for one MASApplicationWindow.
    ''' It exposes intent-level input settings and notifications without exposing the raw RootHost input coordinator.
    ''' </summary>
    Public NotInheritable Class MASApplicationWindowInput

        Private ReadOnly _rootHost As MASSkiaRootHost
        Private ReadOnly _input As MASSkiaRootInputCoordinator
        Private ReadOnly _throwIfDisposed As Action

        ''' <summary>
        ''' Pre-route observation notification. Handlers cannot mark the pointer event handled or suppress MAS routing.
        ''' Use MAS controls, commands, or official routing participants for behavior; this event is diagnostics/telemetry only.
        ''' </summary>
        Public Event PointerMoved(clientX As Single, clientY As Single)

        ''' <summary>
        ''' Pre-route observation notification. Handlers cannot mark the pointer event handled or suppress MAS routing.
        ''' Use MAS controls, commands, or official routing participants for behavior; this event is diagnostics/telemetry only.
        ''' </summary>
        Public Event PointerDown(clientX As Single, clientY As Single, button As MouseButtons)

        ''' <summary>
        ''' Pre-route observation notification. Handlers cannot mark the pointer event handled or suppress MAS routing.
        ''' Use MAS controls, commands, or official routing participants for behavior; this event is diagnostics/telemetry only.
        ''' </summary>
        Public Event PointerUp(clientX As Single, clientY As Single, button As MouseButtons)

        ''' <summary>
        ''' Pre-route observation notification. Handlers cannot mark the wheel event handled or suppress MAS routing/page fallback.
        ''' Use MAS controls or official routing participants for behavior; this event is diagnostics/telemetry only.
        ''' </summary>
        Public Event PointerWheel(clientX As Single, clientY As Single, delta As Integer)

        Public Event PointerLeft()
        Public Event HostFocusLost()

        Friend Sub New(rootHost As MASSkiaRootHost,
                       input As MASSkiaRootInputCoordinator,
                       throwIfDisposed As Action)

            If rootHost Is Nothing Then Throw New ArgumentNullException(NameOf(rootHost))
            If input Is Nothing Then Throw New ArgumentNullException(NameOf(input))
            If throwIfDisposed Is Nothing Then Throw New ArgumentNullException(NameOf(throwIfDisposed))
            _rootHost = rootHost
            _input = input
            _throwIfDisposed = throwIfDisposed

            AddHandler _input.PointerMoved, AddressOf Input_PointerMoved
            AddHandler _input.PointerDown, AddressOf Input_PointerDown
            AddHandler _input.PointerUp, AddressOf Input_PointerUp
            AddHandler _input.PointerWheel, AddressOf Input_PointerWheel
            AddHandler _input.PointerLeft, AddressOf Input_PointerLeft
            AddHandler _input.HostFocusLost, AddressOf Input_HostFocusLost
        End Sub

        ''' <summary>
        ''' Enables WinForms mouse capture while dragging the MAS top bar.
        ''' </summary>
        Public Property UseMouseCaptureForTopBar As Boolean
            Get
                Return InvokeOnUiThread(
                    Function() _input.UseMouseCaptureForTopBar,
                    "MASApplicationWindow.Input.UseMouseCaptureForTopBar.Get")
            End Get
            Set(value As Boolean)
                InvokeOnUiThread(
                    Sub() _input.UseMouseCaptureForTopBar = value,
                    "MASApplicationWindow.Input.UseMouseCaptureForTopBar.Set")
            End Set
        End Property

        ''' <summary>
        ''' Enables the smarter MAS top bar move path used by the root input coordinator.
        ''' </summary>
        Public Property UseSmartTopBarMove As Boolean
            Get
                Return InvokeOnUiThread(
                    Function() _input.UseSmartTopBarMove,
                    "MASApplicationWindow.Input.UseSmartTopBarMove.Get")
            End Get
            Set(value As Boolean)
                InvokeOnUiThread(
                    Sub() _input.UseSmartTopBarMove = value,
                    "MASApplicationWindow.Input.UseSmartTopBarMove.Set")
            End Set
        End Property

        ''' <summary>
        ''' True when the owning window has a top-bar input region attached.
        ''' </summary>
        Public ReadOnly Property HasTopBar As Boolean
            Get
                Return InvokeOnUiThread(
                    Function() _input.HasTopBar,
                    "MASApplicationWindow.Input.HasTopBar.Get")
            End Get
        End Property

        ''' <summary>
        ''' True when native WinForms/SKGLControl input handlers are attached automatically.
        ''' </summary>
        Public ReadOnly Property IsNativeInputAttached As Boolean
            Get
                Return InvokeOnUiThread(
                    Function() _input.IsNativeInputAttached,
                    "MASApplicationWindow.Input.IsNativeInputAttached.Get")
            End Get
        End Property

        ''' <summary>
        ''' Attaches native WinForms/SKGLControl input handlers.
        ''' Use this after creating a window with autoHookPointerInput:=False.
        ''' </summary>
        Public Sub AttachNativeInput()
            InvokeOnUiThread(
                Sub() _input.AttachNativeInput(),
                "MASApplicationWindow.Input.AttachNativeInput")
        End Sub

        ''' <summary>
        ''' Detaches native WinForms/SKGLControl input handlers while leaving manual routing methods available internally.
        ''' </summary>
        Public Sub DetachNativeInput()
            InvokeOnUiThread(
                Sub() _input.DetachNativeInput(),
                "MASApplicationWindow.Input.DetachNativeInput")
        End Sub

        ''' <summary>
        ''' Releases any pointer capture owned by the window input router.
        ''' </summary>
        Public Sub ReleasePointerCapture()
            InvokeOnUiThread(
                Sub() _input.ForceReleaseAllCapture(),
                "MASApplicationWindow.Input.ReleasePointerCapture")
        End Sub

        ''' <summary>
        ''' Synchronizes the input hot-state from the current OS cursor position.
        ''' Useful after native focus or mouse transitions.
        ''' </summary>
        Public Sub SyncPointerFromCursor()
            InvokeOnUiThread(
                Sub() _input.SyncMouseFromCursor(),
                "MASApplicationWindow.Input.SyncPointerFromCursor")
        End Sub

        ''' <summary>
        ''' Advanced compatibility access to the raw RootHost input coordinator.
        ''' Prefer MASApplicationWindow.Input settings/events/methods for normal SDK code.
        ''' </summary>
        <Obsolete("AdvancedCoordinator is a internal advanced compatibility hook. Prefer MASApplicationWindow.Input for new SDK code.", True)>
        Friend ReadOnly Property AdvancedCoordinator As MASSkiaRootInputCoordinator
            Get
                ThrowIfDisposed()
                Return _input
            End Get
        End Property

        Private Sub InvokeOnUiThread(action As Action, diagnosticName As String)
            If action Is Nothing Then Return

            ThrowIfDisposed()

            Dim executed As Boolean = False
            Dim capturedException As Exception = Nothing
            Dim invoked As Boolean = _rootHost.InvokeOnUiThreadCore(
                Sub()
                    executed = True

                    Try
                        action.Invoke()
                    Catch ex As Exception
                        capturedException = ex
                    End Try
                End Sub,
                diagnosticName)

            If capturedException IsNot Nothing Then
                Throw New InvalidOperationException(
                    "MASApplicationWindow.Input public operation failed on the owning UI thread. See InnerException for the original misuse or runtime fault.",
                    capturedException)
            End If

            If Not invoked OrElse Not executed Then
                ThrowIfDisposed()
                Throw New InvalidOperationException("MASApplicationWindow.Input requires an active UI-thread host before input operations can be invoked.")
            End If
        End Sub

        Private Function InvokeOnUiThread(Of TResult)(func As Func(Of TResult),
                                                      diagnosticName As String) As TResult

            If func Is Nothing Then Return Nothing

            ThrowIfDisposed()

            Dim executed As Boolean = False
            Dim capturedException As Exception = Nothing
            Dim result As TResult = _rootHost.InvokeOnUiThreadCore(
                Function()
                    executed = True

                    Try
                        Return func.Invoke()
                    Catch ex As Exception
                        capturedException = ex
                        Return Nothing
                    End Try
                End Function,
                Nothing,
                diagnosticName)

            If capturedException IsNot Nothing Then
                Throw New InvalidOperationException(
                    "MASApplicationWindow.Input public query failed on the owning UI thread. See InnerException for the original misuse or runtime fault.",
                    capturedException)
            End If

            If Not executed Then
                ThrowIfDisposed()
                Throw New InvalidOperationException("MASApplicationWindow.Input requires an active UI-thread host before input operations can be invoked.")
            End If

            Return result
        End Function

        Private Sub ThrowIfDisposed()
            _throwIfDisposed.Invoke()
        End Sub

        Private Sub Input_PointerMoved(clientX As Single, clientY As Single)
            Try
                RaiseEvent PointerMoved(clientX, clientY)
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException1, "MASApplicationWindow.Input.PointerMoved")
            End Try
        End Sub

        Private Sub Input_PointerDown(clientX As Single, clientY As Single, button As MouseButtons)
            Try
                RaiseEvent PointerDown(clientX, clientY, button)
            Catch masCaughtException2 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException2, "MASApplicationWindow.Input.PointerDown")
            End Try
        End Sub

        Private Sub Input_PointerUp(clientX As Single, clientY As Single, button As MouseButtons)
            Try
                RaiseEvent PointerUp(clientX, clientY, button)
            Catch masCaughtException3 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException3, "MASApplicationWindow.Input.PointerUp")
            End Try
        End Sub

        Private Sub Input_PointerWheel(clientX As Single, clientY As Single, delta As Integer)
            Try
                RaiseEvent PointerWheel(clientX, clientY, delta)
            Catch masCaughtException4 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException4, "MASApplicationWindow.Input.PointerWheel")
            End Try
        End Sub

        Private Sub Input_PointerLeft()
            Try
                RaiseEvent PointerLeft()
            Catch masCaughtException5 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException5, "MASApplicationWindow.Input.PointerLeft")
            End Try
        End Sub

        Private Sub Input_HostFocusLost()
            Try
                RaiseEvent HostFocusLost()
            Catch masCaughtException6 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException6, "MASApplicationWindow.Input.HostFocusLost")
            End Try
        End Sub

    End Class

End Namespace
