package hierarchy

import (
	
	
	
)

// Candidates identifies the graph nodes that may participate in hierarchy
// discovery. Existing hierarchy membership is derived state and deliberately
// does not disqualify a node, so repeated layouts can reconsider topology and
// edge-direction changes.
func ( *layoutgraph.Graph) map[*layoutgraph.Node]struct{} {
	 := make(map[*layoutgraph.Node]struct{})
	for ,  := range .Nodes {
		if ,  := .NodeToTree[];  {
			continue
		}
		if .IsTreeSentinel() || .Sequence != nil || .FixedTopLeft != nil {
			continue
		}
		if isSimpleCandidate(, ) {
			[] = struct{}{}
			continue
		}
		if .IsContainer() && shapeCanBeContainer(.Shape) && !.AspectRatio1() && isEligibleContainer(, ) {
			[] = struct{}{}
		}
	}
	return 
}

func isSimpleCandidate( *layoutgraph.Graph,  *layoutgraph.Node) bool {
	return !(.IsContainer() || .IsTreeSentinel() || .IsClusterVessel() ||
		.IsSequenceVessel() || .Cluster != nil)
}

// Hierarchy containers grow only horizontally. These shapes can grow in one
// direction without distorting their visual meaning.
func shapeCanBeContainer( nodeshape.Shape) bool {
	switch .GetType() {
	case "", shape.SQUARE_TYPE, shape.PACKAGE_TYPE, shape.STORED_DATA_TYPE, shape.QUEUE_TYPE, shape.STEP_TYPE:
		return true
	default:
		return false
	}
}

// A container can participate only when it has no internal edges and none of
// its descendants belongs to another specialized layout structure.
func isEligibleContainer( *layoutgraph.Graph,  *layoutgraph.Node) bool {
	for ,  := range .Containers[] {
		if .FixedTopLeft != nil {
			return false
		}
		if ,  := .NodeToTree[];  {
			return false
		}
		if .IsTreeSentinel() || .Sequence != nil {
			return false
		}
		if !.IsContainer() && !isSimpleCandidate(, ) {
			return false
		}
		for ,  := range .Edges {
			if !isHierarchyStructuralEdge() {
				continue
			}
			if .Adjacent().IsDescendantOf() {
				return false
			}
		}
		if .IsContainer() && !(, ) {
			return false
		}
	}
	return true
}