Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Windows.Forms
Imports Nexamas.UI.Host
Imports Nexamas.UI.Layout

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Official presentation facade for one MAS application window.
    ''' It owns Form size, placement, window state, and durable user preference restore/save.
    ''' It deliberately does not arrange child controls; child layout remains owned by MASSize/MASLayout/MASScreen.
    ''' </summary>
    Public NotInheritable Class MASApplicationWindowPresentation
        Implements IDisposable

        Private ReadOnly _owner As Form
        Private ReadOnly _rootHost As MASSkiaRootHost
        Private _currentProfile As MASWindowPresentationProfile = MASWindowPresentationProfile.Standard
        Private _currentOptions As MASWindowPresentationOptions
        Private _disposed As Boolean
        Private _eventsAttached As Boolean

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

        Friend ReadOnly Property CurrentProfile As MASWindowPresentationProfile
            Get
                Return MASWindowPresentationProfile.Normalize(_currentProfile)
            End Get
        End Property

        Public ReadOnly Property CurrentProfileKind As MASWindowPresentationProfileKind
            Get
                Return CurrentProfile.Kind
            End Get
        End Property

        Public Function GetAllProfileKinds() As IReadOnlyList(Of MASWindowPresentationProfileKind)
            Return Array.AsReadOnly(New MASWindowPresentationProfileKind() {
                MASWindowPresentationProfileKind.Utility,
                MASWindowPresentationProfileKind.Compact,
                MASWindowPresentationProfileKind.Standard,
                MASWindowPresentationProfileKind.Spacious,
                MASWindowPresentationProfileKind.Productive,
                MASWindowPresentationProfileKind.Immersive
            })
        End Function

        Friend Function GetAllProfiles() As IReadOnlyList(Of MASWindowPresentationProfile)
            Return Array.AsReadOnly(New MASWindowPresentationProfile() {
                MASWindowPresentationProfile.Utility,
                MASWindowPresentationProfile.Compact,
                MASWindowPresentationProfile.Standard,
                MASWindowPresentationProfile.Spacious,
                MASWindowPresentationProfile.Productive,
                MASWindowPresentationProfile.Immersive
            })
        End Function


        ''' <summary>
        ''' Applies a small utility presentation for lightweight support windows without durable user restore.
        ''' </summary>
        Public Function UseUtility() As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(MASWindowPresentationProfileKind.Utility), MASWindowPresentationOptions.OneShot())
        End Function

        ''' <summary>
        ''' Applies a standard balanced application-window presentation without durable user restore.
        ''' </summary>
        Public Function UseStandard() As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(MASWindowPresentationProfileKind.Standard), MASWindowPresentationOptions.OneShot())
        End Function

        ''' <summary>
        ''' Applies a compact application-window presentation without durable user restore.
        ''' </summary>
        Public Function UseCompact() As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(MASWindowPresentationProfileKind.Compact), MASWindowPresentationOptions.OneShot())
        End Function

        ''' <summary>
        ''' Applies a spacious application-window presentation without durable user restore.
        ''' </summary>
        Public Function UseSpacious() As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(MASWindowPresentationProfileKind.Spacious), MASWindowPresentationOptions.OneShot())
        End Function

        ''' <summary>
        ''' Applies a productive application-window presentation without durable user restore.
        ''' </summary>
        Public Function UseProductive() As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(MASWindowPresentationProfileKind.Productive), MASWindowPresentationOptions.OneShot())
        End Function

        ''' <summary>
        ''' Applies a larger immersive application-window presentation without durable user restore.
        ''' </summary>
        Public Function UseImmersive() As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(MASWindowPresentationProfileKind.Immersive), MASWindowPresentationOptions.OneShot())
        End Function

        ''' <summary>
        ''' Applies a profile and enables safe durable user restore/save for this logical window key.
        ''' </summary>
        Public Function UseUserPreferences(persistenceKey As String,
                                           Optional profileKind As MASWindowPresentationProfileKind = MASWindowPresentationProfileKind.Standard) As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(profileKind), MASWindowPresentationOptions.UserPreferences(persistenceKey))
        End Function

        Public Function Apply(profileKind As MASWindowPresentationProfileKind) As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(profileKind), MASWindowPresentationOptions.OneShot())
        End Function

        Public Function Apply(profileKind As MASWindowPresentationProfileKind,
                              startupPlacement As MASWindowStartupPlacement) As MASApplicationWindowPresentation
            Return ApplyCore(MASWindowPresentationProfile.FromKind(profileKind), MASWindowPresentationOptions.OneShot(startupPlacement))
        End Function

        Friend Function ApplyCore(profile As MASWindowPresentationProfile,
                                  Optional options As MASWindowPresentationOptions = Nothing) As MASApplicationWindowPresentation
            ThrowIfDisposed()

            Dim safeProfile As MASWindowPresentationProfile = MASWindowPresentationProfile.Normalize(profile)
            Dim safeOptions As MASWindowPresentationOptions = MASWindowPresentationOptions.Normalize(options, safeProfile)
            Dim storedState As MASWindowPresentationState = Nothing

            If safeOptions.RestoreUserChoice AndAlso Not String.IsNullOrWhiteSpace(safeOptions.PersistenceKey) Then
                storedState = MASWindowPresentationStore.Load(safeOptions.PersistenceKey)
                If safeOptions.RestoreProfileChoice AndAlso storedState IsNot Nothing Then
                    safeProfile = MASWindowPresentationProfile.FromKind(storedState.ProfileKind)
                    safeOptions = MASWindowPresentationOptions.Normalize(safeOptions, safeProfile)
                End If
            End If

            Dim plan As MASWindowPresentationState = MASWindowPresentationPlanner.Plan(_owner, safeProfile, safeOptions, storedState)
            ApplyPlan(plan)

            _currentProfile = safeProfile
            _currentOptions = safeOptions

            If safeOptions.SaveUserChoice AndAlso Not String.IsNullOrWhiteSpace(safeOptions.PersistenceKey) Then
                AttachEvents()
            Else
                DetachEvents()
            End If

            If safeOptions.ApplySizeProfile Then
                MASRuntimeSizeProfileService.TryUse(safeOptions.SizeProfileKind)
            End If

            RefreshLayout()
            Return Me
        End Function

        Public Function ApplyAndSave(profileKind As MASWindowPresentationProfileKind,
                                     persistenceKey As String) As MASApplicationWindowPresentation
            Dim options As MASWindowPresentationOptions = MASWindowPresentationOptions.UserPreferences(persistenceKey)
            options.RestoreProfileChoice = False
            ApplyCore(MASWindowPresentationProfile.FromKind(profileKind), options)
            SaveCurrent(persistenceKey)
            Return Me
        End Function

        ''' <summary>
        ''' Saves the current presentation state for the active persistence key, if one is configured.
        ''' </summary>
        Public Function SaveCurrent() As Boolean
            ThrowIfDisposed()
            If _currentOptions Is Nothing OrElse String.IsNullOrWhiteSpace(_currentOptions.PersistenceKey) Then Return False
            Return SaveCurrent(_currentOptions.PersistenceKey)
        End Function

        ''' <summary>
        ''' Saves the current presentation state for an explicit logical window key.
        ''' </summary>
        Public Function SaveCurrent(persistenceKey As String) As Boolean
            ThrowIfDisposed()
            If String.IsNullOrWhiteSpace(persistenceKey) Then Return False

            Dim state As MASWindowPresentationState = MASWindowPresentationPlanner.Capture(_owner, CurrentProfile)
            Return MASWindowPresentationStore.Save(persistenceKey, state)
        End Function

        Private Sub ApplyPlan(plan As MASWindowPresentationState)
            If plan Is Nothing Then Return

            Dim oldState As FormWindowState = _owner.WindowState
            If oldState <> FormWindowState.Normal Then _owner.WindowState = FormWindowState.Normal

            If plan.Bounds.Width > 0 AndAlso plan.Bounds.Height > 0 Then
                _owner.StartPosition = FormStartPosition.Manual
                _owner.Bounds = plan.Bounds
                _owner.MinimumSize = New System.Drawing.Size(MASWindowPresentationSizeTokens.MinimumVisibleWidth, MASWindowPresentationSizeTokens.MinimumVisibleHeight)
            End If

            If plan.WindowState = FormWindowState.Maximized Then
                _owner.WindowState = FormWindowState.Maximized
            ElseIf oldState <> FormWindowState.Minimized Then
                _owner.WindowState = FormWindowState.Normal
            End If
        End Sub

        Private Sub AttachEvents()
            If _eventsAttached Then Return
            AddHandler _owner.FormClosing, AddressOf OwnerForm_FormClosing
            AddHandler _owner.ResizeEnd, AddressOf OwnerForm_ResizeEnd
            AddHandler _owner.Disposed, AddressOf OwnerForm_Disposed
            _eventsAttached = True
        End Sub

        Private Sub DetachEvents()
            If Not _eventsAttached Then Return
            RemoveHandler _owner.FormClosing, AddressOf OwnerForm_FormClosing
            RemoveHandler _owner.ResizeEnd, AddressOf OwnerForm_ResizeEnd
            RemoveHandler _owner.Disposed, AddressOf OwnerForm_Disposed
            _eventsAttached = False
        End Sub

        Private Sub OwnerForm_FormClosing(sender As Object, e As FormClosingEventArgs)
            SaveCurrent()
        End Sub

        Private Sub OwnerForm_ResizeEnd(sender As Object, e As EventArgs)
            SaveCurrent()
        End Sub

        Private Sub OwnerForm_Disposed(sender As Object, e As EventArgs)
            Dispose()
        End Sub

        Private Sub RefreshLayout()
            If _rootHost Is Nothing OrElse _rootHost.IsDisposed Then Return
            _rootHost.RefreshSizeLayoutForRuntimeProfile()
            _rootHost.RequestInvalidate()
        End Sub

        Private Sub ThrowIfDisposed()
            If _disposed Then Throw New ObjectDisposedException(NameOf(MASApplicationWindowPresentation))
        End Sub

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

    End Class

End Namespace
