Option Strict On
Option Explicit On

Imports System.Collections.Generic
Imports SkiaSharp

Namespace Nexamas.UI.Composition

    ''' <summary>
    ''' Phase 1 dock layout node.
    ''' Consumes Top/Bottom/Left/Right/Center item slots and produces placements only.
    ''' </summary>
    <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
    Friend NotInheritable Class MASDockLayoutNode
        Inherits MASLayoutNodeBase

        Friend Sub New(children As IEnumerable(Of MASLayoutItem),
                       Optional padding As MASLayoutThickness = Nothing)
            MyBase.New(children, 0.0F, padding, MASLayoutAlignment.Stretch)
        End Sub

        Public Overrides Function Measure(context As MASLayoutMeasureContext) As SKSize
            If context Is Nothing Then context = New MASLayoutMeasureContext(SKSize.Empty)
            ValidateCommon(context, "MASDockLayoutNode")

            Dim contentAvailable As New SKSize(
                Math.Max(0.0F, FiniteOrZero(context.AvailableSize.Width) - Padding.Horizontal),
                Math.Max(0.0F, FiniteOrZero(context.AvailableSize.Height) - Padding.Vertical))

            Dim width As Single = 0.0F
            Dim height As Single = 0.0F

            For Each item As MASLayoutItem In Items
                If item Is Nothing OrElse Not item.IsVisibleForLayout Then Continue For

                Dim size As SKSize = ChildPreferredSize(item, contentAvailable, context)

                Select Case item.Dock
                    Case MASLayoutDock.Top, MASLayoutDock.Bottom
                        width = Math.Max(width, size.Width + item.Margin.Horizontal)
                        height += size.Height + item.Margin.Vertical
                    Case MASLayoutDock.Left, MASLayoutDock.Right
                        width += size.Width + item.Margin.Horizontal
                        height = Math.Max(height, size.Height + item.Margin.Vertical)
                    Case Else
                        width = Math.Max(width, size.Width + item.Margin.Horizontal)
                        height = Math.Max(height, size.Height + item.Margin.Vertical)
                End Select
            Next

            Return New SKSize(width + Padding.Horizontal, height + Padding.Vertical)
        End Function

        Public Overrides Function Arrange(context As MASLayoutArrangeContext) As MASLayoutArrangeResult
            Dim result As New MASLayoutArrangeResult()
            If context Is Nothing OrElse context.BoundsLogical.IsEmpty Then Return result

            Dim remaining As New SKRect(
                context.BoundsLogical.Left + SafeLeft(Padding),
                context.BoundsLogical.Top + SafeTop(Padding),
                context.BoundsLogical.Right - SafeRight(Padding),
                context.BoundsLogical.Bottom - SafeBottom(Padding))

            If remaining.Width <= 0.0F OrElse remaining.Height <= 0.0F Then Return result

            Dim centers As New List(Of MASLayoutItem)()

            For Each item As MASLayoutItem In Items
                If item Is Nothing OrElse Not item.IsVisibleForLayout Then Continue For

                If item.Dock = MASLayoutDock.Center Then
                    centers.Add(item)
                    Continue For
                End If

                Dim desired As SKSize = ChildPreferredSize(item, New SKSize(remaining.Width, remaining.Height), New MASLayoutMeasureContext(New SKSize(remaining.Width, remaining.Height), context.IntegrationContext, context.Diagnostics))
                Dim bounds As SKRect = SKRect.Empty

                Select Case item.Dock
                    Case MASLayoutDock.Top
                        Dim h As Single = ResolveLayoutLength(item.HeightPolicy, desired.Height, remaining.Height)
                        bounds = New SKRect(remaining.Left + item.Margin.Left, remaining.Top + item.Margin.Top, remaining.Right - item.Margin.Right, remaining.Top + item.Margin.Top + h)
                        remaining.Top = Math.Min(remaining.Bottom, remaining.Top + h + item.Margin.Vertical)

                    Case MASLayoutDock.Bottom
                        Dim h As Single = ResolveLayoutLength(item.HeightPolicy, desired.Height, remaining.Height)
                        bounds = New SKRect(remaining.Left + item.Margin.Left, remaining.Bottom - item.Margin.Bottom - h, remaining.Right - item.Margin.Right, remaining.Bottom - item.Margin.Bottom)
                        remaining.Bottom = Math.Max(remaining.Top, remaining.Bottom - h - item.Margin.Vertical)

                    Case MASLayoutDock.Left
                        Dim w As Single = ResolveLayoutLength(item.WidthPolicy, desired.Width, remaining.Width)
                        bounds = New SKRect(remaining.Left + item.Margin.Left, remaining.Top + item.Margin.Top, remaining.Left + item.Margin.Left + w, remaining.Bottom - item.Margin.Bottom)
                        remaining.Left = Math.Min(remaining.Right, remaining.Left + w + item.Margin.Horizontal)

                    Case MASLayoutDock.Right
                        Dim w As Single = ResolveLayoutLength(item.WidthPolicy, desired.Width, remaining.Width)
                        bounds = New SKRect(remaining.Right - item.Margin.Right - w, remaining.Top + item.Margin.Top, remaining.Right - item.Margin.Right, remaining.Bottom - item.Margin.Bottom)
                        remaining.Right = Math.Max(remaining.Left, remaining.Right - w - item.Margin.Horizontal)
                End Select

                ArrangeChild(item, bounds, context, result)
            Next

            For Each item As MASLayoutItem In centers
                Dim bounds As New SKRect(
                    remaining.Left + item.Margin.Left,
                    remaining.Top + item.Margin.Top,
                    remaining.Right - item.Margin.Right,
                    remaining.Bottom - item.Margin.Bottom)

                ArrangeChild(item, bounds, context, result)
            Next

            Return result
        End Function

    End Class

End Namespace
