package routing

import (
	
	

	
	
)

func hasCompleteEdgeRoute( *layoutgraph.Edge) bool {
	if len(.Points) < 2 {
		return false
	}
	for ,  := range .Points {
		if  == nil {
			return false
		}
	}
	return true
}

func ( context.Context,  *layoutgraph.Graph,  []*layoutgraph.Edge) error {
	return routeEdgesWithBudgets(, , , defaultOVGBuildLimits(), maxRouteStageWorkUnits)
}

func routeEdgesWithBudgets( context.Context,  *layoutgraph.Graph,  []*layoutgraph.Edge,  ovgBuildLimits,  uint64) error {
	if  == nil {
		return fmt.Errorf("cannot route edges on a nil graph")
	}
	if  == nil {
		return fmt.Errorf("cannot route edges without a context")
	}
	if  := .Err();  != nil {
		return 
	}
	// Reject caller-owned selections before using their length as an allocation
	// hint. Accepted selections are charged again inside the atomic boundary.
	if int64(len()) > layoutgraph.MaxTopologyReferences {
		return fmt.Errorf("TALA EdgeRouting selected edge references exceed limit %d", layoutgraph.MaxTopologyReferences)
	}
	if  := layoutgraph.Validate(, "RouteEdges", );  != nil {
		return 
	}
	if len() == 0 {
		return nil
	}
	if len(.Nodes) == 0 {
		return fmt.Errorf("cannot route edges on an empty graph")
	}
	// A valid selection is duplicate-free and contains only graph edges, so it
	// can never be larger than the graph inventory. Check before map allocation.
	if len() > len(.Edges) {
		return fmt.Errorf("selected edge count %d exceeds graph edge count %d", len(), len(.Edges))
	}

	 := make(map[*layoutgraph.Node]struct{}, len(.Nodes))
	for ,  := range .Nodes {
		if  == nil {
			return fmt.Errorf("graph node at index %d is nil", )
		}
		[] = struct{}{}
	}
	 := make(map[*layoutgraph.Edge]struct{}, len(.Edges))
	for ,  := range .Edges {
		if  == nil {
			return fmt.Errorf("graph edge at index %d is nil", )
		}
		if .From == nil || .To == nil || .From.TopLeft == nil || .To.TopLeft == nil {
			return fmt.Errorf("graph edge %d has unplaced or missing endpoints", .IDValue())
		}
		if ,  := [.From]; ! {
			return fmt.Errorf("graph edge %d source node does not belong to the graph", .IDValue())
		}
		if ,  := [.To]; ! {
			return fmt.Errorf("graph edge %d target node does not belong to the graph", .IDValue())
		}
		[] = struct{}{}
	}
	 := make(map[*layoutgraph.Edge]struct{}, len())
	for ,  := range  {
		if  == nil {
			return fmt.Errorf("cannot route a nil edge")
		}
		if ,  := []; ! {
			return fmt.Errorf("edge %d does not belong to the graph", .IDValue())
		}
		if ,  := [];  {
			return fmt.Errorf("edge %d was selected more than once", .IDValue())
		}
		[] = struct{}{}
	}
	for ,  := range .Edges {
		if ,  := [];  {
			continue
		}
		if !hasCompleteEdgeRoute() {
			return fmt.Errorf("unselected edge %d has no complete route", .IDValue())
		}
	}

	// Standalone routing is one API transaction and one aggregate post-routing
	// work budget. OVG construction and label placement retain their independent
	// derived-resource guards inside this exact rollback boundary.
	return runAtomicRouteStageAfterPreflight(, "EdgeRouting", , , , func( *routeWorkGuard) error {
		if  := .add(uint64(len(.Nodes)));  != nil {
			return 
		}
		.ComputeCellSize()

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

		for ,  := range  {
			if .HasTableColumn() {
				if  := .step();  != nil {
					return 
				}
				continue
			}
			if  := tryStraightEdgeFallbackGuarded(, , );  != nil {
				return 
			}
		}

		 := make([]*layoutgraph.Edge, 0, len(.Edges))
		for ,  := range .Edges {
			if  := .step();  != nil {
				return 
			}
			if ,  := []; ! {
				 = append(, )
			}
		}
		 := make([]*layoutgraph.Edge, 0, len())
		for ,  := range  {
			if  := .step();  != nil {
				return 
			}
			if isSpecialEdgeForBalancing(, ) {
				 = append(, )
				continue
			}
			 = append(, )
		}
		if  := balanceRegularEdgesGuarded(, , , );  != nil {
			return 
		}
		for ,  := range  {
			if  := traceToShapeBorderGuarded(, );  != nil {
				return 
			}
		}
		if  := reorderDuplicatesInEdgesGuarded(, );  != nil {
			return 
		}
		if  := .step();  != nil {
			return 
		}
		if  := labeling.PlaceNewEdges(, , );  != nil {
			return 
		}
		return .finish()
	})
}