package placement

import (
	
	

	
	
	
)

func swapPositions( *layoutgraph.Node,  *layoutgraph.Node) {
	 := .TopLeft.X
	 := .TopLeft.Y

	.MoveWithChildren(
		.TopLeft.X-.TopLeft.X,
		.TopLeft.Y-.TopLeft.Y,
	)

	.MoveWithChildren(
		-.TopLeft.X,
		-.TopLeft.Y,
	)
}

func smartSwapPositions( *layoutgraph.Node,  *layoutgraph.Node) {
	 := .TopLeft.X
	 := .TopLeft.Y

	 := .Orientation()
	if  == geo.Left {
		.MoveAbsWithChildren(.TopLeft.X+.Width-.Width, .TopLeft.Y)
		.MoveAbsWithChildren(, .TopLeft.Y)
	} else if  == geo.Right {
		.MoveAbsWithChildren(.TopLeft.X, .TopLeft.Y)
		.MoveAbsWithChildren(+.Width-.Width, .TopLeft.Y)
	} else if  == geo.Top {
		.MoveAbsWithChildren(.TopLeft.X, .TopLeft.Y+.Height-.Height)
		.MoveAbsWithChildren(.TopLeft.X, )
	} else if  == geo.Bottom {
		.MoveAbsWithChildren(.TopLeft.X, .TopLeft.Y)
		.MoveAbsWithChildren(.TopLeft.X, +.Height-.Height)
	} else if  == geo.TopLeft {
		.MoveAbsWithChildren(.TopLeft.X+.Width-.Width, .TopLeft.Y+.Height-.Height)
		.MoveAbsWithChildren(, )
	} else if  == geo.TopRight {
		.MoveAbsWithChildren(.TopLeft.X, .TopLeft.Y+.Height-.Height)
		.MoveAbsWithChildren(+.Width-.Width, )
	} else if  == geo.BottomLeft {
		.MoveAbsWithChildren(.TopLeft.X+.Width-.Width, .TopLeft.Y)
		.MoveAbsWithChildren(, +.Height-.Height)
	} else if  == geo.BottomRight {
		.MoveAbsWithChildren(.TopLeft.X, .TopLeft.Y)
		.MoveAbsWithChildren(+.Width-.Width, +.Height-.Height)
	}
}

// swapOptimize swaps node positions when doing so lowers placement cost.
func swapOptimize( context.Context,  layoutgraph.Nodes,  *layoutgraph.Graph) (bool, error) {
	, ,  := layoutgraph.EnsureTransactionWorkGuard(, "SwapOptimizeTransactions")
	if  != nil {
		return false, 
	}
	 := .CellSize
	 := false

	 := func( *layoutgraph.Node) (float64, error) {
		,  := placementcost.NodeEdgeLength(, , placementcost.EdgeLengthOptions{EdgeAbductions: nil, IncludeNodeSizes: true, EnforceMinimumGap: false, PenalizeDirection: true})
		if  != nil {
			return 0, 
		}
		,  := placementcost.ColumnCrossingCost(, , nil)
		if  != nil {
			return 0, 
		}
		,  := placementcost.NodeSymmetry(, , nil)
		if  != nil {
			return 0, 
		}
		 += 
		 -=  *  * float64(len(.Edges))
		return , nil
	}

	,  := .NewRequestTransaction(, layoutgraph.TransactionOptions{AffectContainers: true})
	if  != nil {
		return false, 
	}
	for ,  := range  {
		if ,  := .NodeToTree[];  {
			continue
		}
		if .Hierarchy != nil {
			continue
		}
		if .FixedTopLeft != nil {
			continue
		}
		if len(.Edges) == 0 && !.HasLeakyEdge() {
			continue
		}

		 := false
		var  *layoutgraph.Node
		 := math.Inf(1)

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

		for ,  := range .Containers[.Container] {
			if  ==  {
				continue
			}
			if ,  := .NodeToTree[];  {
				continue
			}
			if .Hierarchy != nil {
				continue
			}
			if .FixedTopLeft != nil {
				continue
			}

			.AddOp(func() error {
				swapPositions(, )

				return nil
			})

			var  float64
			var  float64
			var  int64
			 = .Commit()
			if  == nil {
				,  = ()
				if  == nil {
					,  = placementcost.EdgeLength(, , placementcost.EdgeLengthOptions{EdgeAbductions: nil, IncludeNodeSizes: true, EnforceMinimumGap: false, PenalizeDirection: true})
				}
				if  == nil {
					,  = placementcost.GraphEdgeCrossings(, )
				}
				if  != nil {
					.Rollback()
					.Clear()
					return false, 
				}
			} else if !layoutgraph.IsCandidateRejection() {
				return false, 
			}

			.Rollback()
			.Clear()

			.AddOp(func() error {
				smartSwapPositions(, )

				return nil
			})

			 = .Commit()

			var  float64
			var  float64
			var  int64
			if  == nil {
				,  = ()
				if  == nil {
					,  = placementcost.EdgeLength(, , placementcost.EdgeLengthOptions{EdgeAbductions: nil, IncludeNodeSizes: true, EnforceMinimumGap: false, PenalizeDirection: true})
				}
				if  == nil {
					,  = placementcost.GraphEdgeCrossings(, )
				}
				if  != nil {
					.Rollback()
					.Clear()
					return false, 
				}
			} else if !layoutgraph.IsCandidateRejection() {
				return false, 
			}

			.Rollback()
			.Clear()

			if  == 0 &&  == 0 {
				continue
			}
			if  != 0 &&  == 0 {
				if  <=  && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 {
					 = 
					 = false
					 = 
				}
			} else if  != 0 &&  == 0 {
				if  <=  && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 {
					 = 
					 = true
					 = 
				}
			} else if  != 0 &&  != 0 {
				if geo.PrecisionCompare(, , geo.PRECISION) < 0 {
					if  <=  && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 {
						 = 
						 = true
						 = 
					}
				} else {
					if  <=  && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 {
						 = 
						 = false
						 = 
					}
				}
			} else {
				// They can both be 0 if the node is just a container, in which case we compare globals
				if  != 0 &&  == 0 {
					if  <=  && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 {
						 = 
						 = false
						 = 
					}
				} else if  == 0 &&  != 0 {
					if  <=  && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 {
						 = 
						 = true
						 = 
					}
				} else {
					if geo.PrecisionCompare(, , geo.PRECISION) < 0 {
						if  <=  && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 {
							 = 
							 = false
							 = 
						}
					} else {
						if  <=  && geo.PrecisionCompare(, , geo.PRECISION) < 0 && geo.PrecisionCompare(, , geo.PRECISION) < 0 {
							 = 
							 = true
							 = 
						}
					}
				}
			}
		}

		if  != nil {
			 = true
			.AddOp(func() error {
				if  {
					smartSwapPositions(, )
				} else {
					swapPositions(, )
				}
				return nil
			})
			 := .Commit()
			if  != nil {
				return false, 
			}
			.Clear()
			if  := .UpdateState();  != nil {
				return false, 
			}
		}
	}

	return , nil
}