Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.FloatRuntime
Imports Nexamas.UI.Host
Imports SkiaSharp

Namespace Nexamas.UI.Controls

    Friend NotInheritable Class MASToastFloatService
        Implements IDisposable

        Private ReadOnly _rootHost As MASSkiaRootHost
        Private _content As MASToastFloatContent
        Private _handle As MASFloatHandle
        Private _disposed As Boolean

        Friend Sub New(rootHost As MASSkiaRootHost)
            If rootHost Is Nothing Then Throw New ArgumentNullException(NameOf(rootHost))
            _rootHost = rootHost
        End Sub

        Friend Function Show(options As MASToastOptions) As Integer
            Dim toastId As Integer = 0
            ShowWithSurfaceResult(options, toastId)
            Return toastId
        End Function

        Friend Function ShowWithSurfaceResult(options As MASToastOptions,
                                              ByRef toastId As Integer) As MASFloatShowResult
            If _disposed Then
                toastId = 0
                Return MASFloatShowResult.Rejected("Toast service is disposed.")
            End If

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

            EnsureContent()

            toastId = _content.ShowToast(options)
            Dim showResult As MASFloatShowResult = EnsureFloatOpen()

            _rootHost.RequestInvalidate()
            Return showResult
        End Function

        Friend Function Info(message As String,
                             Optional title As String = "") As Integer
            Return Show(MASToastOptions.Info(message, title))
        End Function

        Friend Function Success(message As String,
                                Optional title As String = "") As Integer
            Return Show(MASToastOptions.Success(message, title))
        End Function

        Friend Function Warning(message As String,
                                Optional title As String = "") As Integer
            Return Show(MASToastOptions.Warning(message, title))
        End Function

        Friend Function Danger(message As String,
                               Optional title As String = "") As Integer
            Return Show(MASToastOptions.Danger(message, title))
        End Function

        Friend Function Dismiss(toastId As Integer) As Boolean
            If _content Is Nothing Then Return False
            Return _content.Dismiss(toastId)
        End Function

        Friend Sub ClearAll()
            If _content Is Nothing Then Return
            _content.ClearAll()
        End Sub

        Private Sub EnsureContent()
            If _content IsNot Nothing Then Return

            _content = New MASToastFloatContent(
                invalidate:=Sub()
                                _rootHost.RequestInvalidate()
                            End Sub,
                motionFrameClock:=_rootHost.MotionFrameClockCore)
        End Sub

        Private Function EnsureFloatOpen() As MASFloatShowResult
            If _handle IsNot Nothing AndAlso _rootHost.FloatRuntimeCore.IsOpen(_handle) Then
                Return MASFloatShowResult.Reused(_handle)
            End If

            Dim shownHandle As MASFloatHandle = Nothing

            Dim request As New MASFloatRequest() With {
                .FloatKey = MASFloatKeys.Toast,
                .Content = _content,
                .OwnerKey = "MAS.RootHost.Toast",
                .RequestedSlot = MASFloatSlot.System,
                .RequestedScope = MASFloatScope.Owner,
                .RequestedLayer = MASFloatLayerLevel.Passive,
                .RequestedPresentation = MASFloatPresentationProfiles.Toast(),
                .ShowPolicy = MASFloatShowPolicy.ReuseIfSameOwner,
                .AvailableBoundsPx = _rootHost.GetSurfaceViewportPx(),
                .InitialBoundsPx = _rootHost.GetSurfaceViewportPx(),
                .OnClosed = Sub(args As MASFloatClosedEventArgs)
                                Dim ownsClosingHandle As Boolean = False

                                If args IsNot Nothing Then
                                    ownsClosingHandle = IsSameHandle(args.Handle, shownHandle)
                                Else
                                    ownsClosingHandle = (_handle Is Nothing OrElse IsSameHandle(_handle, shownHandle))
                                End If

                                If ownsClosingHandle AndAlso
                                   (_handle Is Nothing OrElse IsSameHandle(_handle, shownHandle)) Then

                                    _handle = Nothing
                                End If
                            End Sub
            }

            Dim showResult As MASFloatShowResult = _rootHost.FloatRuntimeCore.ShowEx(request)
            shownHandle = If(showResult Is Nothing, Nothing, showResult.Handle)
            _handle = shownHandle

            Return If(showResult, MASFloatShowResult.Rejected("Toast Float show returned no result."))
        End Function

        Private Shared Function IsSameHandle(left As MASFloatHandle,
                                             right As MASFloatHandle) As Boolean

            If left Is Nothing OrElse right Is Nothing Then Return False
            Return left.Id = right.Id AndAlso left.Generation = right.Generation
        End Function
        Friend ReadOnly Property HasAnyToast As Boolean
            Get
                Return _content IsNot Nothing AndAlso _content.HasAnyToast
            End Get
        End Property
        Public Sub Dispose() Implements IDisposable.Dispose
            If _disposed Then Return
            _disposed = True

            Try
                If _handle IsNot Nothing Then
                    _rootHost.FloatRuntimeCore.Close(_handle, MASFloatCloseReason.Programmatic)
                End If
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowBoundary(masCaughtException1)
            End Try

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

            _handle = Nothing
            _content = Nothing
        End Sub

    End Class

End Namespace