package routing

import (
	

	

	
)

func removeDuplicatePointsGuarded( []*geo.Point,  *routeWorkGuard) ([]*geo.Point, error) {
	if len() <= 1 {
		return , .step()
	}

	 := make([]*geo.Point, 0, len())
	 = append(, [0])
	for  := 1;  < len(); ++ {
		if  := .step();  != nil {
			return nil, 
		}
		 := [-1]
		 := []
		if .X != .X || .Y != .Y {
			 = append(, )
		}
	}

	if len() == 1 {
		 := [0].Copy()
		.X++
		 = append(, )
	}
	return , nil
}

func nodeSegmentsGuarded( layoutgraph.Nodes,  bool,  *routeWorkGuard) ([]*geo.Segment, error) {
	 := make([]*geo.Segment, 0, len()*2)
	for ,  := range  {
		if  := .step();  != nil {
			return nil, 
		}
		if  {
			 = append(, &geo.Segment{Start: .TopLeft, End: geo.NewPoint(.TopLeft.X+.Width, .TopLeft.Y)})
			 = append(, &geo.Segment{Start: geo.NewPoint(.TopLeft.X, .TopLeft.Y+.Height), End: geo.NewPoint(.TopLeft.X+.Width, .TopLeft.Y+.Height)})
		} else {
			 = append(, &geo.Segment{Start: .TopLeft, End: geo.NewPoint(.TopLeft.X, .TopLeft.Y+.Height)})
			 = append(, &geo.Segment{Start: geo.NewPoint(.TopLeft.X+.Width, .TopLeft.Y), End: geo.NewPoint(.TopLeft.X+.Width, .TopLeft.Y+.Height)})
		}
	}
	return , nil
}

func edgeSegmentsGuarded( layoutgraph.Edges,  bool,  *routeWorkGuard) ([]*layoutgraph.EdgeSegment, error) {
	var  []*layoutgraph.EdgeSegment
	for ,  := range  {
		if  := .step();  != nil {
			return nil, 
		}
		for  := 0;  < len(.Points)-1; ++ {
			if  := .step();  != nil {
				return nil, 
			}
			var ,  *geo.Point
			if  {
				if .Points[].Y == .Points[+1].Y {
					if .Points[].X < .Points[+1].X {
						,  = .Points[], .Points[+1]
					} else {
						,  = .Points[+1], .Points[]
					}
				}
			} else if .Points[].X == .Points[+1].X {
				if .Points[].Y < .Points[+1].Y {
					,  = .Points[], .Points[+1]
				} else {
					,  = .Points[+1], .Points[]
				}
			}
			if  != nil &&  != nil {
				 = append(, layoutgraph.NewEdgeSegment(, , ))
			}
		}
	}
	return , nil
}

// routeSegmentBounds is the cancellable equivalent of geo.Segment.GetBounds.
// Keep its comparisons byte-for-byte equivalent so successful layouts do not
// change while long locked-segment scans become interruptible.
func routeSegmentBounds( geo.Segment,  []*geo.Segment,  float64,  *routeWorkGuard) (float64, float64, error) {
	 := math.Inf(1)
	 := math.Inf(-1)
	if .Start.X == .End.X && .Start.Y == .End.Y {
		return , , .step()
	}
	 := .Start.X == .End.X
	for ,  := range  {
		if  := .step();  != nil {
			return 0, 0, 
		}
		if  {
			if .End.Y < .Start.Y- {
				continue
			}
			if .Start.Y > .End.Y+ {
				continue
			}
			if .Start.X <= .Start.X {
				 = math.Max(, .Start.X)
			}
			if .Start.X > .Start.X {
				 = math.Min(, .Start.X)
			}
		} else {
			if .End.X < .Start.X- {
				continue
			}
			if .Start.X > .End.X+ {
				continue
			}
			if .Start.Y <= .Start.Y {
				 = math.Max(, .Start.Y)
			}
			if .Start.Y > .Start.Y {
				 = math.Min(, .Start.Y)
			}
		}
	}
	return , , nil
}

func evenlyDistributeGuarded(,  float64,  int,  *routeWorkGuard) ([]float64, error) {
	if  <= 0 ||  >=  {
		return []float64{}, .step()
	}
	 := math.Floor(( - ) / float64(+1))
	if  <= 0 {
		return []float64{}, .step()
	}
	 := make([]float64, 0, )
	for  := 1;  <= ; ++ {
		if  := .step();  != nil {
			return nil, 
		}
		 = append(, +float64()*)
	}
	return , nil
}

type balanceOrderStatus int

const (
	balanceOrderPreserved balanceOrderStatus = iota
	balanceOrderReversed
	balanceOrderContactChanged
)

// checkBalanceOrder checks a batch against parallel routes that
// belong to another movement range. Such routes are not locked yet when the
// narrowest range is balanced, but moving past one can drag an attached elbow
// across it. Sorting within each batch alone cannot preserve this ordering.
//
// Check every member, including partial shared trunks, before changing any
// coordinates. Rejecting the whole proposal preserves shared routes; the caller
// still locks the unchanged batch so balancing always makes progress.
func checkBalanceOrder( []*layoutgraph.EdgeSegment,  map[*layoutgraph.EdgeSegment]bool,  []*layoutgraph.EdgeSegment,  []float64,  bool,  *routeWorkGuard) (balanceOrderStatus, error) {
	 := false
	for ,  := range  {
		if  := .step();  != nil {
			return balanceOrderPreserved, 
		}
		 := .Start.Y
		if  {
			 = .Start.X
		}
		if [] !=  {
			 = true
			break
		}
	}
	if ! {
		return balanceOrderPreserved, nil
	}
	 := balanceOrderPreserved
	// Skip batch members before scanning proposals. A parallel bundle already
	// balanced together needs only a linear scan when no outside routes exist.
	for ,  := range  {
		if  := .step();  != nil {
			return balanceOrderPreserved, 
		}
		if [] {
			continue
		}
		for ,  := range  {
			if  := .step();  != nil {
				return balanceOrderPreserved, 
			}
			// Segments of one route may meet while eliminating an elbow.
			// Preserve ordering between distinct routes, not within a route.
			if .Owner() == .Owner() {
				continue
			}
			,  := .Start.Y, .Start.Y
			,  := .Start.X, .End.X
			,  := .Start.X, .End.X
			if  {
				,  = .Start.X, .Start.X
				,  = .Start.Y, .End.Y
				,  = .Start.Y, .End.Y
			}
			if [] ==  {
				continue
			}
			// Closed intervals matter: an elbow at the end of either segment
			// moves with it, so touching intervals can also acquire a crossing.
			if math.Max(, ) < math.Min(, ) || math.Max(, ) < math.Min(, ) {
				continue
			}
			if  ==  || [] ==  {
				// Creating a shared coordinate or splitting one is not a
				// crossing improvement: crossing counts omit collinear contact.
				return balanceOrderContactChanged, nil
			}
			if ( < ) != ([] < ) {
				 = balanceOrderReversed
				// Keep checking: a later relation may prohibit fallback.
			}
		}
	}
	return , nil
}