Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Host
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Components
Imports SkiaSharp

Namespace Nexamas.UI.Application

    Partial Public NotInheritable Class MASApplicationSurfaceLayoutBuilder
        Private Function IsCommandBackgroundVisible() As Boolean
            Return _showCommandBackground AndAlso _commandBarPage IsNot Nothing
        End Function

        Private Function IsRegionBackgroundVisible() As Boolean
            Return _showRegionBackgrounds
        End Function

        Private Function ResolveApplicationSurfaceContentViewport(viewportLogical As SKRect) As SKRect
            If viewportLogical.IsEmpty OrElse viewportLogical.Width <= 1.0F OrElse viewportLogical.Height <= 1.0F Then Return viewportLogical

            Dim topInset As Single = ResolveReservedApplicationChromeInset()
            If topInset <= 0.0F Then Return viewportLogical

            Dim safeTop As Single = Math.Min(viewportLogical.Bottom, viewportLogical.Top + topInset)
            Return New SKRect(viewportLogical.Left, safeTop, viewportLogical.Right, viewportLogical.Bottom)
        End Function

        Private Function ResolveReservedApplicationChromeInset() As Single
            If _standardChromeShell Is Nothing Then Return 0.0F

            Try
                Return SafeNonNegative(_standardChromeShell.StandardContentTopLogical)
            Catch masCaughtException As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowBoundary(masCaughtException, "Application.Controls.LayoutApplicationSurface.ResolveStandardApplicationChrome")
                Return 0.0F
            End Try
        End Function

        Private Function ResolveCommandBackgroundVisualStyle() As MASCardVisualStyle
            Return _backgroundRegistry.CommandBackgroundVisualStyle
        End Function

        Private Function ResolveRegionBackgroundVisualStyle() As MASCardVisualStyle
            Return _backgroundRegistry.RegionBackgroundVisualStyle
        End Function

        Private Sub AddApplicationSurfaceRegionBackground(entries As IList(Of MASApplicationSurfaceBackgroundEntry),
                                                          bounds As SKRect)
            If Not IsRegionBackgroundVisible() Then Return
            AddBackground(entries, bounds, ResolveRegionBackgroundVisualStyle(), _regionBackgroundSurfaceMaterialKey)
        End Sub

        Private Sub AddSurfaceRegion(entries As IList(Of MASApplicationLayoutRegionEntry),
                                     backgroundEntries As IList(Of MASApplicationSurfaceBackgroundEntry),
                                     bounds As SKRect,
                                     page As MASApplicationLayoutPageBuilder,
                                     profile As MASSizeProfile)
            If bounds.IsEmpty OrElse bounds.Width <= 0.0F OrElse bounds.Height <= 0.0F Then Return
            AddApplicationSurfaceRegionBackground(backgroundEntries, bounds)
            AddRegion(entries, ResolveRegionContentBounds(bounds, profile), page)
        End Sub

        Private Function ResolveCommandRegionContentBounds(commandBounds As SKRect,
                                                           profile As MASSizeProfile,
                                                           commandPage As MASApplicationLayoutPageBuilder) As SKRect
            Dim inset As MASLayoutInset = MASLayoutSpacingResolver.ScaleInset(_commandBackgroundPadding, profile)
            Dim contentBounds As SKRect = MASLayoutInset.ApplyInside(commandBounds, inset)

            If contentBounds.IsEmpty OrElse contentBounds.Width <= 1.0F OrElse contentBounds.Height <= 1.0F Then
                Return commandBounds
            End If

            Dim desiredContentHeight As Single = MeasureCommandPageDesiredHeight(commandPage, contentBounds, profile)
            If desiredContentHeight <= 0.0F OrElse desiredContentHeight >= contentBounds.Height Then
                Return contentBounds
            End If

            Dim centeredTop As Single = contentBounds.Top + ((contentBounds.Height - desiredContentHeight) / 2.0F)
            Return New SKRect(contentBounds.Left, centeredTop, contentBounds.Right, centeredTop + desiredContentHeight)
        End Function

        Private Shared Function MeasureCommandPageDesiredHeight(commandPage As MASApplicationLayoutPageBuilder,
                                                                contentBounds As SKRect,
                                                                profile As MASSizeProfile) As Single
            If commandPage Is Nothing Then Return 0.0F
            If contentBounds.IsEmpty OrElse contentBounds.Width <= 1.0F OrElse contentBounds.Height <= 1.0F Then Return 0.0F

            Dim node As MASLayoutNode = commandPage.BuildNode(profile)
            If node Is Nothing Then Return 0.0F

            Dim safeProfile As MASSizeProfile = MASSizeProfile.Normalize(profile)
            Dim integration As MASSizeLayoutIntegrationContext = MASSizeLayoutIntegrationGateway.Create(Nothing, safeProfile, 1.0F)
            Dim context As New MASLayoutContext(contentBounds, integration)
            Dim engine As New MASLayoutEngine()
            Dim measured As SKSize = engine.Measure(node, context)
            Dim measuredHeight As Single = measured.Height

            If Single.IsNaN(measuredHeight) OrElse Single.IsInfinity(measuredHeight) OrElse measuredHeight <= 0.0F Then
                Return 0.0F
            End If

            Return Math.Min(measuredHeight, contentBounds.Height)
        End Function

        Private Function ResolveRegionContentBounds(regionBounds As SKRect,
                                                    profile As MASSizeProfile) As SKRect
            If Not IsRegionBackgroundVisible() Then Return regionBounds
            Dim inset As MASLayoutInset = MASLayoutSpacingResolver.ScaleInset(_regionBackgroundPadding, profile)
            Dim contentBounds As SKRect = MASLayoutInset.ApplyInside(regionBounds, inset)

            If contentBounds.IsEmpty OrElse contentBounds.Width <= 1.0F OrElse contentBounds.Height <= 1.0F Then
                Return regionBounds
            End If

            Return contentBounds
        End Function

        Private Shared Sub AddBackground(entries As IList(Of MASApplicationSurfaceBackgroundEntry),
                                         bounds As SKRect,
                                         visualStyle As MASCardVisualStyle,
                                         Optional surfaceMaterialKey As String = Nothing)
            If entries Is Nothing Then Return
            If bounds.IsEmpty OrElse bounds.Width <= 0.0F OrElse bounds.Height <= 0.0F Then Return
            entries.Add(New MASApplicationSurfaceBackgroundEntry(bounds, visualStyle, surfaceMaterialKey))
        End Sub

        Private Shared Sub AddRegion(entries As IList(Of MASApplicationLayoutRegionEntry),
                                     bounds As SKRect,
                                     page As MASApplicationLayoutPageBuilder)
            If entries Is Nothing OrElse page Is Nothing Then Return
            If bounds.IsEmpty OrElse bounds.Width <= 0.0F OrElse bounds.Height <= 0.0F Then Return
            entries.Add(New MASApplicationLayoutRegionEntry(bounds, page))
        End Sub
    End Class

End Namespace
