Option Strict On
Option Explicit On

Imports System
Imports System.Windows.Forms
Imports Nexamas.UI.Composition
Imports Nexamas.UI.Controls
Imports SkiaSharp

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Public SDK facade for lightweight layered WinForms scenes.
    ''' This is the stable Application-level replacement for direct MASLayeredSceneHost usage.
    ''' </summary>
    <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
    Friend NotInheritable Class MASApplicationLayeredSceneHost
        Implements IDisposable

        Friend Delegate Sub DrawSceneCallback(canvas As SKCanvas,
                                              width As Integer,
                                              height As Integer,
                                              context As MASApplicationLayeredSceneContext)

        Private ReadOnly _inner As MASLayeredSceneHost
        Private ReadOnly _presentation As MASApplicationLayeredScenePresentation
        Private _disposed As Boolean

        Friend Sub New(owner As Form,
                       drawScene As DrawSceneCallback,
                       renderPadding As Integer,
                       supersampleScale As Integer)

            If owner Is Nothing Then Throw New ArgumentNullException(NameOf(owner))
            If drawScene Is Nothing Then Throw New ArgumentNullException(NameOf(drawScene))

            _inner =
                New MASLayeredSceneHost(
                    owner:=owner,
                    drawScene:=Sub(canvas As SKCanvas,
                                   width As Integer,
                                   height As Integer,
                                   themeContext As Theming.MASThemeContext)

                                   Dim publicContext As New MASApplicationLayeredSceneContext(
                                       themeContext:=themeContext,
                                       width:=width,
                                       height:=height)

                                   drawScene.Invoke(
                                       canvas:=canvas,
                                       width:=width,
                                       height:=height,
                                       context:=publicContext)

                               End Sub,
                    renderPadding:=renderPadding,
                    supersampleScale:=supersampleScale)

            _presentation =
                New MASApplicationLayeredScenePresentation(
                    owner:=owner,
                    invalidateLayout:=AddressOf InvalidateCompositionLayout)

        End Sub

        Friend ReadOnly Property Presentation As MASApplicationLayeredScenePresentation
            Get
                ThrowIfDisposed()
                Return _presentation
            End Get
        End Property

        Friend ReadOnly Property Dpi As Single
            Get
                If _disposed OrElse _inner Is Nothing Then Return 1.0F
                Return _inner.Dpi
            End Get
        End Property

        Friend ReadOnly Property IsDisposed As Boolean
            Get
                Return _disposed
            End Get
        End Property

        Friend Sub Add(control As MASControlBase)

            ThrowIfDisposed()

            If control Is Nothing Then Throw New ArgumentNullException(NameOf(control))

            _inner.Add(control)

        End Sub

        Friend Sub FocusControl(control As MASControlBase)

            ThrowIfDisposed()

            If control Is Nothing Then Return

            _inner.FocusControl(control)

        End Sub

        Friend Function BuildCompositionScrollKey(suffix As String) As String

            ThrowIfDisposed()

            Return _inner.BuildCompositionScrollKey(suffix)

        End Function

        Friend Function ApplyCompositionLayout(layout As IMASLayoutNode,
                                               viewportLogical As SKRect) As Boolean

            ThrowIfDisposed()

            Return _inner.ApplyCompositionLayout(layout, viewportLogical)

        End Function


        Friend Sub InvalidateCompositionLayout()

            ThrowIfDisposed()

            _inner.InvalidateCompositionLayout()

        End Sub

        Friend Function RouteCompositionPointerWheel(pointLogical As SKPoint,
                                                     delta As Integer) As Boolean

            If _disposed Then Return False

            Return _inner.RouteCompositionPointerWheel(pointLogical, delta)

        End Function

        Friend Function RouteCompositionPointerDown(pointLogical As SKPoint) As Boolean

            If _disposed Then Return False

            Return _inner.RouteCompositionPointerDown(pointLogical)

        End Function

        Friend Function RouteCompositionPointerMove(pointLogical As SKPoint) As Boolean

            If _disposed Then Return False

            Return _inner.RouteCompositionPointerMove(pointLogical)

        End Function

        Friend Function RouteCompositionPointerUp(pointLogical As SKPoint) As Boolean

            If _disposed Then Return False

            Return _inner.RouteCompositionPointerUp(pointLogical)

        End Function

        Friend Function RouteCompositionPointerLeave() As Boolean

            If _disposed Then Return False

            Return _inner.RouteCompositionPointerLeave()

        End Function

        Friend Sub MouseMove(e As MouseEventArgs)

            If _disposed Then Return
            If e Is Nothing Then Return

            _inner.MouseMove(e)

        End Sub

        Friend Sub MouseLeave()

            If _disposed Then Return

            _inner.MouseLeave()

        End Sub

        Friend Sub MouseDown(e As MouseEventArgs)

            If _disposed Then Return
            If e Is Nothing Then Return

            _inner.MouseDown(e)

        End Sub

        Friend Sub MouseUp(e As MouseEventArgs)

            If _disposed Then Return
            If e Is Nothing Then Return

            _inner.MouseUp(e)

        End Sub

        Friend Sub MouseWheel(e As MouseEventArgs)

            If _disposed Then Return
            If e Is Nothing Then Return

            _inner.MouseWheel(e)

        End Sub

        Friend Function KeyDown(e As KeyEventArgs) As Boolean

            If _disposed Then Return False
            If e Is Nothing Then Return False

            Return _inner.KeyDown(e)

        End Function

        Friend Function KeyUp(e As KeyEventArgs) As Boolean

            If _disposed Then Return False
            If e Is Nothing Then Return False

            Return _inner.KeyUp(e)

        End Function

        Friend Sub Render()

            If _disposed Then Return

            _inner.Render()

        End Sub

        Private Sub ThrowIfDisposed()

            If _disposed Then
                Throw New ObjectDisposedException(NameOf(MASApplicationLayeredSceneHost))
            End If

        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose

            If _disposed Then Return

            _disposed = True

            Try
                If _presentation IsNot Nothing Then
                    _presentation.Dispose()
                End If

                If _inner IsNot Nothing Then
                    _inner.Dispose()
                End If
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowBoundary(masCaughtException1)
            End Try

        End Sub

    End Class

End Namespace
