package placement

import (
	
	
	

	
	
	
	
)

func initializeNodes( context.Context,  *layoutgraph.Graph) ( error) {
	if  := layoutgraph.Validate(, "InitializeNodes", );  != nil {
		return 
	}
	if len(.Nodes) == 0 {
		return nil
	}
	,  := snapshotNodePositionsContext(, "InitializeNodes", .Nodes)
	if  != nil {
		return 
	}
	 := false
	defer func() {
		if ! {
			restoreNodePositions()
		}
	}()
	,  := limits.NewWorkGuard(, "InitializeNodesReachability", limits.MaxEngineWorkUnits)
	if  != nil {
		return 
	}
	 := .CellSize * compactionFactor

	 := func( *layoutgraph.Node) error {
		if  := .Err();  != nil {
			return fmt.Errorf("InitializeNodes: %w", )
		}
		if .TopLeft != nil {
			return nil
		}

		 := math.Inf(1)
		 := .TopLeft

		,  := newSizelessOptimizer(, , nil)
		if  != nil {
			return 
		}
		,  := nodeCandidatePositions(, , , )
		if  != nil {
			return 
		}
		for ,  := range  {
			,  := occupied(, )
			if  {
				continue
			}

			.TopLeft = 

			,  := placementcost.NodeEdgeLength(, , placementcost.EdgeLengthOptions{EdgeAbductions: nil, IncludeNodeSizes: false, EnforceMinimumGap: false, PenalizeDirection: true})
			if  != nil {
				.TopLeft = nil
				return 
			}

			if  <  {
				 = 
				 = 
			}

			.TopLeft = nil
		}

		.TopLeft = 
		return nil
	}

	// the first subgraph has all the fixed node subgraphs (each may be disconnected)
	if .HasFixedNode() {
		 := .FixedNodes()
		 := make([]*layoutgraph.Node, 0, len())

		for ,  := range  {
			,  := .AllReachableNodesContext(false, true, true, nil, )
			if  != nil {
				return 
			}
			 = append(, ...)
			for ,  := range  {
				.TopLeft = nil
			}
		}

		for ,  := range  {
			.TopLeft = geo.NewPoint(
				math.Ceil(.FixedTopLeft.X/),
				math.Ceil(.FixedTopLeft.Y/),
			)
		}

		for ,  := range  {
			if  := ();  != nil {
				return 
			}
		}
	} else {
		,  := .Nodes[0].AllReachableNodesContext(false, true, true, nil, )
		if  != nil {
			return 
		}

		for ,  := range [1:] {
			.TopLeft = nil
		}
		.Nodes[0].TopLeft = geo.NewPoint(float64(len(.Nodes)), float64(len(.Nodes)))

		for ,  := range [1:] {
			if  := ();  != nil {
				return 
			}
		}
	}

	for ,  := range .Nodes {
		if .TopLeft == nil {
			return fmt.Errorf("missed initializing node %v", .DebugID())
		}
	}

	if  := .Finish();  != nil {
		return 
	}
	 = true
	return nil
}

func nodeCandidatePositions( context.Context,  *layoutgraph.Node,  *layoutgraph.Graph,  *sizelessOptimizer) ( []*geo.Point,  error) {
	,  := medianToNeighbors(, false, nil)
	 := math.Floor()
	 := math.Floor()
	,  := .FindClosestUnoccupiedDistance(, , geo.NewPoint(, ))
	if  != nil {
		return nil, 
	}
	 :=  -  - 2
	 :=  -  - 2
	 :=  +  + 2
	 :=  +  + 2
	if .HasFixedNode() {
		 = max(, 0)
		 = max(, 0)
	}

	if .IsMajorityTarget() {
		// if it's, mainly, a target node, give preference to place it to bottom-right
		for  := ;  >= ; -- {
			for  := ;  >= ; -- {
				 = append(, geo.NewPoint(, ))
			}
		}
	} else {
		for  := ;  <= ; ++ {
			for  := ;  <= ; ++ {
				 = append(, geo.NewPoint(, ))
			}
		}
	}

	return , nil
}