Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Components
Imports Nexamas.UI.FloatRuntime
Imports Nexamas.UI.Host
Imports SkiaSharp

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Application service for showing MASFileExplorerView through MASFloatRuntime.
    '''
    ''' This class is not an Overlay service.
    ''' It does not own global/current Float lifecycle.
    ''' It does not keep a current handle.
    ''' It does not close "whatever is open".
    '''
    ''' Responsibilities:
    ''' - Build FileExplorer Float requests.
    ''' - Show FileExplorer Float requests.
    ''' - Provide convenient Computer/custom-explorer entry points.
    ''' - Bridge FileExplorer internal ViewModeRequested into a child Float menu.
    '''
    ''' Lifecycle ownership remains inside MASFloatRuntime.
    ''' </summary>
    Partial Friend NotInheritable Class MASFileExplorerService

        Private Const DefaultOwnerKey As String = "MAS.FileExplorer.Service"

        Private ReadOnly _rootHost As MASSkiaRootHost
        Private ReadOnly _ownerGate As New Object()
        Private ReadOnly _activeOwnerKeys As New Dictionary(Of String, Integer)(StringComparer.Ordinal)

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

#Region "Show - default computer"

        Friend Function ShowComputer(Optional ownerKey As String = DefaultOwnerKey,
                                     Optional onClosed As Action = Nothing,
                                     Optional onAccepted As Action(Of MASFileExplorerFloatResult) = Nothing,
                                     Optional onCancelled As Action = Nothing) As MASFloatHandle

            Return ToCompatibilityFloatHandle(
                ShowComputerEx(
                    ownerKey:=ownerKey,
                    onClosed:=onClosed,
                    onAccepted:=onAccepted,
                    onCancelled:=onCancelled))

        End Function

        Friend Function ShowComputerEx(Optional ownerKey As String = DefaultOwnerKey,
                                       Optional onClosed As Action = Nothing,
                                       Optional onAccepted As Action(Of MASFileExplorerFloatResult) = Nothing,
                                       Optional onCancelled As Action = Nothing) As MASFloatShowResult

            Return ShowComputerEx(
                ownerKey:=ownerKey,
                options:=MASFileExplorerFloatOptions.CreateDefault(),
                onOpened:=Nothing,
                onClosed:=ToClosedCallback(onClosed),
                onAccepted:=onAccepted,
                onCancelled:=onCancelled
            )

        End Function

        Friend Function ShowComputer(ownerKey As String,
                                     options As MASFileExplorerFloatOptions,
                                     Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                                     Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing,
                                     Optional onAccepted As Action(Of MASFileExplorerFloatResult) = Nothing,
                                     Optional onCancelled As Action = Nothing) As MASFloatHandle

            Return ToCompatibilityFloatHandle(
                ShowComputerEx(
                    ownerKey:=ownerKey,
                    options:=options,
                    onOpened:=onOpened,
                    onClosed:=onClosed,
                    onAccepted:=onAccepted,
                    onCancelled:=onCancelled))

        End Function

        Friend Function ShowComputerEx(ownerKey As String,
                                       options As MASFileExplorerFloatOptions,
                                       Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                                       Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing,
                                       Optional onAccepted As Action(Of MASFileExplorerFloatResult) = Nothing,
                                       Optional onCancelled As Action = Nothing) As MASFloatShowResult

            Dim request As MASFloatRequest =
                CreateComputerRequest(
                    ownerKey:=ownerKey,
                    options:=options,
                    onOpened:=onOpened,
                    onClosed:=ComposeExplorerClosedCallback(onClosed, onAccepted, onCancelled)
                )

            Return ShowRequestEx(request)

        End Function

        ''' <summary>
        ''' Internal path for creating a default computer float request. SDK code should call ShowComputer instead.
        ''' </summary>
        Friend Function CreateComputerRequest(Optional ownerKey As String = DefaultOwnerKey,
                                              Optional options As MASFileExplorerFloatOptions = Nothing,
                                              Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                                              Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatRequest

            Dim safeOwnerKey As String = NormalizeOwnerKey(ownerKey)
            Dim safeOptions As MASFileExplorerFloatOptions =
                If(options, MASFileExplorerFloatOptions.CreateDefault()).Clone()

            safeOptions.UseDefaultComputerRoot = True

            Return MASFileExplorerFloatRequestBuilder.CreateRequest(
                rootHost:=_rootHost,
                ownerKey:=safeOwnerKey,
                options:=safeOptions,
                initialBoundsPx:=GetDefaultExplorerBoundsPx(),
                showPolicy:=MASFloatShowPolicy.CloseSameOwnerThenShow,
                shield:=MASFloatShieldOptions.None,
                onOpened:=onOpened,
                onClosed:=onClosed
            )

        End Function

#End Region


#Region "Show - options"

        Friend Function Show(options As MASFileExplorerFloatOptions,
                             Optional ownerKey As String = DefaultOwnerKey,
                             Optional onClosed As Action = Nothing,
                             Optional onAccepted As Action(Of MASFileExplorerFloatResult) = Nothing,
                             Optional onCancelled As Action = Nothing) As MASFloatHandle

            Return ToCompatibilityFloatHandle(
                ShowEx(
                    options:=options,
                    ownerKey:=ownerKey,
                    onClosed:=onClosed,
                    onAccepted:=onAccepted,
                    onCancelled:=onCancelled))

        End Function

        Friend Function ShowEx(options As MASFileExplorerFloatOptions,
                               Optional ownerKey As String = DefaultOwnerKey,
                               Optional onClosed As Action = Nothing,
                               Optional onAccepted As Action(Of MASFileExplorerFloatResult) = Nothing,
                               Optional onCancelled As Action = Nothing) As MASFloatShowResult

            Return ShowEx(
                ownerKey:=ownerKey,
                options:=options,
                onOpened:=Nothing,
                onClosed:=ToClosedCallback(onClosed),
                onAccepted:=onAccepted,
                onCancelled:=onCancelled
            )

        End Function

        Friend Function Show(ownerKey As String,
                             options As MASFileExplorerFloatOptions,
                             Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                             Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing,
                             Optional onAccepted As Action(Of MASFileExplorerFloatResult) = Nothing,
                             Optional onCancelled As Action = Nothing) As MASFloatHandle

            Return ToCompatibilityFloatHandle(
                ShowEx(
                    ownerKey:=ownerKey,
                    options:=options,
                    onOpened:=onOpened,
                    onClosed:=onClosed,
                    onAccepted:=onAccepted,
                    onCancelled:=onCancelled))

        End Function

        Friend Function ShowEx(ownerKey As String,
                               options As MASFileExplorerFloatOptions,
                               Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                               Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing,
                               Optional onAccepted As Action(Of MASFileExplorerFloatResult) = Nothing,
                               Optional onCancelled As Action = Nothing) As MASFloatShowResult

            Dim request As MASFloatRequest =
                CreateRequest(
                    ownerKey:=ownerKey,
                    options:=options,
                    onOpened:=onOpened,
                    onClosed:=ComposeExplorerClosedCallback(onClosed, onAccepted, onCancelled)
                )

            Return ShowRequestEx(request)

        End Function

        ''' <summary>
        ''' Internal path for creating a raw file-explorer float request. SDK code should call Show/ShowComputer instead.
        ''' </summary>
        Friend Function CreateRequest(ownerKey As String,
                                      options As MASFileExplorerFloatOptions,
                                      Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                                      Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatRequest

            Dim safeOwnerKey As String = NormalizeOwnerKey(ownerKey)
            Dim safeOptions As MASFileExplorerFloatOptions =
                If(options, MASFileExplorerFloatOptions.CreateDefault()).Clone()

            Return MASFileExplorerFloatRequestBuilder.CreateRequest(
                rootHost:=_rootHost,
                ownerKey:=safeOwnerKey,
                options:=safeOptions,
                initialBoundsPx:=ResolveInitialBoundsPx(safeOptions.BoundsPx),
                showPolicy:=MASFloatShowPolicy.CloseSameOwnerThenShow,
                shield:=MASFloatShieldOptions.None,
                onOpened:=onOpened,
                onClosed:=onClosed
            )

        End Function

#End Region


#Region "Show - existing explorer instance"

        Friend Function ShowExplorer(explorer As MASFileExplorerView,
                                     Optional ownerKey As String = DefaultOwnerKey,
                                     Optional onClosed As Action = Nothing) As MASFloatHandle

            Return ToCompatibilityFloatHandle(
                ShowExplorerEx(
                    explorer:=explorer,
                    ownerKey:=ownerKey,
                    onClosed:=onClosed))

        End Function

        Friend Function ShowExplorerEx(explorer As MASFileExplorerView,
                                       Optional ownerKey As String = DefaultOwnerKey,
                                       Optional onClosed As Action = Nothing) As MASFloatShowResult

            Return ShowExplorerEx(
                explorer:=explorer,
                ownerKey:=ownerKey,
                initialBoundsPx:=GetDefaultExplorerBoundsPx(),
                showPolicy:=MASFloatShowPolicy.CloseSameOwnerThenShow,
                onOpened:=Nothing,
                onClosed:=ToClosedCallback(onClosed)
            )

        End Function

        Friend Function ShowExplorer(explorer As MASFileExplorerView,
                                     ownerKey As String,
                                     initialBoundsPx As SKRect,
                                     Optional showPolicy As MASFloatShowPolicy = MASFloatShowPolicy.CloseSameOwnerThenShow,
                                     Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                                     Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatHandle

            Return ToCompatibilityFloatHandle(
                ShowExplorerEx(
                    explorer:=explorer,
                    ownerKey:=ownerKey,
                    initialBoundsPx:=initialBoundsPx,
                    showPolicy:=showPolicy,
                    onOpened:=onOpened,
                    onClosed:=onClosed))

        End Function

        Friend Function ShowExplorerEx(explorer As MASFileExplorerView,
                                       ownerKey As String,
                                       initialBoundsPx As SKRect,
                                       Optional showPolicy As MASFloatShowPolicy = MASFloatShowPolicy.CloseSameOwnerThenShow,
                                       Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                                       Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatShowResult

            Dim request As MASFloatRequest =
                CreateExplorerRequest(
                    explorer:=explorer,
                    ownerKey:=ownerKey,
                    initialBoundsPx:=initialBoundsPx,
                    showPolicy:=showPolicy,
                    onOpened:=onOpened,
                    onClosed:=onClosed
                )

            Return ShowRequestEx(request)

        End Function

        Friend Function ShowExplorerAt(explorer As MASFileExplorerView,
                                       explorerBoundsPx As SKRect,
                                       Optional ownerKey As String = DefaultOwnerKey,
                                       Optional onClosed As Action = Nothing) As MASFloatHandle

            Return ToCompatibilityFloatHandle(
                ShowExplorerAtEx(
                    explorer:=explorer,
                    explorerBoundsPx:=explorerBoundsPx,
                    ownerKey:=ownerKey,
                    onClosed:=onClosed))

        End Function

        Friend Function ShowExplorerAtEx(explorer As MASFileExplorerView,
                                         explorerBoundsPx As SKRect,
                                         Optional ownerKey As String = DefaultOwnerKey,
                                         Optional onClosed As Action = Nothing) As MASFloatShowResult

            Return ShowExplorerEx(
                explorer:=explorer,
                ownerKey:=ownerKey,
                initialBoundsPx:=explorerBoundsPx,
                showPolicy:=MASFloatShowPolicy.CloseSameOwnerThenShow,
                onOpened:=Nothing,
                onClosed:=ToClosedCallback(onClosed)
            )

        End Function

        ''' <summary>
        ''' Internal path for wrapping an existing explorer view in a float request.
        ''' </summary>
        Friend Function CreateExplorerRequest(explorer As MASFileExplorerView,
                                              Optional ownerKey As String = DefaultOwnerKey,
                                              Optional initialBoundsPx As SKRect = Nothing,
                                              Optional showPolicy As MASFloatShowPolicy = MASFloatShowPolicy.CloseSameOwnerThenShow,
                                              Optional onOpened As Action(Of MASFloatHandle) = Nothing,
                                              Optional onClosed As Action(Of MASFloatClosedEventArgs) = Nothing) As MASFloatRequest

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

            Dim safeOwnerKey As String = NormalizeOwnerKey(ownerKey)

            Dim content As New MASFloatControlsContent(
                name:="MASFileExplorerFloatContent",
                themeHost:=_rootHost.ThemeHostCore,
                invalidate:=AddressOf _rootHost.RequestInvalidate
            )

            content.Add(explorer)

            content.AcceptsPointerInput = True
            content.AcceptsKeyboardInput = True
            content.AcceptsTextInput = True
            content.CloseOnEscape = True
            content.CloseOnOutsidePointer = False
            content.SwallowOutsidePointer = True

            Dim openedHandle As MASFloatHandle = Nothing

            WireExplorerToFloat(
                explorer:=explorer,
                content:=content,
                ownerKey:=safeOwnerKey,
                getParentHandle:=Function()
                                     Return openedHandle
                                 End Function
            )

            Dim finalOnOpened As Action(Of MASFloatHandle) =
                Sub(handle As MASFloatHandle)
                    openedHandle = handle

                    If onOpened IsNot Nothing Then
                        onOpened.Invoke(handle)
                    End If
                End Sub

            Dim request As New MASFloatRequest() With {
                .FloatKey = MASFloatKeys.FileExplorer,
                .OwnerKey = safeOwnerKey,
                .Content = content,
                .ShowPolicy = showPolicy,
                .Shield = MASFloatShieldOptions.None,
                .InitialBoundsPx = ResolveInitialBoundsPx(initialBoundsPx),
                .OnOpened = finalOnOpened,
                .OnClosed = onClosed
            }

            Dim availableBoundsPx As SKRect = _rootHost.GetSurfaceViewportPx()
            If IsUsableRect(availableBoundsPx) Then
                request.AvailableBoundsPx = availableBoundsPx
            End If

            Return request

        End Function

#End Region


End Class

End Namespace
