package proximity

import (
	
	

	
	
	
)

// AssignNears marks otherwise unconnected siblings that share an external
// neighbor so placement keeps them close together.
func ( context.Context,  *layoutgraph.Graph,  *layoutgraph.Node,  []*layoutgraph.EdgeAbduction) error {
	return assignNearsWithWorkLimit(, , , , limits.MaxEngineWorkUnits)
}

func assignNearsWithWorkLimit( context.Context,  *layoutgraph.Graph,  *layoutgraph.Node,  []*layoutgraph.EdgeAbduction,  int64) ( error) {
	,  := limits.NewWorkGuard(, "AssignNears", )
	if  != nil {
		return 
	}
	 := make(map[*layoutgraph.Node]map[*layoutgraph.Node]struct{})
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		if  == nil {
			return invariant.New("nil edge abduction while assigning nears")
		}
		 := groupVessel(.OriginallyFrom)
		 := groupVessel(.OriginallyTo)
		var ,  *layoutgraph.Node
		for ,  := range .Containers[] {
			if  := .Step();  != nil {
				return 
			}
			,  := isDescendantOf(, , )
			if  != nil {
				return 
			}
			,  := isDescendantOf(, , )
			if  != nil {
				return 
			}
			if  {
				,  = .CurrentTo, 
				break
			} else if  {
				,  = .CurrentFrom, 
				break
			}
		}
		if  != nil &&  != nil {
			if [] == nil {
				[] = make(map[*layoutgraph.Node]struct{})
			}
			[][] = struct{}{}
		}
	}

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

	 := make(map[*layoutgraph.Node]map[*layoutgraph.Node]struct{})
	 := make(map[*layoutgraph.Node]map[*layoutgraph.Node]struct{})
	var  int64
	 := func( *layoutgraph.Node) (map[*layoutgraph.Node]struct{}, error) {
		if ,  := [];  {
			return , nil
		}
		if int64(len(.Nears)) > layoutgraph.MaxTopologyReferences- {
			return nil, fmt.Errorf("TALA AssignNears topology references exceed limit %d", layoutgraph.MaxTopologyReferences)
		}
		 += int64(len(.Nears))
		[] = .Nears
		 := make(map[*layoutgraph.Node]struct{}, len(.Nears)+1)
		for  := range .Nears {
			if  := .Step();  != nil {
				return nil, 
			}
			[] = struct{}{}
		}
		[] = 
		return , nil
	}
	 := func(,  *layoutgraph.Node) (bool, error) {
		for ,  := range .Edges {
			if  := .Step();  != nil {
				return false, 
			}
			if  != nil && .Adjacent() ==  {
				return true, nil
			}
		}
		return false, nil
	}

	for ,  := range  {
		 := make([]*layoutgraph.Node, 0, len([]))
		for  := range [] {
			if  := .Step();  != nil {
				return 
			}
			 = append(, )
		}
		layoutgraph.SortNodesByID()
		if len() == 1 {
			continue
		}
		for ,  := range  {
			for ,  := range [+1:] {
				if  := .Step();  != nil {
					return 
				}
				if .Hierarchy != nil || .Hierarchy != nil {
					continue
				}
				,  := (, )
				if  != nil {
					return 
				}
				if  {
					continue
				}
				,  := ()
				if  != nil {
					return 
				}
				,  := ()
				if  != nil {
					return 
				}
				if ,  := []; ! {
					if  >= layoutgraph.MaxTopologyReferences {
						return fmt.Errorf("TALA AssignNears topology references exceed limit %d", layoutgraph.MaxTopologyReferences)
					}
					[] = struct{}{}
					++
				}
				if ,  := []; ! {
					if  >= layoutgraph.MaxTopologyReferences {
						return fmt.Errorf("TALA AssignNears topology references exceed limit %d", layoutgraph.MaxTopologyReferences)
					}
					[] = struct{}{}
					++
				}
			}
		}
	}
	if  := .Finish();  != nil {
		return 
	}

	 := false
	defer func() {
		if  := recover();  != nil {
			for ,  := range  {
				.Nears = 
			}
			panic()
		}
		if ! {
			for ,  := range  {
				.Nears = 
			}
		}
	}()
	 := make([]*layoutgraph.Node, 0, len())
	for  := range  {
		 = append(, )
	}
	layoutgraph.SortNodesByID()
	for ,  := range  {
		.Nears = []
		if  := .Finish();  != nil {
			return 
		}
	}
	 = true
	return nil
}

func groupVessel( *layoutgraph.Node) *layoutgraph.Node {
	if  == nil {
		return nil
	}
	if .Cluster != nil {
		return .Cluster.Vessel
	}
	if .Sequence != nil {
		return .Sequence.Vessel
	}
	return 
}

func isDescendantOf(,  *layoutgraph.Node,  *limits.WorkGuard) (bool, error) {
	for {
		if  := .Step();  != nil {
			return false, 
		}
		if  ==  {
			return true, nil
		}
		if  == nil {
			return false, nil
		}
		switch {
		case .Container != nil:
			 = .Container
		case .Cluster != nil:
			 = .Cluster.Vessel
		case .Sequence != nil:
			 = .Sequence.Vessel
		default:
			 = nil
		}
	}
}