package grouping

import (
	
	
	
	
	
	

	
	
	
	
)

// AssignArrangement selects the cluster axis from node dimensions. Randomness
// is consumed only for square clusters, preserving the engine's seed contract.
func ( *layoutgraph.Cluster,  bool,  *rand.Rand) layoutgraph.ClusterArrangement {
	,  := averageClusterDimensions()
	if  {
		return layoutgraph.Row
	}
	if  >  {
		return layoutgraph.Column
	}
	if  <  {
		return layoutgraph.Row
	}
	if .Float64() > 0.5 {
		return layoutgraph.Column
	}
	return layoutgraph.Row
}

func averageClusterDimensions( *layoutgraph.Cluster) (,  float64) {
	for ,  := range .Nodes {
		 += .Width
		 += .Height
	}
	 := float64(len(.Nodes))
	return math.Round( / ), math.Round( / )
}

// PaddingBetween calculates the spacing between adjacent cluster members.
func ( *layoutgraph.Cluster,  bool) float64 {
	,  := averageClusterDimensions()
	 := false
	var ,  float64
	for ,  := range .Nodes {
		 =  || .Icon != nil
		if .Label != nil {
			 = math.Max(, .Label.Width)
			 = math.Max(, .Label.Height)
		}
	}
	var  float64
	if .Arrangement == layoutgraph.Row {
		 = math.Max(layoutgraph.NodeGap, math.Ceil()*0.1)
		if  {
			 = math.Max(, 2*label.PADDING+)
		}
	} else {
		 = math.Max(layoutgraph.NodeGap, math.Ceil()*0.1)
		if  {
			 = math.Max(, 2*label.PADDING+)
		}
	}
	if  {
		var  float64
		for  := 0;  < len(.Nodes)-1; ++ {
			 += .Nodes[].DistanceTo(.Nodes[+1], true)
		}
		 :=  / float64(len(.Nodes)-1)
		if  > 0 {
			return math.Round(math.Min(, ))
		}
	}
	return math.Round()
}

// CreateVessel builds the temporary placement node representing a cluster.
func ( *layoutgraph.Cluster,  layoutgraph.EntityID) *layoutgraph.Node {
	,  := math.Inf(1), math.Inf(1)
	for ,  := range .Nodes {
		if .TopLeft != nil {
			 = math.Min(, .TopLeft.X)
			 = math.Min(, .TopLeft.Y)
		}
	}
	 := layoutgraph.NewNode(, 0, 0)
	.SetClusterVessel(true)
	.Resize()
	if .Arrangement == layoutgraph.Row {
		if !math.IsInf(, 1) && !math.IsInf(, 1) {
			sort.Slice(.Nodes, func(,  int) bool { return .Nodes[].TopLeft.X < .Nodes[].TopLeft.X })
			.TopLeft = geo.NewPoint(, )
		}
	}
	if .Arrangement == layoutgraph.Column {
		if !math.IsInf(, 1) && !math.IsInf(, 1) {
			sort.Slice(.Nodes, func(,  int) bool { return .Nodes[].TopLeft.Y < .Nodes[].TopLeft.Y })
			.TopLeft = geo.NewPoint(, )
		}
	}
	return 
}

// AddCluster installs a discovered cluster and its temporary vessel into the
// mutable layout graph.
func ( *layoutgraph.Graph,  *layoutgraph.Cluster) {
	.AddNewNodeToContainer(.Container, .Vessel)
	for ,  := range .Nodes {
		.Cluster = 
	}
	var  []*layoutgraph.Node
	for ,  := range .Containers[.Container] {
		if .Cluster !=  {
			 = append(, )
		}
	}
	.Containers[.Container] = 
	for ,  := range .Nodes {
		.RemoveNode()
		.Container = nil
	}
	.Clusters[.Vessel] = 
}

func abductClusterEdges( *layoutgraph.Cluster,  []*layoutgraph.Edge,  *limits.WorkGuard) error {
	var  []*layoutgraph.EdgeAbduction
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		if .From.Cluster ==  {
			for range len(.From.Edges) + len(.Vessel.Edges) {
				if  := .Step();  != nil {
					return 
				}
			}
			 = append(, &layoutgraph.EdgeAbduction{
				Edge: , OriginallyFrom: .From,
				CurrentFrom: .Vessel, CurrentTo: .To,
			})
			.Reconnect(.Vessel, false)
		}
		if .To.Cluster ==  {
			for range len(.To.Edges) + len(.Vessel.Edges) {
				if  := .Step();  != nil {
					return 
				}
			}
			 = append(, &layoutgraph.EdgeAbduction{
				Edge: , OriginallyTo: .To,
				CurrentTo: .Vessel, CurrentFrom: .From,
			})
			.Reconnect(.Vessel, true)
		}
	}
	.EdgeAbductions = 
	return .Finish()
}

// AddClusters discovers interchangeable sibling nodes and replaces accepted
// groups with temporary vessels for node placement.
func ( context.Context,  *layoutgraph.Graph,  int64,  *rand.Rand) ( error) {
	if  == nil {
		return fmt.Errorf("TALA AddClusters requires a graph")
	}
	if  == nil {
		return fmt.Errorf("TALA AddClusters requires a random generator")
	}
	if  := layoutgraph.Validate(, "AddClusters", );  != nil {
		return 
	}
	, ,  := layoutgraph.EnsureTransactionWorkGuard(, "AddClustersTransactions")
	if  != nil {
		return 
	}
	,  := .ContainerRDFSOrder(nil, )
	if  != nil {
		return 
	}

	 := layoutgraph.NewGraphStateSnapshot(layoutgraph.GraphStateSnapshotOptions{
		CaptureTopology:   true,
		CaptureEdgeRoutes: true,
	})
	if  := .UpdateWithWorkGuard(, );  != nil {
		return 
	}
	 := false
	defer func() {
		if  := recover();  != nil {
			layoutgraph.RestoreGraphState(, )
			panic()
		}
		if ! {
			layoutgraph.RestoreGraphState(, )
		}
	}()

	if .Clusters == nil {
		.Clusters = map[*layoutgraph.Node]*layoutgraph.Cluster{}
	} else {
		clear(.Clusters)
	}
	,  := buildClusterDiscoveryIndex(, , )
	if  != nil {
		return 
	}
	 := .infos
	 := .edgeOrder
	 := make(map[layoutgraph.EntityID]struct{}, len(.Nodes))
	for ,  := range .Nodes {
		if  := .Step();  != nil {
			return 
		}
		[.ID] = struct{}{}
	}
	for ,  := range .SequenceOrder() {
		if  := .Step();  != nil {
			return 
		}
		[.ID] = struct{}{}
		for ,  := range .Sequences[].Nodes {
			if  := .Step();  != nil {
				return 
			}
			[.ID] = struct{}{}
		}
	}
	 := make(map[*layoutgraph.Tree]struct{})
	for ,  := range .TreeOrder() {
		if  := .Step();  != nil {
			return 
		}
		if  != nil {
			[.ID] = struct{}{}
		}
		 := slices.Clone(.Trees[])
		for len() > 0 {
			if  := .Step();  != nil {
				return 
			}
			 := len() - 1
			 := []
			 = [:]
			if  == nil {
				continue
			}
			if ,  := [];  {
				continue
			}
			[] = struct{}{}
			if .Node != nil {
				[.Node.ID] = struct{}{}
			}
			 = append(, .Children...)
		}
	}
	 := func( layoutgraph.EntityID) (layoutgraph.EntityID, error) {
		for {
			if  := .Step();  != nil {
				return 0, 
			}
			if ,  := []; ! {
				return , nil
			}
			if  == math.MaxInt64 {
				 = 0
			} else {
				++
			}
		}
	}
	 := func( *layoutgraph.Cluster) error {
		for range .Nodes {
			for range .Nodes {
				if  := .Step();  != nil {
					return 
				}
			}
		}
		for  := 1;  < len(.Nodes);  *= 2 {
			for range .Nodes {
				if  := .Step();  != nil {
					return 
				}
			}
			if  > len(.Nodes)/2 {
				break
			}
		}
		return .Finish()
	}

	 := func( *layoutgraph.Cluster,  layoutgraph.ClusterArrangement) (bool, error) {
		for ,  := range .Nodes {
			if  := .Step();  != nil {
				return false, 
			}
			for ,  := range .Edges {
				if  := .Step();  != nil {
					return false, 
				}
				,  := clusterIsDescendantOfGuarded(, .Adjacent(), )
				if  != nil {
					return false, 
				}
				if  {
					return false, nil
				}
			}
		}
		,  := (.Int63())
		if  != nil {
			return false, 
		}
		,  := clusterIncidentEdges(, , , )
		if  != nil {
			return false, 
		}
		if  := ();  != nil {
			return false, 
		}
		.Arrangement = 
		.DesiredArrangement = 
		.Padding = PaddingBetween(, false)
		 := CreateVessel(, )
		.Vessel = 
		AddCluster(, )
		if  := .Step();  != nil {
			return false, 
		}
		if  := abductClusterEdges(, , );  != nil {
			return false, 
		}
		if  := .refreshAfterClusterAbduction(, , , );  != nil {
			return false, 
		}
		[] = struct{}{}
		for ,  := range .Nodes {
			if  := .Step();  != nil {
				return false, 
			}
			[.ID] = struct{}{}
		}
		return true, nil
	}

	const  = 4.0
	 := func( *layoutgraph.Node) error {
		if  == nil || !.IsContainer() {
			return nil
		}
		 := []
		if  == nil {
			return fmt.Errorf("TALA AddClusters cannot find container discovery index")
		}
		 := .ContainerPadding(, true)
		var ,  float64
		for ,  := range .Containers[] {
			if  := .Step();  != nil {
				return 
			}
			,  := .Width, .Height
			if  := [];  != nil {
				 = .estimatedWidth
				 = .estimatedHeight
			}
			 += 
			 += 
		}
		.estimatedWidth = max(.Width, +.Left()+.Right())
		.estimatedHeight = max(.Height, +.Top()+.Bottom())
		return .Finish()
	}
	 := append(slices.Clone(), nil)
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		 := rand.New(rand.NewSource())
		 := .Containers[]
		for ,  := range  {
			if  := .Step();  != nil {
				return 
			}
			 := []
			if  == nil {
				return fmt.Errorf("TALA AddClusters cannot find node discovery index")
			}
			if .noClustering || .Cluster != nil {
				continue
			}
			 := false
			for ,  := range .Edges {
				if  := .Step();  != nil {
					return 
				}
				if  := .Adjacent();  != nil && .IsClusterVessel() {
					 = true
					break
				}
			}
			if  || .toTableColumn {
				continue
			}
			 := []*layoutgraph.Node{}
			 := false
			for ,  := range  {
				if  := .Step();  != nil {
					return 
				}
				if  ==  || !.SameShape() {
					continue
				}
				 := []
				if  == nil {
					return fmt.Errorf("TALA AddClusters cannot find comparison-node discovery index")
				}
				if .noClustering || .Cluster != nil || .toTableColumn {
					continue
				}
				if *.estimatedWidth < .estimatedWidth ||
					*.estimatedWidth < .estimatedWidth ||
					*.estimatedHeight < .estimatedHeight ||
					*.estimatedHeight < .estimatedHeight {
					continue
				}
				 := len(.neighbors) > 0 && len(.neighbors) == len(.neighbors)
				if  {
					for ,  := range .neighbors {
						if  := .Step();  != nil {
							return 
						}
						 =  ||  != nil && .Sequence != nil
						if ,  := .neighborSet[]; ! {
							 = false
							break
						}
					}
				}
				if  && .edgeSignature.matches(.edgeSignature) {
					 = append(, )
				}
			}
			if len() <= 1 {
				continue
			}
			 := &layoutgraph.Cluster{Nodes: , Container: , Graph: }
			for ,  := range  {
				if  := .Step();  != nil {
					return 
				}
				if .AspectRatio1() {
					.FixedSize = true
					break
				}
			}
			if  := ();  != nil {
				return 
			}
			 := AssignArrangement(, , )
			,  := (, )
			if  != nil {
				return 
			}
			if ! {
				if ,  := (, .Flip());  != nil {
					return 
				}
			}
		}
		if  := ();  != nil {
			return 
		}
	}
	if  := .Finish();  != nil {
		return 
	}
	 = true
	return nil
}