text: package containernode
  
  import (
  	"math/rand"
  	"sort"
  
  	"github.com/onsi/ginkgo/internal/leafnodes"
  	"github.com/onsi/ginkgo/types"
  )
  
  type subjectOrContainerNode struct {
  	containerNode *ContainerNode
  	subjectNode   leafnodes.SubjectNode
  }
  
  func (n subjectOrContainerNode) text() string {
  	if n.containerNode != nil {
  		return n.containerNode.Text()
  	} else {
  		return n.subjectNode.Text()
  	}
  }
  
  type CollatedNodes struct {
  	Containers []*ContainerNode
  	Subject    leafnodes.SubjectNode
  }
  
  type ContainerNode struct {
  	text         string
  	flag         types.FlagType
  	codeLocation types.CodeLocation
  
  	setupNodes               []leafnodes.BasicNode
  	subjectAndContainerNodes []subjectOrContainerNode
  }
  
  func New(text string, flag types.FlagType, codeLocation types.CodeLocation) *ContainerNode {
  	return &ContainerNode{
  		text:         text,
  		flag:         flag,
  		codeLocation: codeLocation,
  	}
  }
  
  func (container *ContainerNode) Shuffle(r *rand.Rand) {
  	sort.Sort(container)
  	permutation := r.Perm(len(container.subjectAndContainerNodes))
  	shuffledNodes := make([]subjectOrContainerNode, len(container.subjectAndContainerNodes))
  	for i, j := range permutation {
  		shuffledNodes[i] = container.subjectAndContainerNodes[j]
  	}
  	container.subjectAndContainerNodes = shuffledNodes
  }
  
  func (node *ContainerNode) BackPropagateProgrammaticFocus() bool {
  	if node.flag == types.FlagTypePending {
  		return false
  	}
  
  	shouldUnfocus := false
  	for _, subjectOrContainerNode := range node.subjectAndContainerNodes {
  		if subjectOrContainerNode.containerNode != nil {
  			shouldUnfocus = subjectOrContainerNode.containerNode.BackPropagateProgrammaticFocus() || shouldUnfocus
  		} else {
  			shouldUnfocus = (subjectOrContainerNode.subjectNode.Flag() == types.FlagTypeFocused) || shouldUnfocus
  		}
  	}
  
  	if shouldUnfocus {
  		if node.flag == types.FlagTypeFocused {
  			node.flag = types.FlagTypeNone
  		}
  		return true
  	}
  
  	return node.flag == types.FlagTypeFocused
  }
  
  func (node *ContainerNode) Collate() []CollatedNodes {
  	return node.collate([]*ContainerNode{})
  }
  
  func (node *ContainerNode) collate(enclosingContainers []*ContainerNode) []CollatedNodes {
  	collated := make([]CollatedNodes, 0)
  
  	containers := make([]*ContainerNode, len(enclosingContainers))
  	copy(containers, enclosingContainers)
  	containers = append(containers, node)
  
  	for _, subjectOrContainer := range node.subjectAndContainerNodes {
  		if subjectOrContainer.containerNode != nil {
  			collated = append(collated, subjectOrContainer.containerNode.collate(containers)...)
  		} else {
  			collated = append(collated, CollatedNodes{
  				Containers: containers,
  				Subject:    subjectOrContainer.subjectNode,
  			})
  		}
  	}
  
  	return collated
  }
  
  func (node *ContainerNode) PushContainerNode(container *ContainerNode) {
  	node.subjectAndContainerNodes = append(node.subjectAndContainerNodes, subjectOrContainerNode{containerNode: container})
  }
  
  func (node *ContainerNode) PushSubjectNode(subject leafnodes.SubjectNode) {
  	node.subjectAndContainerNodes = append(node.subjectAndContainerNodes, subjectOrContainerNode{subjectNode: subject})
  }
  
  func (node *ContainerNode) PushSetupNode(setupNode leafnodes.BasicNode) {
  	node.setupNodes = append(node.setupNodes, setupNode)
  }
  
  func (node *ContainerNode) SetupNodesOfType(nodeType types.SpecComponentType) []leafnodes.BasicNode {
  	nodes := []leafnodes.BasicNode{}
  	for _, setupNode := range node.setupNodes {
  		if setupNode.Type() == nodeType {
  			nodes = append(nodes, setupNode)
  		}
  	}
  	return nodes
  }
  
  func (node *ContainerNode) Text() string {
  	return node.text
  }
  
  func (node *ContainerNode) CodeLocation() types.CodeLocation {
  	return node.codeLocation
  }
  
  func (node *ContainerNode) Flag() types.FlagType {
  	return node.flag
  }
  
  //sort.Interface
  
  func (node *ContainerNode) Len() int {
  	return len(node.subjectAndContainerNodes)
  }
  
  func (node *ContainerNode) Less(i, j int) bool {
  	return node.subjectAndContainerNodes[i].text() < node.subjectAndContainerNodes[j].text()
  }
  
  func (node *ContainerNode) Swap(i, j int) {
  	node.subjectAndContainerNodes[i], node.subjectAndContainerNodes[j] = node.subjectAndContainerNodes[j], node.subjectAndContainerNodes[i]
  }
  