package routing

import (
	
	
	
	
)

func hasFixedBalancingPorts( *layoutgraph.Edge) bool {
	return .HasTableColumn() || .From.Shape.GetType() == shape.DIAMOND_TYPE || .To.Shape.GetType() == shape.DIAMOND_TYPE
}

// balancePortInteriorsGuarded gives fixed-port routes a separate conservative
// balancing pass. Other routes, endpoints, and their approach segments act as
// immutable corridor boundaries. Reject the whole tentative batch if moving
// connected bends creates an obstruction, crossing, or substantial detour.
func balancePortInteriorsGuarded( *layoutgraph.Graph,  *routeWorkGuard) error {
	var ,  []*layoutgraph.Edge
	for ,  := range .Edges {
		if  := .step();  != nil {
			return 
		}
		,  := .NodeToTree[.From]
		,  := .NodeToTree[.To]
		if hasFixedBalancingPorts() && !.IsCurve && !.IsLoop() && ! && ! && len(.Points) >= 6 {
			 = append(, )
		} else {
			 = append(, )
		}
	}
	if len() == 0 {
		return nil
	}
	,  := quality.Inspect(.ctx, )
	if  != nil {
		return 
	}
	,  := captureRouteMutations(, nil, )
	if  != nil {
		return 
	}
	,  := copyRoutePoints(, )
	if  != nil {
		return 
	}
	if  := balanceRegularEdgesGuarded(, , , );  != nil {
		return 
	}
	for ,  := range  {
		,  := changedRouteIsClear(, , [], true, )
		if  != nil {
			return 
		}
		if ! {
			.restore()
			return nil
		}
	}
	,  := quality.Inspect(.ctx, )
	if  != nil {
		return 
	}
	if .RouteObstructions > .RouteObstructions || .Crossings > .Crossings ||
		.TextOcclusions > .TextOcclusions || .RouteLength > .RouteLength*1.1 {
		.restore()
	}
	return nil
}

func copyRoutePoints( []*layoutgraph.Edge,  *routeWorkGuard) (map[*layoutgraph.Edge][]*geo.Point, error) {
	 := make(map[*layoutgraph.Edge][]*geo.Point, len())
	for ,  := range  {
		if  := .add(uint64(len(.Points)) + 1);  != nil {
			return nil, 
		}
		 := make([]*geo.Point, len(.Points))
		for ,  := range .Points {
			 := *
			[] = &
		}
		[] = 
	}
	return , nil
}

func changedRouteIsClear( *layoutgraph.Graph,  *layoutgraph.Edge,  []*geo.Point,  bool,  *routeWorkGuard) (bool, error) {
	if len(.Points) < 2 || len() < 2 {
		return false, nil
	}
	if  && (*.Points[0] != *[0] || *.Points[len(.Points)-1] != *[len()-1] ||
		!sameRouteDirection([0], [1], .Points[0], .Points[1]) ||
		!sameRouteDirection([len()-2], [len()-1], .Points[len(.Points)-2], .Points[len(.Points)-1])) {
		return false, nil
	}
	for  := 1;  < len(.Points); ++ {
		,  := .Points[-1], .Points[]
		 := false
		for  := 1;  < len(); ++ {
			if  := .step();  != nil {
				return false, 
			}
			if * == *[-1] && * == *[] {
				 = true
				break
			}
		}
		if  {
			continue
		}
		if .X != .X && .Y != .Y {
			return false, nil
		}
		,  := lineIntersectsUnrelatedNode(, , , , )
		if  != nil {
			return false, 
		}
		if  {
			return false, nil
		}
	}
	return true, nil
}