Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Layout

Namespace Nexamas.UI.Application

    Partial Public NotInheritable Class MASApplicationWindowControls
        Private _hasLastLayoutRefreshFailure As Boolean
        Private _lastLayoutRefreshFailureScope As String = String.Empty
        Private _lastLayoutRefreshFailureReason As String = String.Empty
        Private _lastLayoutRefreshFailureStage As String = String.Empty
        Private _lastLayoutRefreshFailureCode As String = String.Empty
        Private _lastLayoutRefreshFailureMessage As String = String.Empty
        Private _lastLayoutRefreshFailureDetail As String = String.Empty
        Private _lastLayoutRefreshFailureExceptionType As String = String.Empty
        Private _lastLayoutRefreshFailureUtc As DateTime = DateTime.MinValue

        ''' <summary>
        ''' Raised after a retained Application layout refresh fails without throwing to the host resize/theme path.
        ''' Read the LastLayoutRefreshFailure* properties for the developer-visible failure snapshot.
        ''' </summary>
        Public Event LayoutRefreshFailed As EventHandler

        ''' <summary>
        ''' Indicates whether the retained Application layout facade has a recorded refresh failure snapshot.
        ''' A later successful retained layout pass clears this flag.
        ''' </summary>
        Public ReadOnly Property HasLastLayoutRefreshFailure As Boolean
            Get
                ThrowIfDisposed()
                Return _hasLastLayoutRefreshFailure
            End Get
        End Property

        ''' <summary>
        ''' Official retained-layout surface that last failed, such as LayoutPage or LayoutApplicationSurface.
        ''' </summary>
        Public ReadOnly Property LastLayoutRefreshFailureScope As String
            Get
                ThrowIfDisposed()
                Return _lastLayoutRefreshFailureScope
            End Get
        End Property

        ''' <summary>
        ''' Runtime reason that triggered the last retained-layout refresh failure.
        ''' </summary>
        Public ReadOnly Property LastLayoutRefreshFailureReason As String
            Get
                ThrowIfDisposed()
                Return _lastLayoutRefreshFailureReason
            End Get
        End Property

        ''' <summary>
        ''' Internal refresh stage that produced the last retained-layout failure, without exposing layout engine objects.
        ''' </summary>
        Public ReadOnly Property LastLayoutRefreshFailureStage As String
            Get
                ThrowIfDisposed()
                Return _lastLayoutRefreshFailureStage
            End Get
        End Property

        ''' <summary>
        ''' Diagnostic code for the last retained-layout refresh failure.
        ''' </summary>
        Public ReadOnly Property LastLayoutRefreshFailureCode As String
            Get
                ThrowIfDisposed()
                Return _lastLayoutRefreshFailureCode
            End Get
        End Property

        ''' <summary>
        ''' Developer-facing message for the last retained-layout refresh failure.
        ''' </summary>
        Public ReadOnly Property LastLayoutRefreshFailureMessage As String
            Get
                ThrowIfDisposed()
                Return _lastLayoutRefreshFailureMessage
            End Get
        End Property

        ''' <summary>
        ''' Additional detail for the last retained-layout refresh failure.
        ''' </summary>
        Public ReadOnly Property LastLayoutRefreshFailureDetail As String
            Get
                ThrowIfDisposed()
                Return _lastLayoutRefreshFailureDetail
            End Get
        End Property

        ''' <summary>
        ''' Exception type for the last retained-layout refresh failure, or an empty string for non-exception diagnostics.
        ''' </summary>
        Public ReadOnly Property LastLayoutRefreshFailureExceptionType As String
            Get
                ThrowIfDisposed()
                Return _lastLayoutRefreshFailureExceptionType
            End Get
        End Property

        ''' <summary>
        ''' UTC time when the last retained-layout refresh failure snapshot was recorded.
        ''' </summary>
        Public ReadOnly Property LastLayoutRefreshFailureUtc As DateTime
            Get
                ThrowIfDisposed()
                Return _lastLayoutRefreshFailureUtc
            End Get
        End Property

        Friend Sub ClearLayoutRefreshFailureInternal(scope As String)
            _hasLastLayoutRefreshFailure = False
            _lastLayoutRefreshFailureScope = If(scope, String.Empty)
            _lastLayoutRefreshFailureReason = String.Empty
            _lastLayoutRefreshFailureStage = String.Empty
            _lastLayoutRefreshFailureCode = String.Empty
            _lastLayoutRefreshFailureMessage = String.Empty
            _lastLayoutRefreshFailureDetail = String.Empty
            _lastLayoutRefreshFailureExceptionType = String.Empty
            _lastLayoutRefreshFailureUtc = DateTime.MinValue
        End Sub

        Friend Sub RecordLayoutRefreshDiagnosticsFailureInternal(scope As String,
                                                                refreshReason As String,
                                                                stage As String,
                                                                diagnostics As MASSizeLayoutDiagnosticBag)
            Dim code As String = "MASLayout.ApplicationRefreshDiagnosticFailure"
            Dim message As String = "The retained Application layout refresh failed with diagnostics."
            Dim detail As String = String.Empty

            If diagnostics IsNot Nothing Then
                For Each item As MASSizeLayoutDiagnostic In diagnostics.Items
                    If item Is Nothing Then Continue For
                    If item.Severity <> MASSizeLayoutDiagnosticSeverity.Error Then Continue For

                    code = item.Code
                    message = item.Message
                    detail = item.Detail
                    Exit For
                Next
            End If

            RecordLayoutRefreshFailureInternal(scope, refreshReason, stage, code, message, detail, String.Empty)
        End Sub

        Friend Sub RecordLayoutRefreshExceptionFailureInternal(scope As String,
                                                              refreshReason As String,
                                                              stage As String,
                                                              exception As Exception)
            Dim exceptionType As String = String.Empty
            Dim message As String = "The retained Application layout refresh failed with an exception."
            Dim detail As String = String.Empty

            If exception IsNot Nothing Then
                exceptionType = exception.GetType().FullName
                message = exception.Message
                detail = "ExceptionType=" & exceptionType
            End If

            RecordLayoutRefreshFailureInternal(
                scope,
                refreshReason,
                stage,
                "MASLayout.ApplicationRefreshException",
                message,
                detail,
                exceptionType)
        End Sub

        Private Sub RecordLayoutRefreshFailureInternal(scope As String,
                                                       refreshReason As String,
                                                       stage As String,
                                                       code As String,
                                                       message As String,
                                                       detail As String,
                                                       exceptionType As String)
            _hasLastLayoutRefreshFailure = True
            _lastLayoutRefreshFailureScope = If(scope, String.Empty)
            _lastLayoutRefreshFailureReason = If(refreshReason, String.Empty)
            _lastLayoutRefreshFailureStage = If(stage, String.Empty)
            _lastLayoutRefreshFailureCode = If(code, String.Empty)
            _lastLayoutRefreshFailureMessage = If(message, String.Empty)
            _lastLayoutRefreshFailureDetail = If(detail, String.Empty)
            _lastLayoutRefreshFailureExceptionType = If(exceptionType, String.Empty)
            _lastLayoutRefreshFailureUtc = DateTime.UtcNow

            Try
                RaiseEvent LayoutRefreshFailed(Me, EventArgs.Empty)
            Catch masCaughtLayoutRefreshFailedHandlerException As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowBoundary(
                    masCaughtLayoutRefreshFailedHandlerException,
                    "MASApplicationWindow.Controls.LayoutRefreshFailed")
            End Try
        End Sub
    End Class

End Namespace
