// Copyright (c) 2022 Kiel University and others.
// Copyright (c) 2026 The elk-go Authors.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

package core

import (
	
	

	
	
)

var topdownMargins = graph.CloneablePropertyWithDefault("org.eclipse.elk.margins", func() geometry.Spacing {
	return geometry.Spacing{}
})

// layoutTopdown is the top-down branch of ELK 0.12's recursive graph layout
// engine. It sizes compound children before laying out their parent, then
// records the scale and coordinate compensation required by hierarchical
// nodes before recursion continues into those children.
func ( *Engine) (
	 *graph.Model,
	 graph.NodeID,
	 *AlgorithmData,
	 ProgressMonitor,
) error {
	 := .Node()
	,  := graph.TryGet(&.Properties, TopdownNodeType)
	if ! ||  == "" {
		return fmt.Errorf("%s has not been assigned a top-down node type.", nodePath(, ))
	}

	if  == "HIERARCHICAL_NODE" ||  == "ROOT_NODE" {
		for ,  := range .Children {
			 := .Node()
			if len(.Children) == 0 {
				continue
			}
			if graph.Has(&.Properties, TopdownSizeApproximator) {
				return fmt.Errorf("topdown size approximators cannot be constructed through LayoutJSON")
			}
			 := graph.Get(&.Properties, Padding)
			 := graph.Get(&.Properties, TopdownHierarchicalNodeWidth)
			 := graph.Get(&.Properties, TopdownHierarchicalNodeAspectRatio)
			.Shape.SetDimensions(
				math.Max(.Shape.Width, +.Horizontal()),
				math.Max(.Shape.Height, /+.Vertical()),
			)
		}
	}

	 := graph.Get(&.Properties, Padding)
	 := .Shape.Width - .Horizontal()
	 := .Shape.Height - .Vertical()
	graph.Set(&.Properties, AspectRatio, /)

	if  := .executeAlgorithm(, , , );  != nil {
		return 
	}

	if  == "ROOT_NODE" {
		computeChildAreaDimensions(, )
		 := graph.Get(&.Properties, ChildAreaWidth)
		 := graph.Get(&.Properties, ChildAreaHeight)
		.Shape.SetDimensions(.Left++.Right, .Top++.Bottom)
	}

	if  != "HIERARCHICAL_NODE" {
		return nil
	}
	if  < 0 ||  < 0 {
		return fmt.Errorf("The size defined by the parent parallel node is too small for the space provided by the paddings of the child hierarchical node. %s",
			nodePath(, ))
	}
	if !graph.Has(&.Properties, ChildAreaWidth) && !graph.Has(&.Properties, ChildAreaHeight) {
		computeChildAreaDimensions(, )
	}
	 := graph.Get(&.Properties, ChildAreaWidth)
	 := graph.Get(&.Properties, ChildAreaHeight)
	 :=  / 
	 :=  / 
	 := math.Min(, math.Min(, graph.Get(&.Properties, TopdownScaleCap)))
	graph.Set(&.Properties, TopdownScaleFactor, )

	var ,  float64
	 := graph.Get(&.Properties, ContentAlignment)
	if  <  {
		if containsOption(, "H_CENTER") {
			 = (/2 - */2) / 
		} else if containsOption(, "H_RIGHT") {
			 = ( - *) / 
		}
	}
	if  <  {
		if containsOption(, "V_CENTER") {
			 = (/2 - */2) / 
		} else if containsOption(, "V_BOTTOM") {
			 = ( - *) / 
		}
	}
	 := geometry.Point{
		X:  + .Left/ - .Left,
		Y:  + .Top/ - .Top,
	}
	translateTopdownContent(, , )
	return nil
}

func containsOption( []string,  string) bool {
	for ,  := range  {
		if  ==  {
			return true
		}
	}
	return false
}

func translateTopdownContent( *graph.Model,  graph.NodeID,  geometry.Point) {
	 := .Node()
	for ,  := range .Children {
		 := .Node()
		.Shape.SetLocation(.Shape.X+.X, .Shape.Y+.Y)
	}
	for ,  := range .ContainedEdges {
		 := .Edge()
		for ,  := range .Sections {
			TranslateSection(, , )
		}
		for ,  := range .Labels {
			 := .Label()
			.Shape.SetLocation(.Shape.X+.X, .Shape.Y+.Y)
		}
		if ,  := graph.TryGet(&.Properties, JunctionPoints);  {
			.Offset()
			graph.Set(&.Properties, JunctionPoints, )
		}
	}
}

func computeChildAreaDimensions( *graph.Model,  graph.NodeID) {
	,  := math.Inf(1), math.Inf(1)
	,  := 0.0, 0.0
	 := func( *graph.Shape,  *graph.PropertyMap) {
		 := graph.Get(, topdownMargins)
		 = math.Min(, .X-.Left)
		 = math.Min(, .Y-.Top)
		 = math.Max(, .X+.Width+.Right)
		 = math.Max(, .Y+.Height+.Bottom)
	}
	 := .Node()
	for ,  := range .Labels {
		 := .Label()
		(&.Shape, &.Properties)
	}
	for ,  := range .Children {
		 := .Node()
		(&.Shape, &.Properties)
	}
	for ,  := range .ContainedEdges {
		 := .Edge()
		for ,  := range .Labels {
			 := .Label()
			(&.Shape, &.Properties)
		}
		for ,  := range .Sections {
			 := .Section()
			 = math.Min(, math.Min(.Start.X, .End.X))
			 = math.Min(, math.Min(.Start.Y, .End.Y))
			 = math.Max(, math.Max(.Start.X, .End.X))
			 = math.Max(, math.Max(.Start.Y, .End.Y))
			for ,  := range .BendPoints {
				 = math.Min(, .X)
				 = math.Min(, .Y)
				 = math.Max(, .X)
				 = math.Max(, .Y)
			}
		}
	}
	graph.Set(&.Properties, ChildAreaWidth, -)
	graph.Set(&.Properties, ChildAreaHeight, -)
}