package placementcost

import (
	
	
	

	
	
)

const (
	scoringCancellationCheckInterval = 64
	sizelessDirectionDeltaFactor     = 0.25
	symmetryToleranceBand            = 1.0
)

const (
	// SideEdgeSpacing is the minimum spacing used to distinguish aligned side ports.
	SideEdgeSpacing = 40.0
	// IdealGapSize is the target separation between connected node boundaries.
	IdealGapSize = 2.5 * layoutgraph.ConnectedNodeGap
)

func scoringCancellationError( context.Context,  int) error {
	if %scoringCancellationCheckInterval != 0 {
		return nil
	}
	return checkScoringCancellation()
}

// Keep the interval check small enough to inline into the scoring loops. The
// context call and error formatting are only needed at a polling boundary.
func checkScoringCancellation( context.Context) error {
	if  := .Err();  != nil {
		return fmt.Errorf("EdgeLength: %w", )
	}
	return nil
}

type compassReading int

func directionCompass( geo.Orientation) compassReading {
	switch  {
	case geo.BottomLeft:
		return -3
	case geo.Left:
		return -2
	case geo.TopLeft:
		return -1
	case geo.Top:
		return 0
	case geo.TopRight:
		return 1
	case geo.Right:
		return 2
	case geo.BottomRight:
		return 3
	case geo.Bottom:
		return 4
	default:
		return 0
	}
}

func compassDelta(,  compassReading) compassReading {
	 :=  - 
	if  > 4 {
		 -= 8
	} else if  < -4 {
		 += 8
	}
	return 
}

func compassAxisDelta(,  compassReading) compassReading {
	 = ( + 4) % 4
	 = ( + 4) % 4
	 :=  - 
	if  == 3 {
		return -1
	}
	return 
}

func distanceToPoint( *layoutgraph.Node,  *geo.Point,  bool) float64 {
	 := geo.Box{TopLeft: .TopLeft}
	if  {
		.Width, .Height = .Width, .Height
	}
	 := geo.Box{TopLeft: }
	return distanceBetweenBoxes(, )
}

func placementDistance(,  *layoutgraph.Node,  bool) float64 {
	 := .DistanceTo(, )
	 := math.Abs(.TopLeft.X - .TopLeft.X)
	 := math.Abs(.TopLeft.Y - .TopLeft.Y)
	if  {
		 = math.Abs((.TopLeft.X+.Width/2)-(.TopLeft.X+.Width/2)) / (.Width + .Width)
		 = math.Abs((.TopLeft.Y+.Height/2)-(.TopLeft.Y+.Height/2)) / (.Height + .Height)
	}
	return  + math.Min(, )/20
}

func distanceBetweenBoxes(,  geo.Box) float64 {
	 := intervalGap(.TopLeft.X, .TopLeft.X+.Width, .TopLeft.X, .TopLeft.X+.Width)
	 := intervalGap(.TopLeft.Y, .TopLeft.Y+.Height, .TopLeft.Y, .TopLeft.Y+.Height)
	return geo.EuclideanDistance(0, 0, , )
}

func intervalGap(, , ,  float64) float64 {
	if  <  {
		return  - 
	}
	if  <  {
		return  - 
	}
	return 0
}

func sizelessOrientation(,  *layoutgraph.Node) geo.Orientation {
	if .TopLeft == nil || .TopLeft == nil {
		return geo.NONE
	}
	if .TopLeft.Y < .TopLeft.Y {
		if .TopLeft.X < .TopLeft.X {
			return geo.TopLeft
		}
		if .TopLeft.X < .TopLeft.X {
			return geo.TopRight
		}
		return geo.Top
	}
	if .TopLeft.Y < .TopLeft.Y {
		if .TopLeft.X < .TopLeft.X {
			return geo.BottomLeft
		}
		if .TopLeft.X < .TopLeft.X {
			return geo.BottomRight
		}
		return geo.Bottom
	}
	if .TopLeft.X < .TopLeft.X {
		return geo.Right
	}
	if .TopLeft.X < .TopLeft.X {
		return geo.Left
	}
	return geo.NONE
}

func depth( *layoutgraph.Node) int {
	if  == nil {
		return 0
	}
	return 1 + (.Container)
}

func distanceBetweenTableColumns( *layoutgraph.Graph,  *layoutgraph.Edge, ,  *layoutgraph.Node) float64 {
	, , , ,  := .FacingTablePortValues(, )
	if  == geo.NONE {
		if  == nil {
			 = .From
		}
		if  == nil {
			 = .To
		}
		,  := layoutgraph.Nodes{, }.BoundingBox()
		return 2 * geo.EuclideanDistance(.X, .Y, .X, .Y)
	}
	 := 2.0
	if  == geo.Left ||  == geo.Right {
		 = 1
	}
	if ! {
		 = geo.Point{
			X: .TopLeft.X + .Width/2,
			Y: .TopLeft.Y + .Height/2,
		}
	}
	if ! {
		 = geo.Point{
			X: .TopLeft.X + .Width/2,
			Y: .TopLeft.Y + .Height/2,
		}
	}
	 := 0.0
	if math.Abs(.X-.X) < IdealGapSize {
		 = 2 * .CellSize
	}
	return  * ( + geo.EuclideanDistance(.X, .Y, .X, .Y))
}