package routing

import (
	
	
	

	
	
	
)

func ( context.Context,  *layoutgraph.Graph) error {
	return balanceEdgeSegmentsWithLimit(, , maxRouteStageWorkUnits)
}

func balanceEdgeSegmentsWithLimit( context.Context,  *layoutgraph.Graph,  uint64) error {
	return runAtomicRouteStage(, "BalanceEdgeSegments", , nil, , func( *routeWorkGuard) error {
		return balanceEdgeSegmentsGuarded(, )
	})
}

func balanceEdgeSegmentsGuarded( *layoutgraph.Graph,  *routeWorkGuard) error {
	// Special nodes get special routing, don't mess with them
	 := make([]*layoutgraph.Edge, 0)
	 := make([]*layoutgraph.Edge, 0)
	for ,  := range .Edges {
		if  := .step();  != nil {
			return 
		}
		if len(.Points) < 2 {
			return fmt.Errorf("TALA BalanceEdgeSegments edge %d has an incomplete route", .IDValue())
		}
		if isSpecialEdgeForBalancing(, ) {
			 = append(, )
			continue
		}
		 = append(, )
	}

	if  := balanceRegularEdgesGuarded(, , , );  != nil {
		return 
	}
	return balancePortInteriorsGuarded(, )
}

// isSpecialEdgeForBalancing identifies routes whose ports or rule-generated
// geometry balancing must leave unchanged.
func isSpecialEdgeForBalancing( *layoutgraph.Graph,  *layoutgraph.Edge) bool {
	if ,  := .NodeToTree[.From];  {
		return true
	}
	if ,  := .NodeToTree[.To];  {
		return true
	}
	if .HasTableColumn() || .IsLoop() {
		return true
	}
	// We want edges locked to diamond ports strictly.
	if .From.Shape.GetType() == shape.DIAMOND_TYPE || .To.Shape.GetType() == shape.DIAMOND_TYPE {
		return true
	}
	// When node A (width even) aligns with node B (width odd), the centers can
	// end up misaligned by 1.
	 := .Points[0]
	 := .Points[len(.Points)-1]
	return math.Abs(.X-.X) == 1 || math.Abs(.Y-.Y) == 1
}

func balanceRegularEdgesGuarded( *layoutgraph.Graph, ,  []*layoutgraph.Edge,  *routeWorkGuard) error {
	// Row and diamond ports fix the endpoint and its short approach segment,
	// while longer interior corridors can still be balanced.
	 := make(map[*geo.Point]bool)
	for ,  := range  {
		if  := .step();  != nil {
			return 
		}
		if !hasFixedBalancingPorts() {
			continue
		}
		for ,  := range .Points[:min(2, len(.Points))] {
			[] = true
		}
		for ,  := range .Points[max(0, len(.Points)-2):] {
			[] = true
		}
	}
	 := func( *geo.Point) (bool, error) {
		for ,  := range .Nodes {
			if  := .step();  != nil {
				return false, 
			}
			if .Width == 1 && .Height == 1 {
				// Check if point is on the node's border
				if (.X == .TopLeft.X || .X == .TopLeft.X+1) &&
					(.Y == .TopLeft.Y || .Y == .TopLeft.Y+1) {
					return true, nil
				}
			}
		}
		return false, nil
	}

	 := func(,  *layoutgraph.Edge) *layoutgraph.Cluster {
		 := .From.Cluster
		 := .To.Cluster

		 := .From.Cluster
		 := .To.Cluster
		if  != nil && ( ==  ||  == ) {
			return 
		}
		if  != nil && ( ==  ||  == ) {
			return 
		}
		return nil
	}

	 := func(,  float64) bool {
		return math.Abs(-) <= 1
	}

	for ,  := range []bool{true, false} {
		,  := nodeSegmentsGuarded(layoutgraph.Nodes(.Nodes), !, )
		if  != nil {
			return 
		}
		 := make(map[layoutgraph.EdgeSegment]bool)
		// When we balance vertical segments horizontally, we get the vertical segments
		,  := edgeSegmentsGuarded(layoutgraph.Edges(), !, )
		if  != nil {
			return 
		}

		 := make([]*layoutgraph.EdgeSegment, 0, len())
		var  []*geo.Segment
		for ,  := range  {
			if [.Start] || [.End] {
				 = append(, &.Segment)
				continue
			}
			,  := (.Start)
			if  != nil {
				return 
			}
			,  := (.End)
			if  != nil {
				return 
			}
			if ! && ! {
				 = append(, )
			}
		}
		// Special edges shouldn't be moved, but they're still considered for bounds checking
		 := 
		,  := edgeSegmentsGuarded(layoutgraph.Edges(), !, )
		if  != nil {
			return 
		}
		for ,  := range  {
			if  := .step();  != nil {
				return 
			}
			 = append(, &.Segment)
		}
		// Regular edges shared with special edges should also be locked
		for ,  := range  {
			for ,  := range  {
				if  := .step();  != nil {
					return 
				}
				if !.Segment.Overlaps(*, , 1) {
					continue
				}
				if  {
					if (.Start.X, .Start.X) {
						 = append(, &.Segment)
						[*] = true
						break
					}
				} else {
					if (.Start.Y, .Start.Y) {
						 = append(, &.Segment)
						[*] = true
						break
					}
				}
			}
		}
		 = append(, ...)
		for len() != len() {
			if  := .step();  != nil {
				return 
			}
			 := Range{start: math.Inf(-1), end: math.Inf(1)}
			 := map[Range][]*layoutgraph.EdgeSegment{}

			for ,  := range  {
				if  := .step();  != nil {
					return 
				}
				if ,  := [*];  {
					continue
				}
				, ,  := routeSegmentBounds(.Segment, , segmentSpacingBuffer, )
				if  != nil {
					return 
				}
				if  {
					if math.IsInf(, -1) {
						 = .Start.X - unboundedSegmentMove
					}
					if math.IsInf(, 1) {
						 = .Start.X + unboundedSegmentMove
					}
				} else {
					if math.IsInf(, -1) {
						 = .Start.Y - unboundedSegmentMove
					}
					if math.IsInf(, 1) {
						 = .Start.Y + unboundedSegmentMove
					}
				}

				 := Range{start: , end: }

				[] = append([], )
				if .length() < .length() {
					 = 
				}
			}

			// For all the segments which share the same min range, we want to further split them up by overlap
			// E.g. if two segments don't overlap, they can both take the 50% point between its range
			// But if they overlap, they share the same space, so have to evenly distribute at 33% and 66% points
			for ,  := range [] {
				if  := .step();  != nil {
					return 
				}
				if ,  := [*];  {
					continue
				}
				 := []*layoutgraph.EdgeSegment{}
				 := map[*layoutgraph.EdgeSegment]bool{: true}
				for ,  := range [] {
					if  := .step();  != nil {
						return 
					}
					if  ==  {
						continue
					}
					if ,  := [*];  {
						continue
					}
					var  float64 = segmentSpacingBuffer
					// Segments of the same edge don't need to maintain a buffer from each other
					if .Owner() == .Owner() {
						 = 0
					}
					if .Segment.Overlaps(.Segment, , ) {
						 = append(, )
						[] = true
					}
				}
				// Even if the same range is not shared, if a segment shares a route with another segment (even partially), it should be balanced together to maintain shared route
				for ,  := range  {
					if  := .step();  != nil {
						return 
					}
					if ,  := [];  {
						continue
					}
					if ,  := [*];  {
						continue
					}
					if  := (.Owner(), .Owner());  != nil && .Arrangement == .DesiredArrangement {
						// we usually want to balance cluster edge segments normally (Example with Arrangement=Row && IsHorizontal):
						//        before       |        after
						//       ┌─────┐       |       ┌─────┐
						//       │     │       |       │     │
						//       └┬────┘       |       └──┬──┘
						//        │            |          │
						//      ┌─┴─────┐      |    ┌─────┴─────┐
						//      │       │      |    │           │
						// ┌────▼┐     ┌▼────┐ | ┌──▼──┐     ┌──▼──┐
						// │     │     │     │ | │     │     │     │
						// └─────┘     └─────┘ | └─────┘     └─────┘
						//
						// but we want to balance cluster mid-segments in a combined range
						//             before                      |              separate ranges            |             combined range
						// ┌──────┐                      ┌───────┐ | ┌──────┐                      ┌───────┐ | ┌──────┐                      ┌───────┐
						// │      │          ┌───────────►       │ | │      │          ┌───────────►       │ | │      │             ┌────────►       │
						// └──────┘          │           └───────┘ | └──────┘          │           └───────┘ | └──────┘             │        └───────┘
						// ┌──────┐          │           ┌───────┐ | ┌──────┐          │           ┌───────┐ | ┌──────┐             │        ┌───────┐
						// │      ├──────────┼───────────►       │ | │      ├──────────┴──┬────────►       │ | │      ├─────────────┼────────►       │
						// └──────┘          │           └───────┘ | └──────┘             │        └───────┘ | └──────┘             │        └───────┘
						// ┌───────────┐     │           ┌───────┐ | ┌───────────┐        │        ┌───────┐ | ┌───────────┐        │        ┌───────┐
						// │           │     └───────────►       │ | │           │        └────────►       │ | │           │        └────────►       │
						// └───────────┘                 └───────┘ | └───────────┘                 └───────┘ | └───────────┘                 └───────┘
						var  bool
						if  {
							 = .Arrangement == layoutgraph.Column && (.Start.X, .Start.X)
						} else {
							 = .Arrangement == layoutgraph.Row && (.Start.Y, .Start.Y)
						}
						if  {
							 = append(, )
							[] = true
							continue
						}
					}
					if !.Segment.Overlaps(.Segment, , 1) {
						continue
					}
					var  bool
					if  {
						 = (.Start.X, .Start.X)
					} else {
						 = (.Start.Y, .Start.Y)
					}
					if  {
						 = append(, )
						[] = true
					}
				}
				if  := stableSortRouteValues(, func(,  *layoutgraph.EdgeSegment) bool {
					var ,  float64
					var ,  float64
					if  {
						 = .Start.X
						 = .Start.X
						 = .Start.Y
						 = .Start.Y
					} else {
						 = .Start.Y
						 = .Start.Y
						 = .Start.X
						 = .Start.X
					}
					if  ==  {
						return  < 
					}
					return  < 
				}, );  != nil {
					return 
				}
				// Among the overlapping segments, some may be on shared routes. They're shared intentionally, so we want to keep them shared.
				 := map[float64]struct{}{}
				for ,  := range  {
					if  := .step();  != nil {
						return 
					}
					if  {
						[math.Round(.Start.X)] = struct{}{}
					} else {
						[math.Round(.Start.Y)] = struct{}{}
					}
				}

				// Now we take the overlapping segments with the same range of movement, and rebalance them
				,  := evenlyDistributeGuarded(.start, .end, len(), )
				if  != nil {
					return 
				}
				 := make([]float64, len())
				for ,  := range  {
					if  := .step();  != nil {
						return 
					}
					[] = .Start.Y
					if  {
						[] = .Start.X
					}
				}

				for ,  := 0, 0;  < len(); ++ {
					if  := .step();  != nil {
						return 
					}
					 := 0
					for + < len() {
						if  := .step();  != nil {
							return 
						}
						if  {
							if ([].Start.X, [+].Start.X) {
								++
							} else {
								break
							}
						} else {
							if ([].Start.Y, [+].Start.Y) {
								++
							} else {
								break
							}
						}
					}

					 := []
					for  := ;  < +; ++ {
						if  := .step();  != nil {
							return 
						}
						[] = 
					}
					 += 
				}
				,  := checkBalanceOrder(, , , , , )
				if  != nil {
					return 
				}
				if  != balanceOrderContactChanged {
					,  := checkBalanceOrder(, , , , , )
					if  != nil {
						return 
					}
					 = max(, )
				}
				 :=  == balanceOrderPreserved
				if  == balanceOrderReversed {
					,  = balanceReversalRemovesCrossings(, , , , )
					if  != nil {
						return 
					}
				}
				if  {
					for ,  := range  {
						if  := .step();  != nil {
							return 
						}
						if  {
							.Start.X = []
							.End.X = []
						} else {
							.Start.Y = []
							.End.Y = []
						}
					}
				}
				for ,  := range  {
					if  := .step();  != nil {
						return 
					}
					[*] = true
					 = append(, &.Segment)
				}
			}
		}
	}
	for ,  := range  {
		,  := removeDuplicatePointsGuarded(.Points, )
		if  != nil {
			return 
		}
		.Points = 
	}
	return nil
}

// FixClusterEdgeBranching resolves route branching at cluster boundaries.
func ( context.Context,  *layoutgraph.Graph) error {
	return fixClusterEdgeBranchingWithLimit(, , maxRouteStageWorkUnits)
}

func fixClusterEdgeBranchingWithLimit( context.Context,  *layoutgraph.Graph,  uint64) error {
	return runAtomicRouteStage(, "FixClusterEdgeBranching", , nil, , func( *routeWorkGuard) error {
		return fixClusterEdgeBranchingGuarded(, )
	})
}

func fixClusterEdgeBranchingGuarded( *layoutgraph.Graph,  *routeWorkGuard) error {
	for ,  := range .Nodes {
		if  := .step();  != nil {
			return 
		}
		if len(.Edges) <= 1 {
			continue
		}
		if .Cluster != nil {
			continue
		}
		 := make(map[*layoutgraph.Cluster]bool)
		 := make(map[*layoutgraph.Cluster][]*layoutgraph.Edge)
		for ,  := range .Edges {
			if  := .step();  != nil {
				return 
			}
			if len(.Points) != 4 {
				continue
			}
			 := .Adjacent()
			if .Cluster != nil {
				if .Cluster.DesiredArrangement != .Cluster.Arrangement {
					continue
				}
				if .From ==  {
					[.Cluster] = true
				} else {
					[.Cluster] = false
				}
				if ,  := [.Cluster]; ! {
					[.Cluster] = []*layoutgraph.Edge{}
				} else {
					[.Cluster] = append([.Cluster], )
				}
			}
		}

		for ,  := range  {
			if  := .step();  != nil {
				return 
			}
			 := false
			 := false
			for ,  := range  {
				if  := .step();  != nil {
					return 
				}
				if .Arrangement == layoutgraph.Row {
					if [] {
						if .Points[3].X < .Points[0].X {
							 = true
						}
						if .Points[3].X > .Points[0].X {
							 = true
						}
					} else {
						if .Points[0].X < .Points[3].X {
							 = true
						}
						if .Points[0].X > .Points[3].X {
							 = true
						}
					}
				} else {
					if [] {
						if .Points[3].Y < .Points[0].Y {
							 = true
						}
						if .Points[3].Y > .Points[0].Y {
							 = true
						}
					} else {
						if .Points[0].Y < .Points[3].Y {
							 = true
						}
						if .Points[0].Y > .Points[3].Y {
							 = true
						}
					}
				}
			}
			if ! || ! {
				continue
			}

			 := make(map[*layoutgraph.Edge]*geo.Point)
			 := make(map[*layoutgraph.Edge]*geo.Point)
			var  []*geo.Point
			for ,  := range  {
				if  := .step();  != nil {
					return 
				}
				if [] {
					 = append(, .Points[1])
				} else {
					 = append(, .Points[2])
				}
				[] = .Points[1].Copy()
				[] = .Points[2].Copy()
			}

			var  *geo.Point
			var  float64

		:
			for ,  := range  {
				if  := .step();  != nil {
					return 
				}
				for ,  := range  {
					if  := .step();  != nil {
						return 
					}
					.Points[1] = [].Copy()
					.Points[2] = [].Copy()
				}
				 := 0.
				for ,  := range  {
					if  := .step();  != nil {
						return 
					}
					,  := estimateRouteCostGuarded(layoutgraph.Edges(.Edges), , )
					if  != nil {
						return 
					}
					if [] {
						if .Points[1] ==  {
							 += 
							continue
						}
					} else {
						if .Points[2] ==  {
							 += 
							continue
						}
					}
					if [] {
						.Points[1] = .Copy()
						if .Arrangement == layoutgraph.Row {
							.Points[2].Y = .Y
						} else {
							.Points[2].X = .X
						}
					} else {
						.Points[2] = .Copy()
						if .Arrangement == layoutgraph.Row {
							.Points[1].Y = .Y
						} else {
							.Points[1].X = .X
						}
					}

					 := false
					,  := routeIntersectsNodeGuarded(layoutgraph.Nodes(.Nodes), , )
					if  != nil {
						return 
					}
					if  {
						 = true
					}
					if ! {
						,  := estimateRouteCostGuarded(layoutgraph.Edges(.Edges), , )
						if  != nil {
							return 
						}
						 += 
						if  >  {
							 = true
						}
					}
					if  {
						continue 
					}
				}
				if  == nil ||  <  {
					 = 
					 = 
				}
			}

			for ,  := range  {
				if  := .step();  != nil {
					return 
				}
				.Points[1] = [].Copy()
				.Points[2] = [].Copy()
			}

			if  != nil {
				for ,  := range  {
					if  := .step();  != nil {
						return 
					}
					if [] {
						.Points[1] = .Copy()
						if .Arrangement == layoutgraph.Row {
							.Points[2].Y = .Y
						} else {
							.Points[2].X = .X
						}
					} else {
						.Points[2] = .Copy()
						if .Arrangement == layoutgraph.Row {
							.Points[1].Y = .Y
						} else {
							.Points[1].X = .X
						}
					}
				}
			}
		}
	}

	return .finish()
}