package labeling

import (
	
	
	

	
	

	
	
)

const (
	// Label placement is intentionally bounded independently of adapter input
	// validation. The engine is also called directly by route-only consumers and
	// tests, so its expensive overlap kernels must defend their own boundary.
	maxLabelPlacementWorkUnits       int64 = limits.MaxLabelPlacementWorkUnits
	maxLabelPlacementAncestryDepth         = layoutgraph.MaxTopologyDepth
	labelPlacementContextCheckStride       = 64
)

// labelPlacementWorkGuard makes every unit of quadratic/candidate work both
// cancellable and bounded. Its overflow check happens before addition, so the
// limit remains deterministic even on 32-bit platforms and hostile inputs.
type labelPlacementWorkGuard struct {
	ctx      context.Context
	location string
	used     int64
	limit    int64
}

func newLabelPlacementWorkGuard( context.Context,  string,  int64) (*labelPlacementWorkGuard, error) {
	if  == nil {
		return nil, fmt.Errorf("TALA %s requires a context", )
	}
	if  < 0 {
		return nil, fmt.Errorf("TALA %s work limit must not be negative", )
	}
	 := &labelPlacementWorkGuard{
		ctx:      ,
		location: ,
		limit:    ,
	}
	if  := .check();  != nil {
		return nil, 
	}
	return , nil
}

func ( *labelPlacementWorkGuard) () error {
	return .add(1)
}

func ( *labelPlacementWorkGuard) ( int64) error {
	if  < 0 {
		return fmt.Errorf("TALA %s received a negative work estimate", .location)
	}
	// Written this way rather than used+units > limit so the calculation cannot
	// wrap before the comparison.
	if .used < 0 || .used > .limit ||  > .limit-.used {
		// Preserve cancellation as the primary failure when it races the budget
		// boundary; otherwise callers could receive a resource error after they
		// had already canceled the work.
		if  := .check();  != nil {
			return 
		}
		return fmt.Errorf("TALA %s work exceeds limit %d", .location, .limit)
	}
	 := .used
	.used += 
	if  == 0 || /labelPlacementContextCheckStride != .used/labelPlacementContextCheckStride {
		return .check()
	}
	return nil
}

func ( *labelPlacementWorkGuard) () error {
	if  := .ctx.Err();  != nil {
		return fmt.Errorf("%s: %w", .location, )
	}
	return nil
}

type labelPositionSnapshot struct {
	label    *layoutgraph.Label
	position label.Position
}

type iconPositionSnapshot struct {
	icon     *layoutgraph.Icon
	position label.Position
}

type edgeLabelPercentageSnapshot struct {
	edge       *layoutgraph.Edge
	percentage float64
}

type labelPlacementSnapshot struct {
	labels          []labelPositionSnapshot
	icons           []iconPositionSnapshot
	edgePercentages []edgeLabelPercentageSnapshot
}

// captureLabelPlacement records only the state this algorithm owns. Keeping
// the original label/icon objects (rather than copying or replacing them)
// preserves pointer identity for callers that retain aliases.
func captureLabelPlacement( *layoutgraph.Graph,  []*layoutgraph.Edge) labelPlacementSnapshot {
	 := labelPlacementSnapshot{}
	 := make(map[*layoutgraph.Label]struct{})
	 := make(map[*layoutgraph.Icon]struct{})
	 := make(map[*layoutgraph.Edge]struct{})

	 := func( *layoutgraph.Label) {
		if  == nil {
			return
		}
		if ,  := [];  {
			return
		}
		[] = struct{}{}
		.labels = append(.labels, labelPositionSnapshot{
			label:    ,
			position: .Position,
		})
	}
	 := func( *layoutgraph.Icon) {
		if  == nil {
			return
		}
		if ,  := [];  {
			return
		}
		[] = struct{}{}
		.icons = append(.icons, iconPositionSnapshot{
			icon:     ,
			position: .Position,
		})
	}
	 := func( *layoutgraph.Edge) {
		if  == nil {
			return
		}
		(.Label)
		if ,  := [];  {
			return
		}
		[] = struct{}{}
		.edgePercentages = append(.edgePercentages, edgeLabelPercentageSnapshot{
			edge:       ,
			percentage: .LabelPercentage,
		})
	}

	if  != nil {
		for ,  := range .Nodes {
			if  == nil {
				continue
			}
			(.Label)
			(.Icon)
		}
		for ,  := range .Edges {
			()
		}
	}
	for ,  := range  {
		()
	}
	return 
}

func ( labelPlacementSnapshot) () {
	for ,  := range .labels {
		.label.Position = .position
	}
	for ,  := range .icons {
		.icon.Position = .position
	}
	for ,  := range .edgePercentages {
		.edge.LabelPercentage = .percentage
	}
}

func nodeOverlapCount( *layoutgraph.Node,  layoutgraph.Nodes,  float64,  *labelPlacementWorkGuard) (int, error) {
	 := 0
	for ,  := range  {
		if  := .step();  != nil {
			return 0, 
		}
		if .LabelBoxesOverlap(, ) {
			++
		}
	}
	return , nil
}

func partialNodeOverlapCount( *layoutgraph.Node,  layoutgraph.Nodes,  float64,  *labelPlacementWorkGuard) (int, error) {
	 := 0
	for ,  := range  {
		if  := .step();  != nil {
			return 0, 
		}
		if .LabelBoxesOverlap(, ) && !.Covers() {
			++
		}
	}
	return , nil
}

func nodeOverlapArea( *layoutgraph.Node,  layoutgraph.Nodes,  float64,  bool,  *labelPlacementWorkGuard) (float64, int, error) {
	 := 0.0
	 := 0
	for ,  := range  {
		if  := .step();  != nil {
			return 0, 0, 
		}
		if !.LabelBoxesOverlap(, ) || ( && .Covers()) {
			continue
		}
		if  == 0 || .DoesOverlapExact() {
			 += .LabelOverlapArea()
			++
		}
		if !.IsContainer() {
			 += .Area()
			++
		}
	}
	return , , nil
}

func edgeOverlapCount( *layoutgraph.Node,  layoutgraph.Edges,  float64,  *labelPlacementWorkGuard) (int, error) {
	 := 0
	for ,  := range  {
		if  := .step();  != nil {
			return 0, 
		}
		for  := 1;  < len(.Points); ++ {
			if  := .step();  != nil {
				return 0, 
			}
			if .OverlapsLine(.Points[-1], .Points[], ) {
				++
			}
		}
	}
	return , nil
}

func collectLabelPlacementAncestors( *layoutgraph.Node,  *labelPlacementWorkGuard) (layoutgraph.Nodes, error) {
	 := make(layoutgraph.Nodes, 0, 4)
	for ,  := , 0;  != nil; ++ {
		if  >= maxLabelPlacementAncestryDepth {
			return nil, fmt.Errorf("TALA %s container depth exceeds limit %d", .location, maxLabelPlacementAncestryDepth)
		}
		if  := .step();  != nil {
			return nil, 
		}
		 = append(, )
		 = .EffectiveContainer()
	}
	return , nil
}

func isLabelPlacementDescendantOf(,  *layoutgraph.Node,  *labelPlacementWorkGuard) (bool, error) {
	for  := 0; ; ++ {
		if  ==  {
			return true, nil
		}
		if  == nil {
			return false, nil
		}
		if  >= maxLabelPlacementAncestryDepth {
			return false, fmt.Errorf("TALA %s ancestry depth exceeds limit %d", .location, maxLabelPlacementAncestryDepth)
		}
		if  := .step();  != nil {
			return false, 
		}
		switch {
		case .Container != nil:
			 = .Container
		case .Cluster != nil:
			 = .Cluster.Vessel
		case .Sequence != nil:
			 = .Sequence.Vessel
		default:
			 = nil
		}
	}
}

func clusterBoundaryNodePlacement( *layoutgraph.Node,  layoutgraph.Nodes,  geo.Orientation,  *labelPlacementWorkGuard) (bool, error) {
	for ,  := range  {
		if  := .step();  != nil {
			return false, 
		}
		if  ==  || .TopLeft == nil {
			continue
		}
		switch  {
		case geo.Left:
			if .TopLeft.X < .TopLeft.X {
				return false, nil
			}
		case geo.Top:
			if .TopLeft.Y < .TopLeft.Y {
				return false, nil
			}
		case geo.Right:
			if .TopLeft.X+.Width > .TopLeft.X+.Width {
				return false, nil
			}
		case geo.Bottom:
			if .TopLeft.Y+.Height > .TopLeft.Y+.Height {
				return false, nil
			}
		}
	}
	return true, nil
}

func clusterNodeBoundingBoxPlacement( *layoutgraph.Node,  layoutgraph.Nodes,  *labelPlacementWorkGuard) (*geo.Point, *geo.Point, error) {
	if  == nil || .TopLeft == nil {
		return nil, nil, fmt.Errorf("TALA %s cluster contains an unplaced node", .location)
	}
	if  := .step();  != nil {
		return nil, nil, 
	}
	 := .TopLeft.Copy()
	 := geo.NewPoint(math.Round(.X+.Width), math.Round(.Y+.Height))
	if ,  := .ModifierElementAdjustments();  != 0 ||  != 0 {
		.Y -= 
		.X += 
	}
	.X -= .LoopOffsets[geo.Left]
	.Y -= .LoopOffsets[geo.Top]
	.X += .LoopOffsets[geo.Right]
	.Y += .LoopOffsets[geo.Bottom]

	if .Label != nil && .Label.Position.IsOutside() {
		 := .LabelTopLeft(.Label.Position, .Label.Width, .Label.Height)
		 := float64(label.PADDING)
		 := 2. * label.PADDING
		if .X < .X {
			,  := clusterBoundaryNodePlacement(, , geo.Left, )
			if  != nil {
				return nil, nil, 
			}
			 := 
			if  {
				 = 
			}
			.X = math.Floor(.X - )
		}
		if .Y < .Y {
			,  := clusterBoundaryNodePlacement(, , geo.Top, )
			if  != nil {
				return nil, nil, 
			}
			 := 
			if  {
				 = 
			}
			.Y = math.Floor(.Y - )
		}
		if .X > .X {
			,  := clusterBoundaryNodePlacement(, , geo.Right, )
			if  != nil {
				return nil, nil, 
			}
			 := 
			if  {
				 = 
			}
			.X = math.Ceil(.X + .Label.Width + )
		}
		if .Y > .Y {
			,  := clusterBoundaryNodePlacement(, , geo.Bottom, )
			if  != nil {
				return nil, nil, 
			}
			 := 
			if  {
				 = 
			}
			.Y = math.Ceil(.Y + .Label.Height + )
		}
	}
	if .Icon != nil && !.IsImage() && .Icon.Position.IsOutside() {
		 := float64(layoutgraph.MaxIconSize)
		 := .LabelTopLeft(.Icon.Position, , )
		 := 2. * label.PADDING
		.X = math.Min(.X, math.Floor(.X-))
		.Y = math.Min(.Y, math.Floor(.Y-))
		.X = math.Max(.X, math.Ceil(.X++))
		.Y = math.Max(.Y, math.Ceil(.Y++))
	}
	return , , nil
}

func clusterLabelPlacementOrientation(,  *layoutgraph.Node,  *layoutgraph.Cluster,  *labelPlacementWorkGuard) (geo.Orientation, int, error) {
	 := geo.NewPoint(math.Inf(-1), math.Inf(-1))
	 := geo.NewPoint(math.Inf(1), math.Inf(1))
	if len(.Nodes) > 0 {
		 = geo.NewPoint(math.Inf(1), math.Inf(1))
		 = geo.NewPoint(math.Inf(-1), math.Inf(-1))
		for ,  := range .Nodes {
			, ,  := clusterNodeBoundingBoxPlacement(, .Nodes, )
			if  != nil {
				return geo.NONE, -1, 
			}
			.X = math.Min(.X, .X)
			.Y = math.Min(.Y, .Y)
			.X = math.Max(.X, .X)
			.Y = math.Max(.Y, .Y)
		}
	}
	 := layoutgraph.NewNode(0, .X-.X, .Y-.Y)
	.TopLeft = 
	 := .Orientation()
	 := -1
	for ,  := range .Nodes {
		if  := .step();  != nil {
			return geo.NONE, -1, 
		}
		if  ==  {
			 = 
			break
		}
	}
	return , , nil
}

func routeLengthPlacement( *layoutgraph.Edge,  *labelPlacementWorkGuard) (float64, error) {
	 := 0.0
	for  := 1;  < len(.Points); ++ {
		if  := .step();  != nil {
			return 0, 
		}
		 := .Points[-1]
		 := .Points[]
		 += geo.EuclideanDistance(.X, .Y, .X, .Y)
	}
	return , nil
}

func edgeLabelTopLeft( *layoutgraph.Edge,  label.Position, ,  float64,  *labelPlacementWorkGuard) (*geo.Point, error) {
	// d2's route label helper walks the route once for total length and once to
	// locate the requested distance. Reserve both passes before entering it,
	// then check again at the boundary.
	for  := 0;  < 2; ++ {
		if  := .add(int64(len(.Points)));  != nil {
			return nil, 
		}
	}
	 := .LabelTopLeft(, , )
	if  := .check();  != nil {
		return nil, 
	}
	return , nil
}

func positionedArrowheadLabel( *layoutgraph.Edge,  bool,  *labelPlacementWorkGuard) (*PositionedArrowheadLabel, error) {
	// Arrowhead placement computes route length directly, then the label helper
	// performs its own length and distance passes.
	for  := 0;  < 3; ++ {
		if  := .add(int64(len(.Points)));  != nil {
			return nil, 
		}
	}
	 := PositionArrowheadLabel(, , .Points)
	if  := .check();  != nil {
		return nil, 
	}
	return , nil
}

type labelEdgeSortItem struct {
	edge   *layoutgraph.Edge
	length float64
}

func sortLabelPlacementEdges( []*layoutgraph.Edge,  *labelPlacementWorkGuard) ([]*layoutgraph.Edge, error) {
	 := make([]labelEdgeSortItem, len())
	for ,  := range  {
		if  := .step();  != nil {
			return nil, 
		}
		,  := routeLengthPlacement(, )
		if  != nil {
			return nil, 
		}
		[] = labelEdgeSortItem{edge: , length: }
	}
	 := make([]labelEdgeSortItem, len())
	 := func(,  labelEdgeSortItem) bool {
		if len(.edge.Points) == 2 && len(.edge.Points) > 2 {
			return true
		}
		if len(.edge.Points) == 2 && len(.edge.Points) > 2 {
			return false
		}
		return .length < .length
	}
	for  := 1;  < len(); {
		for  := 0;  < len();  += 2 *  {
			 := min(+, len())
			 := min(+2*, len())
			, ,  := , , 
			for  <  &&  <  {
				if  := .step();  != nil {
					return nil, 
				}
				// Choose the left item for ties, matching sort.SliceStable.
				if ([], []) {
					[] = []
					++
				} else {
					[] = []
					++
				}
				++
			}
			for  <  {
				if  := .step();  != nil {
					return nil, 
				}
				[] = []
				++
				++
			}
			for  <  {
				if  := .step();  != nil {
					return nil, 
				}
				[] = []
				++
				++
			}
		}
		,  = , 
		if  > len()/2 {
			break
		}
		 *= 2
	}
	 := make([]*layoutgraph.Edge, len())
	for ,  := range  {
		[] = .edge
	}
	return , .check()
}

func sortSharedSegmentGroup( []*geo.Segment,  func(*geo.Point) float64,  func() error) error {
	if len() < 2 {
		return nil
	}
	 := make([]*geo.Segment, len())
	 := func(,  *geo.Segment) bool {
		if (.Start) == (.Start) {
			return (.End) < (.End)
		}
		return (.Start) < (.Start)
	}
	 := 
	for  := 1;  < len(); {
		for  := 0;  < len();  += 2 *  {
			 := min(+, len())
			 := min(+2*, len())
			, ,  := , , 
			for  <  &&  <  {
				if  != nil {
					if  := ();  != nil {
						return 
					}
				}
				if ([], []) {
					[] = []
					++
				} else {
					[] = []
					++
				}
				++
			}
			for  <  {
				if  != nil {
					if  := ();  != nil {
						return 
					}
				}
				[] = []
				++
				++
			}
			for  <  {
				if  != nil {
					if  := ();  != nil {
						return 
					}
				}
				[] = []
				++
				++
			}
		}
		,  = , 
		if  > len()/2 {
			break
		}
		 *= 2
	}
	if len() > 0 && &[0] != &[0] {
		copy(, )
	}
	return nil
}