package trees

import (
	

	
	
	
)

const treePreprocessLocation = "PreprocessTrees"

func treePreprocessBadState( string,  ...any) error {
	return invariant.Errorf(, ...)
}

// treeContainerRDFSOrder is the bounded, iterative equivalent of
// containerRDFSOrder. The stack is populated in forward slice order so its
// LIFO traversal preserves the existing reverse-DFS output order exactly.
func treeContainerRDFSOrder( *layoutgraph.Graph,  *layoutgraph.Node,  *limits.WorkGuard) ([]*layoutgraph.Node, error) {
	if  != nil && !.IsContainer() {
		return nil, nil
	}

	type  struct {
		 *layoutgraph.Node
		 bool
	}
	 := make([], 0, len(.Containers[]))
	for ,  := range .Containers[] {
		if  := .Step();  != nil {
			return nil, 
		}
		 = append(, {: })
	}

	 := make([]*layoutgraph.Node, 0, len(.Containers))
	for len() > 0 {
		if  := .Step();  != nil {
			return nil, 
		}
		 := [len()-1]
		 = [:len()-1]
		if . == nil {
			return nil, treePreprocessBadState("tree preprocessing encountered a nil container child")
		}
		if . {
			 = append(, .)
			continue
		}

		if ..IsContainer() {
			 = append(, {: ., : true})
			for ,  := range .Containers[.] {
				if  := .Step();  != nil {
					return nil, 
				}
				 = append(, {: })
			}
			continue
		}

		if ..IsClusterVessel() {
			 := .Clusters[.]
			if  == nil {
				return nil, treePreprocessBadState("cluster vessel %d has no cluster record", ..ID)
			}
			for ,  := range .Nodes {
				if  := .Step();  != nil {
					return nil, 
				}
				if  == nil {
					return nil, treePreprocessBadState("cluster vessel %d contains a nil node", ..ID)
				}
				if .IsContainer() {
					 = append(, {: })
				}
			}
		}
	}
	return , nil
}

func buildTreeAdjacencyMatrix( *layoutgraph.Graph,  *limits.WorkGuard) (func(,  *layoutgraph.Node) *layoutgraph.Edge, error) {
	 := make(map[*layoutgraph.Node]map[*layoutgraph.Node]*layoutgraph.Edge)
	for ,  := range .Edges {
		if  := .Step();  != nil {
			return nil, 
		}
		if  == nil || .From == nil || .To == nil {
			return nil, treePreprocessBadState("tree preprocessing encountered an edge with missing endpoints")
		}
		if ,  := [.From]; ! {
			[.From] = make(map[*layoutgraph.Node]*layoutgraph.Edge)
		}
		[.From][.To] = 
	}
	return func(,  *layoutgraph.Node) *layoutgraph.Edge {
		,  := [][]
		if ! {
			 = [][]
		}
		return 
	}, nil
}

func treeFringeNodes( []*layoutgraph.Node,  *limits.WorkGuard) ([]*layoutgraph.Node, error) {
	 := make(map[*layoutgraph.Node]struct{}, len())
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		if  == nil {
			return nil, treePreprocessBadState("tree preprocessing encountered a nil node")
		}
		[] = struct{}{}
	}

	 := make([]*layoutgraph.Node, 0)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		if len(.Edges) != 1 {
			continue
		}
		 := .Edges[0]
		if  == nil || (.From !=  && .To != ) {
			return nil, treePreprocessBadState("node %d contains a non-incident fringe edge", .ID)
		}
		 := .Adjacent()
		if ,  := [];  {
			 = append(, )
		}
	}
	return , nil
}

func filterTerminalTrees( []*layoutgraph.Tree,  map[*layoutgraph.Node]bool,  *limits.WorkGuard) ([]*layoutgraph.Tree, error) {
	 := make([]*layoutgraph.Tree, 0)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		if  == nil || .Node == nil {
			return nil, treePreprocessBadState("tree preprocessing encountered a tree without a node")
		}
		if ,  := [.Node]; ! {
			 = append(, )
		}
	}
	return , nil
}

// dominantTreeEdgeDirection preserves the recursive helper's preorder search:
// the first non-undirected sentinel direction wins, otherwise the root's
// undirected direction is returned.
func dominantTreeEdgeDirection( *layoutgraph.Tree,  bool,  *limits.WorkGuard) (TreeEdgeDirection, error) {
	if  == nil || .Node == nil {
		return Undirected, treePreprocessBadState("tree preprocessing encountered an incomplete tree")
	}
	if .SentinelEdge == nil {
		return Undirected, treePreprocessBadState("tree node %d has no sentinel edge", .Node.ID)
	}

	 := make([]*layoutgraph.Tree, 0, len(.Children)+1)
	if  {
		 = append(, )
	} else {
		for ,  := range slices.Backward(.Children) {
			if  := .Step();  != nil {
				return Undirected, 
			}
			 = append(, )
		}
	}
	 := make(map[*layoutgraph.Tree]struct{})
	for len() > 0 {
		if  := .Step();  != nil {
			return Undirected, 
		}
		 := [len()-1]
		 = [:len()-1]
		if  == nil || .Node == nil || .SentinelEdge == nil {
			return Undirected, treePreprocessBadState("tree preprocessing encountered an incomplete tree")
		}
		if ,  := [];  {
			return Undirected, treePreprocessBadState("tree preprocessing encountered a repeated tree node")
		}
		[] = struct{}{}
		 := treeEdgeDirection(.Node, .SentinelEdge)
		if  != Undirected {
			return , nil
		}
		for ,  := range slices.Backward(.Children) {
			if  := .Step();  != nil {
				return Undirected, 
			}
			 = append(, )
		}
	}
	return treeEdgeDirection(.Node, .SentinelEdge), nil
}

func countTreeDirections( []*layoutgraph.Tree,  *limits.WorkGuard) (map[TreeEdgeDirection]int, error) {
	 := make(map[TreeEdgeDirection]int)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		,  := dominantTreeEdgeDirection(, true, )
		if  != nil {
			return nil, 
		}
		[]++
	}
	return , nil
}

func candidateTreeRoots( []*layoutgraph.Tree,  *limits.WorkGuard) ([]*layoutgraph.Tree, error) {
	 := make(map[TreeEdgeDirection][]*layoutgraph.Tree)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		,  := dominantTreeEdgeDirection(, false, )
		if  != nil {
			return nil, 
		}
		[] = append([], )
	}

	 := len([Outwards])
	 := len([Inwards])
	 := len([Bidirectional])
	 := len([Undirected])
	 := make([]*layoutgraph.Tree, 0, len())
	 := func( []*layoutgraph.Tree) error {
		for ,  := range  {
			if  := .Step();  != nil {
				return 
			}
			 = append(, )
		}
		return nil
	}
	if  == 1 && 1++ == len() {
		if  := ([Outwards]);  != nil {
			return nil, 
		}
	}
	if  == 1 && 1++ == len() {
		if  := ([Inwards]);  != nil {
			return nil, 
		}
	}
	if  > 0 &&  > 1 && + == len() {
		if  := ([Undirected]);  != nil {
			return nil, 
		}
	}
	if  > 0 &&  > 1 && + == len() {
		if  := ([Undirected]);  != nil {
			return nil, 
		}
	}
	if + == len() {
		if  := ([Bidirectional]);  != nil {
			return nil, 
		}
		if  := ([Undirected]);  != nil {
			return nil, 
		}
	}
	if  := .Check();  != nil {
		return nil, 
	}
	return , nil
}

func treeEndOfLine( *layoutgraph.Tree,  *limits.WorkGuard) (*layoutgraph.Tree, error) {
	 := make(map[*layoutgraph.Tree]struct{})
	 := 
	for {
		if  := .Step();  != nil {
			return nil, 
		}
		if  == nil {
			return nil, treePreprocessBadState("tree preprocessing encountered a nil tree")
		}
		if ,  := [];  {
			return nil, treePreprocessBadState("tree preprocessing encountered a tree cycle")
		}
		[] = struct{}{}
		switch len(.Children) {
		case 0:
			return , nil
		case 1:
			 = .Children[0]
		default:
			return nil, nil
		}
	}
}

func removeTreeChild(,  *layoutgraph.Tree,  *limits.WorkGuard) error {
	 := make([]*layoutgraph.Tree, 0, len(.Children))
	for ,  := range .Children {
		if  := .Step();  != nil {
			return 
		}
		if  !=  {
			 = append(, )
		}
	}
	.Children = 
	return nil
}

func addTreeChild(,  *layoutgraph.Tree,  *limits.WorkGuard) error {
	if  == nil ||  == nil {
		return treePreprocessBadState("tree preprocessing cannot connect a nil tree")
	}
	if .Parent != nil {
		if  := removeTreeChild(.Parent, , );  != nil {
			return 
		}
	}
	if  := .Step();  != nil {
		return 
	}
	.Parent = 
	.Children = append(.Children, )
	return nil
}

func reverseTreeChain( *layoutgraph.Tree,  *limits.WorkGuard) error {
	if  == nil {
		return treePreprocessBadState("tree preprocessing cannot reverse a nil tree")
	}
	 := []*layoutgraph.Tree{}
	 := make(map[*layoutgraph.Tree]struct{})
	 := 
	for len(.Children) > 0 {
		if  := .Step();  != nil {
			return 
		}
		if len(.Children) != 1 {
			return treePreprocessBadState("tree preprocessing attempted to reverse a branching tree")
		}
		if ,  := [];  {
			return treePreprocessBadState("tree preprocessing encountered a tree cycle")
		}
		[] = struct{}{}
		 := .Children[0]
		if  == nil {
			return treePreprocessBadState("tree preprocessing encountered a nil tree child")
		}
		.SentinelEdge = .SentinelEdge
		.SentinelEdge = nil
		if  := removeTreeChild(, , );  != nil {
			return 
		}
		 = append(, )
		 = 
	}
	for  := len() - 1;  > 0; -- {
		if  := addTreeChild([], [-1], );  != nil {
			return 
		}
	}
	return nil
}

func treeBranches( *layoutgraph.Tree,  *limits.WorkGuard) (bool, error) {
	 := make(map[*layoutgraph.Tree]struct{})
	 := 
	for {
		if  := .Step();  != nil {
			return false, 
		}
		if  == nil {
			return false, treePreprocessBadState("tree preprocessing encountered a nil tree")
		}
		if ,  := [];  {
			return false, treePreprocessBadState("tree preprocessing encountered a tree cycle")
		}
		[] = struct{}{}
		switch len(.Children) {
		case 0:
			return false, nil
		case 1:
			 = .Children[0]
		default:
			return true, nil
		}
	}
}

func treeSize( *layoutgraph.Tree,  *limits.WorkGuard) (int, error) {
	if  == nil {
		return 0, treePreprocessBadState("tree preprocessing cannot size a nil tree")
	}
	 := []*layoutgraph.Tree{}
	 := make(map[*layoutgraph.Tree]struct{})
	 := 0
	for len() > 0 {
		if  := .Step();  != nil {
			return 0, 
		}
		 := [len()-1]
		 = [:len()-1]
		if  == nil || .Node == nil {
			return 0, treePreprocessBadState("tree preprocessing encountered an incomplete tree")
		}
		if ,  := [];  {
			return 0, treePreprocessBadState("tree preprocessing encountered a repeated tree node")
		}
		[] = struct{}{}
		++
		for ,  := range slices.Backward(.Children) {
			if  := .Step();  != nil {
				return 0, 
			}
			 = append(, )
		}
	}
	return , nil
}

func treeDescendants( *layoutgraph.Tree,  *limits.WorkGuard) ([]*layoutgraph.Tree, error) {
	if  == nil {
		return nil, treePreprocessBadState("tree preprocessing cannot traverse a nil tree")
	}
	 := make([]*layoutgraph.Tree, 0)
	 := []*layoutgraph.Tree{}
	 := make(map[*layoutgraph.Tree]struct{})
	for  := 0;  < len(); ++ {
		if  := .Step();  != nil {
			return nil, 
		}
		 := []
		if  == nil || .Node == nil {
			return nil, treePreprocessBadState("tree preprocessing encountered an incomplete tree")
		}
		if ,  := [];  {
			return nil, treePreprocessBadState("tree preprocessing encountered a repeated tree node")
		}
		[] = struct{}{}
		for ,  := range .Children {
			if  := .Step();  != nil {
				return nil, 
			}
			 = append(, )
			 = append(, )
		}
	}
	return , nil
}

func rootsByTreeDirection( []*layoutgraph.Tree,  *limits.WorkGuard) (map[TreeEdgeDirection][]*layoutgraph.Tree, error) {
	 := make(map[TreeEdgeDirection][]*layoutgraph.Tree)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		,  := dominantTreeEdgeDirection(, false, )
		if  != nil {
			return nil, 
		}
		[] = append([], )
	}
	return , nil
}

func removeNodeFromGraph( *layoutgraph.Node,  *layoutgraph.Graph,  *limits.WorkGuard) error {
	if len(.Nodes) == 0 {
		return treePreprocessBadState("node %d is missing from the graph", .ID)
	}
	 := make([]*layoutgraph.Node, 0, len(.Nodes)-1)
	 := false
	for ,  := range .Nodes {
		if  := .Step();  != nil {
			return 
		}
		if  ==  {
			 = true
			continue
		}
		 = append(, )
	}
	if ! {
		return treePreprocessBadState("node %d is missing from the graph", .ID)
	}
	.Nodes = 
	return nil
}

func removeEdgeFromNode( *layoutgraph.Node,  *layoutgraph.Edge,  *limits.WorkGuard) error {
	for ,  := range .Edges {
		if  := .Step();  != nil {
			return 
		}
		if  ==  {
			.Edges = append(.Edges[:], .Edges[+1:]...)
			return nil
		}
	}
	return treePreprocessBadState("edge %d is missing from node %d", .ID, .ID)
}

func disconnectTreeEdge( *layoutgraph.Graph,  *layoutgraph.Edge,  *limits.WorkGuard) error {
	if  == nil || .From == nil || .To == nil {
		return treePreprocessBadState("tree preprocessing cannot disconnect an incomplete edge")
	}
	if  := removeEdgeFromNode(.From, , );  != nil {
		return 
	}
	if .To != .From {
		if  := removeEdgeFromNode(.To, , );  != nil {
			return 
		}
	} else {
		// Disconnect historically calls removeEdge for each endpoint even on a
		// self-loop. Preserve the second removal only when a duplicate exists.
		for ,  := range .To.Edges {
			if  := .Step();  != nil {
				return 
			}
			if  ==  {
				if  := removeEdgeFromNode(.To, , );  != nil {
					return 
				}
				break
			}
		}
	}

	 := make([]*layoutgraph.Edge, 0, len(.Edges))
	 := false
	for ,  := range .Edges {
		if  := .Step();  != nil {
			return 
		}
		if  ==  {
			 = true
			continue
		}
		 = append(, )
	}
	if ! {
		return treePreprocessBadState("edge %d is missing from the graph", .ID)
	}
	.Edges = 
	return nil
}

func removeNodeFromContainer( *layoutgraph.Graph, ,  *layoutgraph.Node,  *limits.WorkGuard) error {
	 := make([]*layoutgraph.Node, 0)
	 := false
	for ,  := range .Containers[] {
		if  := .Step();  != nil {
			return 
		}
		if  ==  {
			 = true
			continue
		}
		 = append(, )
	}
	if ! {
		return treePreprocessBadState("node %d is missing from its tree container", .ID)
	}
	.Containers[] = 
	return nil
}

func reconnectTreeGuarded( *layoutgraph.Graph,  *layoutgraph.Tree,  *layoutgraph.Node,  *limits.WorkGuard) error {
	if  == nil {
		return treePreprocessBadState("tree preprocessing cannot reconnect a nil tree")
	}
	 := []*layoutgraph.Tree{}
	 := make(map[*layoutgraph.Tree]struct{})
	for len() > 0 {
		if  := .Step();  != nil {
			return 
		}
		 := [len()-1]
		 = [:len()-1]
		if  == nil || .Node == nil {
			return treePreprocessBadState("tree preprocessing encountered an incomplete tree")
		}
		if ,  := [];  {
			return treePreprocessBadState("tree preprocessing encountered a repeated tree node")
		}
		[] = struct{}{}

		if .Parent != nil {
			 := .SentinelEdge
			if  == nil || .From == nil || .To == nil {
				return treePreprocessBadState("tree node %d has no complete sentinel edge", .Node.ID)
			}
			.AddNodeUnchecked(.Node)
			.AddNodeToContainer(, .Node)
			.From.AddIncidentEdgeUnchecked()
			.To.AddIncidentEdgeUnchecked()
			.Edges = append(.Edges, )
			if  := .Step();  != nil {
				return 
			}
		}

		for ,  := range slices.Backward(.Children) {
			if  := .Step();  != nil {
				return 
			}
			 = append(, )
		}
	}
	return nil
}

func isIsolatedTreeGuarded( *layoutgraph.Graph,  *layoutgraph.Node,  *limits.WorkGuard) (bool, error) {
	if  == nil {
		return false, treePreprocessBadState("tree preprocessing encountered a nil tree sentinel")
	}
	if .IsContainer() {
		return false, nil
	}
	for ,  := range .Edges {
		if  := .Step();  != nil {
			return false, 
		}
		 := false
		for ,  := range .Trees[] {
			if  := .Step();  != nil {
				return false, 
			}
			if  != nil &&  == .SentinelEdge {
				 = true
				break
			}
		}
		if ! {
			return false, nil
		}
	}
	return true, nil
}

func buildNodeToTreeGuarded( *layoutgraph.Graph,  *limits.WorkGuard) error {
	 := make(map[*layoutgraph.Node]*layoutgraph.Tree)
	 := make([]*layoutgraph.Node, 0, len(.Trees))
	for  := range .Trees {
		if  := .Step();  != nil {
			return 
		}
		 = append(, )
	}
	layoutgraph.SortNodesByID()
	if  := .Check();  != nil {
		return 
	}
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		for ,  := range .Trees[] {
			if  == nil || .Node == nil {
				return treePreprocessBadState("tree sentinel contains an incomplete root")
			}
			 := []*layoutgraph.Tree{}
			 := make(map[*layoutgraph.Tree]struct{})
			for  := 0;  < len(); ++ {
				if  := .Step();  != nil {
					return 
				}
				 := []
				if  == nil || .Node == nil {
					return treePreprocessBadState("tree preprocessing encountered an incomplete tree")
				}
				if ,  := [];  {
					return treePreprocessBadState("tree preprocessing encountered a repeated tree node")
				}
				[] = struct{}{}
				[.Node] = 
				for ,  := range .Children {
					if  := .Step();  != nil {
						return 
					}
					 = append(, )
				}
			}
		}
	}
	.NodeToTree = 
	return .Check()
}