Option Strict On
Option Explicit On

Imports System.Collections.Generic
Imports Nexamas.UI.Layout
Imports SkiaSharp

Namespace Nexamas.UI.Composition

    ''' <summary>
    ''' Phase 1 vertical layout node.
    ''' Measure calculates stacked desired size. Arrange produces final placements only.
    ''' </summary>
    <Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Advanced)>
    Friend NotInheritable Class MASVerticalLayoutNode
        Inherits MASLayoutNodeBase

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

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

            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
            Dim visibleCount As Integer = 0

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

                Dim size As SKSize = ChildPreferredSize(item, contentAvailable, context)
                width = Math.Max(width, size.Width + item.Margin.Horizontal)
                height += size.Height + item.Margin.Vertical
                visibleCount += 1
            Next

            If visibleCount > 1 Then height += Spacing * CSng(visibleCount - 1)

            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 content As SKRect = ResolveContentRect(context.BoundsLogical, Padding)
            If content.IsEmpty Then Return result

            Dim visible As List(Of MASLayoutItem) = CollectVisibleItems(Items)

            If visible.Count = 0 Then Return result

            Dim availableForMeasure As New SKSize(content.Width, content.Height)
            Dim measureContext As New MASLayoutMeasureContext(availableForMeasure, context.IntegrationContext, context.Diagnostics)
            Dim axisPlans As List(Of MASLayoutAxisAllocation(Of MASLayoutItem)) =
                BuildStackAxisAllocations(visible, availableForMeasure, measureContext, verticalPrimaryAxis:=True, availablePrimary:=content.Height)

            Dim allocations As Global.System.Collections.ObjectModel.ReadOnlyCollection(Of MASLayoutAxisAllocation(Of MASLayoutItem)) =
                MASLayoutAxisAllocator.Allocate(axisPlans, content.Height, Spacing)

            Dim y As Single = content.Top

            For Each allocation As MASLayoutAxisAllocation(Of MASLayoutItem) In allocations
                Dim item As MASLayoutItem = allocation.Item
                y += allocation.MarginBefore

                Dim h As Single = Math.Max(0.0F, Math.Min(allocation.AssignedPrimary, Math.Max(0.0F, content.Bottom - y - allocation.MarginAfter)))
                Dim desired As SKSize = ChildPreferredSize(item, availableForMeasure, measureContext)
                Dim availableW As Single = Math.Max(0.0F, content.Width - item.Margin.Horizontal)
                Dim alignment As MASLayoutAlignment = EffectiveAlignment(item)
                Dim shouldStretchWidth As Boolean = ShouldFillCrossAxis(
                    item.WidthPolicy,
                    alignment,
                    ChildCanGrowWidth(item, availableForMeasure, measureContext))

                Dim w As Single = ResolveCrossAxisLength(item.WidthPolicy, desired.Width, availableW, shouldStretchWidth)

                Dim childBounds As SKRect = ResolveCompositionStackCrossBounds(
                    crossStart:=content.Left + item.Margin.Left,
                    primaryStart:=y,
                    crossAvailable:=availableW,
                    primaryLength:=h,
                    desiredCrossLength:=w,
                    alignment:=alignment,
                    fillCrossAxis:=shouldStretchWidth,
                    verticalPrimaryAxis:=True)

                ArrangeChild(item, childBounds, context, result)

                y += h + allocation.MarginAfter + Spacing
            Next

            Return result
        End Function

    End Class

End Namespace
