package dagro

// feasibleTree constructs a spanning tree of tight edges, shifting ranks until
// every node can be added. It preserves graphlib edge order for all ties.
func feasibleTree( *Graph) *Graph {
	 := NewGraph(GraphOptions{Undirected: true})
	 := .Nodes()[0]
	 := .NodeCount()
	.SetNode(, Attrs{})

	for tightTree(, ) <  {
		,  := findMinSlackEdge(, )
		if ! {
			panic("dagro: feasibleTree could not find an incident edge")
		}
		 := slack(, )
		if !.HasNode(.V) {
			 = -
		}
		shiftRanks(, , )
	}

	return 
}

// tightTree grows t along zero-slack edges and returns its node count.
func tightTree(,  *Graph) int {
	var  func(string)
	 = func( string) {
		for ,  := range .NodeEdges() {
			 := .V
			if  == .V {
				 = .W
			}
			if !.HasNode() && !jsTruthyNumber(slack(, )) {
				.SetNode(, Attrs{})
				.SetEdge(, , Attrs{})
				()
			}
		}
	}

	for ,  := range .Nodes() {
		()
	}
	return .NodeCount()
}

// findMinSlackEdge returns the first minimum-slack edge incident on t. Lodash
// minBy is stable for ties, so replacement is deliberately strict.
func findMinSlackEdge(,  *Graph) (Edge, bool) {
	var  Edge
	 := 0.0
	 := false
	for ,  := range .Edges() {
		if .HasNode(.V) == .HasNode(.W) {
			continue
		}
		 := slack(, )
		if ! ||  <  {
			, ,  = , , true
		}
	}
	return , 
}

func shiftRanks(,  *Graph,  float64) {
	for ,  := range .Nodes() {
		 := asAttrs(.Node())
		["rank"] = num(, "rank") + 
	}
}