package dagro

func greedyFAS( *Graph,  func(Edge) float64) []Edge {
	if .NodeCount() <= 1 {
		return nil
	}
	, ,  := buildFASState(, )
	 := doGreedyFAS(, , )
	var  []Edge
	for ,  := range  {
		 = append(, .OutEdges(.V, .W)...)
	}
	return 
}

func doGreedyFAS( *Graph,  []*fasList,  int) []Edge {
	var  []Edge
	,  := [len()-1], [0]
	for .NodeCount() > 0 {
		for  := .dequeue();  != nil;  = .dequeue() {
			removeFASNode(, , , , false)
		}
		for  := .dequeue();  != nil;  = .dequeue() {
			removeFASNode(, , , , false)
		}
		if .NodeCount() > 0 {
			for  := len() - 2;  > 0; -- {
				if  := [].dequeue();  != nil {
					 = append(, removeFASNode(, , , , true)...)
					break
				}
			}
		}
	}
	return 
}

func removeFASNode( *Graph,  []*fasList,  int,  *fasEntry,  bool) []Edge {
	var  []Edge
	for ,  := range .InEdges(.V) {
		 := number(.Edge())
		 := .Node(.V).(*fasEntry)
		if  {
			 = append(, Edge{V: .V, W: .W})
		}
		.Out -= 
		assignFASBucket(, , )
	}
	for ,  := range .OutEdges(.V) {
		 := number(.Edge())
		 := .Node(.W).(*fasEntry)
		.In -= 
		assignFASBucket(, , )
	}
	.RemoveNode(.V)
	return 
}

func buildFASState( *Graph,  func(Edge) float64) (*Graph, []*fasList, int) {
	 := NewGraph()
	,  := 0.0, 0.0
	for ,  := range .Nodes() {
		.SetNode(, &fasEntry{V: })
	}
	for ,  := range .Edges() {
		 := 0.0
		if  := .EdgeByArgs(.V, .W);  != nil {
			 = number()
		}
		 := ()
		.SetEdge(.V, .W, +)
		,  := .Node(.V).(*fasEntry), .Node(.W).(*fasEntry)
		.Out += 
		.In += 
		,  = mathMaxJS(, .Out), mathMaxJS(, .In)
	}
	 := make([]*fasList, int(+)+3)
	for  := range  {
		[] = &fasList{}
	}
	 := int() + 1
	for ,  := range .Nodes() {
		assignFASBucket(, , .Node().(*fasEntry))
	}
	return , , 
}

func assignFASBucket( []*fasList,  int,  *fasEntry) {
	 := 0
	if !jsTruthyNumber(.Out) {
		 = 0
	} else if !jsTruthyNumber(.In) {
		 = len() - 1
	} else {
		 = int(.Out-.In) + 
	}
	[].enqueue()
}