package packing

import (
	
	

	

	
	
	
	
)

func newWorkGuard( context.Context,  int64) (*limits.WorkGuard, error) {
	,  := limits.NewWorkGuard(, "BinPack", limits.MaxEngineWorkUnits)
	if  != nil {
		return nil, 
	}
	.SetLimit()
	return , nil
}

func binPackScoreGuarded( layoutgraph.Nodes,  *layoutgraph.Node,  *limits.WorkGuard) (float64, error) {
	, ,  := graphbounds.FixedBoundingBox(, )
	if  != nil {
		return 0, 
	}
	 := .X - .X
	 := .Y - .Y
	 := 0.
	if  != nil {
		if .DesiredWidth != nil && .DesiredHeight == nil &&  < *.DesiredWidth {
			 = *.DesiredWidth - 
		} else if .DesiredWidth == nil && .DesiredHeight != nil &&  < *.DesiredHeight {
			 = *.DesiredHeight - 
		}
	}
	 := * + math.Pow(-, 2.0)*subgraphSquareDampener +
		math.Pow(, 2.0)*subgraphSquareDampener
	return , .Finish()
}

func binPackContainerTopLeft( *layoutgraph.Graph,  *layoutgraph.Node,  layoutgraph.Nodes,  *limits.WorkGuard) (*geo.Point, error) {
	, ,  := graphbounds.FixedBoundingBox(, )
	if  != nil {
		return nil, 
	}
	if  == nil {
		return , .Finish()
	}
	 := .ContainerPadding(, false)
	 := .InsidePlacement(.X-.X, .Y-.Y, )
	return &, .Finish()
}

func binPackIsDescendantOf(,  *layoutgraph.Node,  *limits.WorkGuard) (bool, error) {
	 := make(map[*layoutgraph.Node]struct{})
	for {
		if  := .Step();  != nil {
			return false, 
		}
		if  ==  {
			return true, nil
		}
		if  == nil {
			return false, nil
		}
		if ,  := [];  {
			return false, invariant.New("BinPack found a cycle in node ancestry")
		}
		[] = struct{}{}
		switch {
		case .Container != nil:
			 = .Container
		case .Cluster != nil && .Cluster.Vessel != nil:
			 = .Cluster.Vessel
		case .Sequence != nil && .Sequence.Vessel != nil:
			 = .Sequence.Vessel
		default:
			return  == nil, nil
		}
	}
}

func binPackHasExternalConnection(
	 *layoutgraph.Graph,
	,  *layoutgraph.Node,
	,  bool,
	 *limits.WorkGuard,
) (bool, error) {
	if  == nil {
		return false, nil
	}
	,  := .AllDescendantNodesWithWorkGuard(, true, )
	if  != nil {
		return false, 
	}
	 := make([]*layoutgraph.Node, 0, len()+1)
	 = append(, )
	for ,  := range  {
		if  := .Step();  != nil {
			return false, 
		}
		 = append(, )
	}
	for ,  := range  {
		if  := .Step();  != nil {
			return false, 
		}
		if  {
			,  := binPackOrderedNears(, )
			if  != nil {
				return false, 
			}
			for ,  := range  {
				,  := binPackIsDescendantOf(, , )
				if  != nil {
					return false, 
				}
				if ! {
					return true, nil
				}
			}
			continue
		}
		for ,  := range .Edges {
			if  := .Step();  != nil {
				return false, 
			}
			 := .Adjacent()
			// Once routes exist, moving a descendant connected to this container
			// translates the complete route and pulls the container endpoint off its
			// fixed border. Treat that attachment like a cross-container constraint.
			if  &&  ==  {
				return true, nil
			}
			,  := binPackIsDescendantOf(, , )
			if  != nil {
				return false, 
			}
			if ! {
				return true, nil
			}
		}
	}
	return false, .Finish()
}

func binPackOrderedNears( *layoutgraph.Node,  *limits.WorkGuard) ([]*layoutgraph.Node, error) {
	if  == nil {
		return nil, invariant.New("BinPack cannot order nears for a nil node")
	}
	if len(.Nears) > limits.MaxEngineNodes {
		return nil, invariant.New("BinPack node near count exceeds node limit")
	}
	 := make([]*layoutgraph.Node, 0, len(.Nears))
	for  := range .Nears {
		if  := .Step();  != nil {
			return nil, 
		}
		if  == nil {
			return nil, invariant.New("BinPack found a nil near")
		}
		 = append(, )
	}
	// Account for the comparison sort before entering the small, bounded legacy
	// sorter, so every recursive BinPack helper consumes the same stage budget.
	for  := len();  > 1;  = ( + 1) / 2 {
		for range  {
			if  := .Step();  != nil {
				return nil, 
			}
		}
	}
	layoutgraph.SortNodesByID()
	return , .Finish()
}

type binPackHierarchyBox struct {
	topLeft, bottomRight *geo.Point
}

func binPackHierarchyBoxes( []layoutgraph.Nodes,  *limits.WorkGuard) ([]binPackHierarchyBox, error) {
	 := make([]binPackHierarchyBox, 0)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		if len() == 0 {
			return nil, invariant.New("BinPack contains an empty packed subgraph")
		}
		if [0].Hierarchy == nil {
			continue
		}
		, ,  := graphbounds.BoundingBox(, )
		if  != nil {
			return nil, 
		}
		 = append(, binPackHierarchyBox{topLeft: , bottomRight: })
	}
	return , .Finish()
}

func binPackPointInHierarchy( []binPackHierarchyBox,  *geo.Point,  *limits.WorkGuard) (bool, error) {
	if  == nil {
		return false, invariant.New("BinPack hierarchy check received a nil point")
	}
	for ,  := range  {
		if  := .Step();  != nil {
			return false, 
		}
		if .topLeft.X <= .X && .X <= .bottomRight.X &&
			.topLeft.Y <= .Y && .Y <= .bottomRight.Y {
			return true, nil
		}
	}
	return false, .Finish()
}

func binPackWrapChildren( *layoutgraph.Node,  *limits.WorkGuard) error {
	if !.IsContainer() {
		return nil
	}
	 := layoutgraph.Nodes(.Graph.Containers[])
	 := .Graph.ContainerPadding(, false)
	, ,  := graphbounds.FixedBoundingBox(, )
	if  != nil {
		return 
	}
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		if .Label != nil && (.TopLeft.X == .X || .TopLeft.X+.Width == .X) &&
			.Label.Width > .Width {
			.X = math.Min(.X, math.Floor(.TopLeft.X+(.Width/2.-.Label.Width/2.)))
			.X = math.Max(.X, math.Ceil(.TopLeft.X+.Width-(.Width/2.-.Label.Width/2.)))
		}
	}
	.FitToBoundingBox(, , )
	 := .InsidePlacement(.X-.X, .Y-.Y, )
	.Translate(.X-.X, .Y-.Y)
	return .Finish()
}

func binPackMoveNodeWithChildren( *layoutgraph.Node, ,  float64,  *limits.WorkGuard) error {
	if  := .Step();  != nil {
		return 
	}
	if  == 0 &&  == 0 {
		return nil
	}
	if  == nil || .TopLeft == nil || .Graph == nil {
		return invariant.New("BinPack cannot move an unplaced node or a node without a graph")
	}
	.Translate(, )
	,  := .Graph.AllDescendantNodesWithWorkGuard(, true, )
	if  != nil {
		return 
	}
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		if  == nil || .TopLeft == nil {
			return invariant.New("BinPack cannot move an unplaced descendant")
		}
		.Translate(, )
	}
	return .Finish()
}

func binPackPositionContainerChildren( *layoutgraph.Node,  *limits.WorkGuard) error {
	if  := .Step();  != nil {
		return 
	}
	if  == nil || !.IsContainer() {
		return nil
	}
	if .Graph == nil {
		return invariant.New("BinPack container has no graph")
	}
	 := layoutgraph.Nodes(.Graph.Containers[])
	, ,  := graphbounds.FixedBoundingBox(, )
	if  != nil {
		return 
	}
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		if  == nil || .TopLeft == nil {
			return invariant.New("BinPack container contains an unplaced child")
		}
		if .Label != nil && (.TopLeft.X == .X || .TopLeft.X+.Width == .X) &&
			.Label.Width > .Width {
			.X = math.Min(.X, math.Floor(.TopLeft.X+(.Width/2.-.Label.Width/2.)))
			.X = math.Max(.X, math.Ceil(.TopLeft.X+.Width-(.Width/2.-.Label.Width/2.)))
		}
	}
	 := .InsidePlacement(.X-.X, .Y-.Y, layoutgraph.Spacing{})
	 := .X - .X
	 := .Y - .Y
	for ,  := range  {
		if  := binPackMoveNodeWithChildren(, , , );  != nil {
			return 
		}
	}
	return .Finish()
}

type binPackClusterGeometryWork struct {
	guard *limits.WorkGuard
}

func ( binPackClusterGeometryWork) () error   { return .guard.Step() }
func ( binPackClusterGeometryWork) () error { return .guard.Finish() }

func ( binPackClusterGeometryWork) ( *layoutgraph.Node, ,  float64) error {
	return binPackMoveNodeWithChildren(, , , .guard)
}

func ( binPackClusterGeometryWork) ( *layoutgraph.Node) error {
	return binPackPositionContainerChildren(, .guard)
}

var _ layoutgraph.ClusterGeometryWork = binPackClusterGeometryWork{}

type binPackRDFSFrame struct {
	node  *layoutgraph.Node
	phase uint8
	index int
}

func binPackReverseDFSWalk( *layoutgraph.Node,  func(*layoutgraph.Node) error,  *limits.WorkGuard) error {
	if  == nil {
		return invariant.New("BinPack reverse traversal contains a nil node")
	}
	 := []binPackRDFSFrame{{node: }}
	 := map[*layoutgraph.Node]struct{}{: {}}
	for len() > 0 {
		if  := .Step();  != nil {
			return 
		}
		 := &[len()-1]
		 := .node.Graph
		if  == nil {
			return invariant.New("BinPack reverse traversal found a node without a graph")
		}
		var  layoutgraph.Nodes
		switch .phase {
		case 0:
			if .node.IsContainer() {
				 = .Containers[.node]
			}
		case 1:
			if .node.IsClusterVessel() {
				 := .Clusters[.node]
				if  == nil {
					return invariant.New("BinPack reverse traversal found a cluster vessel without a cluster")
				}
				 = .Nodes
			} else if  := .Sequences[.node];  != nil {
				 = .Nodes
			}
		default:
			if  := (.node);  != nil {
				return 
			}
			delete(, .node)
			 = [:len()-1]
			continue
		}
		if .index >= len() {
			.phase++
			.index = 0
			continue
		}
		 := [.index]
		.index++
		if  == nil {
			return invariant.New("BinPack reverse traversal contains a nil child")
		}
		if ,  := [];  {
			return invariant.New("BinPack reverse traversal found a topology cycle")
		}
		[] = struct{}{}
		 = append(, binPackRDFSFrame{node: })
	}
	return .Finish()
}

func binPackSyncClusters( *layoutgraph.Graph,  *limits.WorkGuard) error {
	if  == nil {
		return invariant.New("BinPack cannot synchronize a nil graph")
	}
	if len(.Clusters) == 0 {
		return .Finish()
	}
	 := binPackClusterGeometryWork{guard: }
	for ,  := range .Nodes {
		if  := .Step();  != nil {
			return 
		}
		if  := binPackReverseDFSWalk(, func( *layoutgraph.Node) error {
			if !.IsClusterVessel() {
				return nil
			}
			return .Clusters[].SyncGeometryWithWork()
		}, );  != nil {
			return 
		}
	}
	return .Finish()
}

func binPackSyncSequences( *layoutgraph.Graph,  *limits.WorkGuard) error {
	if  == nil {
		return invariant.New("BinPack cannot synchronize a nil graph")
	}
	if len(.Sequences) == 0 {
		return .Finish()
	}
	for ,  := range .Nodes {
		if  := .Step();  != nil {
			return 
		}
		if  := binPackReverseDFSWalk(, func( *layoutgraph.Node) error {
			 := .Sequences[]
			if  == nil {
				return nil
			}
			return .SyncGeometryWithWork()
		}, );  != nil {
			return 
		}
	}
	return .Finish()
}

func binPackSmallestDeltas( []layoutgraph.Nodes,  *limits.WorkGuard) (float64, float64, error) {
	,  := math.Inf(1), math.Inf(1)
	for ,  := range  {
		if  := .Step();  != nil {
			return 0, 0, 
		}
		, ,  := graphbounds.BoundingBox(, )
		if  != nil {
			return 0, 0, 
		}
		 = math.Min(, .X-.X)
		 = math.Min(, .Y-.Y)
	}
	if  := .Finish();  != nil {
		return 0, 0, 
	}
	return , , nil
}

// allEdgesHaveCompleteRoutesGuarded enforces the all-or-none route state that
// BinPack relies on. Once routes exist, connected components move as rigid
// bodies and routed container geometry becomes a packing constraint. Treating a
// partially routed graph as wholly unrouted would skip both protections while
// leaving the complete routes in place.
//
// The graph-owned edge list and every affected node-owned edge list must also
// agree exactly. Otherwise a complete route omitted from either inventory could
// evade route-aware packing and be detached or cut by a move or container
// shrink. Self-loops occur once in both inventories.
func allEdgesHaveCompleteRoutesGuarded( *layoutgraph.Graph,  *layoutgraph.Node,  *limits.WorkGuard) (bool, []*layoutgraph.Edge, error) {
	if  == nil {
		return false, nil, invariant.New("BinPack received a nil graph")
	}
	var  []*layoutgraph.Node
	if  == nil {
		 = .Nodes
	} else {
		var  error
		,  = .AllDescendantNodesWithWorkGuard(, true, )
		if  != nil {
			return false, nil, 
		}
	}
	 := make([]*layoutgraph.Node, 0, len()+1)
	if  != nil {
		 = append(, )
	}
	 = append(, ...)
	 := make(map[*layoutgraph.Node]struct{}, len())
	for ,  := range  {
		if  := .Step();  != nil {
			return false, nil, 
		}
		if  == nil || .Graph !=  {
			return false, nil, invariant.New("BinPack affected-node inventory is malformed")
		}
		if ,  := [];  {
			return false, nil, invariant.Errorf("BinPack affected-node inventory repeats node %d", .ID)
		}
		[] = struct{}{}
	}

	 := make(map[*layoutgraph.Node]map[*layoutgraph.Edge]int, len())
	 := make(map[*layoutgraph.Node]int, len())
	for ,  := range  {
		[] = make(map[*layoutgraph.Edge]int)
	}
	 := make(map[*layoutgraph.Edge]struct{})
	 := 0
	var  []*layoutgraph.Edge
	for ,  := range .Edges {
		if  := .Step();  != nil {
			return false, nil, 
		}
		if  == nil {
			return false, nil, invariant.Errorf("BinPack found a nil edge at index %d", )
		}
		if .From == nil || .To == nil {
			return false, nil, invariant.Errorf("BinPack edge %d has a nil endpoint", .ID)
		}
		if .From.Graph !=  || .To.Graph !=  {
			return false, nil, invariant.Errorf("BinPack edge %d has an endpoint owned by another graph", .ID)
		}
		 := false
		if ,  := [.From];  {
			 = true
			[.From][]++
			[.From]++
		}
		if .To != .From {
			if ,  := [.To];  {
				 = true
				[.To][]++
				[.To]++
			}
		}
		if  {
			if ,  := [];  {
				return false, nil, invariant.Errorf("BinPack graph edge inventory repeats affected edge %d", .ID)
			}
			[] = struct{}{}
		}
		if len(.Points) == 0 {
			continue
		}
		if len(.Points) < 2 {
			return false, nil, invariant.Errorf(
				"BinPack edge %d has an incomplete route with %d point(s)",
				.ID, len(.Points),
			)
		}
		for ,  := range .Points {
			if  := .Step();  != nil {
				return false, nil, 
			}
			if  == nil {
				return false, nil, invariant.Errorf(
					"BinPack edge %d has a nil route point at index %d",
					.ID, ,
				)
			}
		}
		++
		if  != nil && (.From ==  || .To == ) {
			 = append(, )
		}
	}
	if  != 0 &&  != len(.Edges) {
		return false, nil, invariant.Errorf(
			"BinPack graph is partially routed: %d of %d edges have routes",
			, len(.Edges),
		)
	}

	for ,  := range  {
		 := make(map[*layoutgraph.Edge]int, len(.Edges))
		for ,  := range .Edges {
			if  := .Step();  != nil {
				return false, nil, 
			}
			if  == nil {
				return false, nil, invariant.Errorf(
					"BinPack node %d edge inventory contains a nil edge at index %d",
					.ID, ,
				)
			}
			if .From !=  && .To !=  {
				return false, nil, invariant.Errorf(
					"BinPack node %d edge inventory contains non-incident edge %d",
					.ID, .ID,
				)
			}
			[]++
			 := [][]
			if [] >  {
				return false, nil, invariant.Errorf(
					"BinPack node %d edge inventory has %d occurrence(s) of edge %d; graph requires %d",
					.ID, [], .ID, ,
				)
			}
		}
		if len(.Edges) != [] {
			return false, nil, invariant.Errorf(
				"BinPack node %d edge inventory has %d occurrence(s); graph requires %d",
				.ID, len(.Edges), [],
			)
		}
	}
	if  == 0 {
		return false, nil, .Finish()
	}
	return true, , .Finish()
}