package quality

import (
	
	
	

	
	

	
	
	
)

func scoreExistingLabelPlacements( *layoutgraph.Graph,  *limits.WorkGuard) (float64, error) {
	if  := .Step();  != nil {
		return 0, 
	}

	var  []geo.Box
	 := 0.0

	// Arrowhead labels and loop labels reserve space before ordinary node and
	// edge labels are scored.
	for ,  := range .Edges {
		if  := .Step();  != nil {
			return 0, 
		}
		if .SourceArrowheadLabel != nil {
			if  := chargeEvaluationWork(, len(.Points));  != nil {
				return 0, 
			}
			 = append(, labeling.PositionArrowheadLabel(, false, .Points).Box)
		}
		if .TargetArrowheadLabel != nil {
			if  := chargeEvaluationWork(, len(.Points));  != nil {
				return 0, 
			}
			 = append(, labeling.PositionArrowheadLabel(, true, .Points).Box)
		}
	}

	for ,  := range .Edges {
		if  := .Step();  != nil {
			return 0, 
		}
		if .IsLoop() && .Label != nil {
			if  := chargeEvaluationWork(, len(.Points));  != nil {
				return 0, 
			}
			 = append(, labelBox())
		}
	}

	for ,  := range .Nodes {
		if  := .Step();  != nil {
			return 0, 
		}

		if .Icon != nil && !.IsImage() {
			 := .IconSize(.Icon.Position)
			 := geo.Box{
				TopLeft: .LabelTopLeft(.Icon.Position, , ),
				Width:   ,
				Height:  ,
			}
			 = append(, )

			,  := nodeOverlapCount(, .Nodes, 0, )
			if  != nil {
				return 0, 
			}
			,  := edgeOverlapCount(, .Edges, 0, )
			if  != nil {
				return 0, 
			}
			,  := boxOverlapCount(, , 0, )
			if  != nil {
				return 0, 
			}
			 += scoreNodeLabelOverlaps(, , -1)
		}

		if .Label == nil {
			continue
		}
		 := geo.Box{
			TopLeft: .LabelTopLeft(.Label.Position, .Label.Width, .Label.Height),
			Width:   .Label.Width,
			Height:  .Label.Height,
		}

		var  []*layoutgraph.Node
		for ,  := range .Containers[.Container] {
			if  := .Step();  != nil {
				return 0, 
			}
			if  !=  {
				 = append(, )
			}
		}
		if .IsContainer() {
			for ,  := range .Containers[] {
				if  := .Step();  != nil {
					return 0, 
				}
				 = append(, )
			}
		}

		var  []*layoutgraph.Node
		for ,  := , 0;  != nil; ,  = .EffectiveContainer(), +1 {
			if  := .Step();  != nil {
				return 0, 
			}
			if  >= layoutgraph.MaxTopologyDepth {
				return 0, fmt.Errorf("TALA Evaluate container depth exceeds limit %d", layoutgraph.MaxTopologyDepth)
			}
			 = append(, )
		}

		,  := nodeOverlapCount(, , label.PADDING, )
		if  != nil {
			return 0, 
		}
		,  := partialNodeOverlapCount(, , label.PADDING, )
		if  != nil {
			return 0, 
		}
		,  := edgeOverlapCount(, .Edges, label.PADDING-1, )
		if  != nil {
			return 0, 
		}
		,  := boxOverlapCount(, , label.PADDING, )
		if  != nil {
			return 0, 
		}
		 += scoreNodeLabelOverlaps(+, , )
		 = append(, )
	}

	,  := findSharedSegments(.Edges, )
	if  != nil {
		return 0, 
	}
	 := make([]geo.Box, 0, len())
	for ,  := range  {
		if  := .Step();  != nil {
			return 0, 
		}
		 := .Start.Copy()
		 := .End.X - .Start.X
		 := .End.Y - .Start.Y
		if .End.X == .Start.X {
			 = 2 * labeling.SharedSegmentClearance
			.X -= labeling.SharedSegmentClearance
		} else {
			 = 2 * labeling.SharedSegmentClearance
			.Y -= labeling.SharedSegmentClearance
		}
		 = append(, geo.Box{TopLeft: , Width: , Height: })
	}

	for ,  := range .Edges {
		if  := .Step();  != nil {
			return 0, 
		}
		if .Label == nil || .IsLoop() {
			continue
		}
		if  := chargeEvaluationWork(, len(.Points));  != nil {
			return 0, 
		}
		 := labelBox()

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

		var ,  []*layoutgraph.Node
		for ,  := range .Nodes {
			if  := .Step();  != nil {
				return 0, 
			}
			,  := evaluationIsDescendantOf(.From, , )
			if  != nil {
				return 0, 
			}
			,  := evaluationIsDescendantOf(.To, , )
			if  != nil {
				return 0, 
			}
			if  != .From &&  != .To && ( || ) {
				 = append(, )
			} else {
				 = append(, )
			}
		}

		,  := nodeOverlapArea(, , label.PADDING, true, )
		if  != nil {
			return 0, 
		}
		,  := nodeOverlapArea(, , label.PADDING, false, )
		if  != nil {
			return 0, 
		}
		,  := edgeOverlapCount(, , label.PADDING, )
		if  != nil {
			return 0, 
		}
		,  := boxOverlapCount(, , 0, )
		if  != nil {
			return 0, 
		}
		,  := boxOverlapCount(, , label.PADDING, )
		if  != nil {
			return 0, 
		}
		,  := boxOverlapCount(, , label.PADDING, )
		if  != nil {
			return 0, 
		}

		 += scoreEdgeLabelOverlaps(
			.Width*.Height,
			+,
			0,
			,
			,
			,
			,
		)
		 = append(, )
	}

	return 1 / (1 + ), nil
}

func labelBox( *layoutgraph.Edge) geo.Box {
	return geo.Box{
		TopLeft: .LabelTopLeft(.Label.Position, .Label.Width, .Label.Height),
		Width:   .Label.Width,
		Height:  .Label.Height,
	}
}

func nodeOverlapCount( geo.Box,  []*layoutgraph.Node,  float64,  *limits.WorkGuard) (int, error) {
	 := 0
	for ,  := range  {
		if  := .Step();  != nil {
			return 0, 
		}
		if boxesOverlapWithPadding(, .Box, ) {
			++
		}
	}
	return , nil
}

func partialNodeOverlapCount( geo.Box,  []*layoutgraph.Node,  float64,  *limits.WorkGuard) (int, error) {
	 := 0
	for ,  := range  {
		if  := .Step();  != nil {
			return 0, 
		}
		if boxesOverlapWithPadding(, .Box, ) && !boxCovers(.Box, ) {
			++
		}
	}
	return , nil
}

func boxOverlapCount( geo.Box,  []geo.Box,  float64,  *limits.WorkGuard) (int, error) {
	 := 0
	for ,  := range  {
		if  := .Step();  != nil {
			return 0, 
		}
		if boxesOverlapWithPadding(, , ) {
			++
		}
	}
	return , nil
}

func nodeOverlapArea( geo.Box,  []*layoutgraph.Node,  float64,  bool,  *limits.WorkGuard) (float64, error) {
	 := 0.0
	for ,  := range  {
		if  := .Step();  != nil {
			return 0, 
		}
		if !boxesOverlapWithPadding(, .Box, ) ||  && boxCovers(.Box, ) {
			continue
		}
		if  == 0 || boxesOverlapWithPadding(, .Box, 0) {
			 += boxOverlapArea(, .Box)
		}
		if !.IsContainer() {
			 += .Width * .Height
		}
	}
	return , nil
}

func edgeOverlapCount( geo.Box,  []*layoutgraph.Edge,  float64,  *limits.WorkGuard) (int, error) {
	 := 0
	for ,  := range  {
		for  := 1;  < len(.Points); ++ {
			if  := .Step();  != nil {
				return 0, 
			}
			if boxOverlapsLine(, .Points[-1], .Points[], ) {
				++
			}
		}
	}
	return , nil
}

func boxesOverlapWithPadding(,  geo.Box,  float64) bool {
	 := .TopLeft.X + .Width
	 := .TopLeft.X + .Width
	if .TopLeft.X >= + || .TopLeft.X >= + {
		return false
	}
	 := .TopLeft.Y + .Height
	 := .TopLeft.Y + .Height
	return .TopLeft.Y < + && .TopLeft.Y < +
}

func boxCovers(,  geo.Box) bool {
	return .TopLeft.X >= .TopLeft.X &&
		.TopLeft.Y >= .TopLeft.Y &&
		.TopLeft.X+.Width <= .TopLeft.X+.Width &&
		.TopLeft.Y+.Height <= .TopLeft.Y+.Height
}

func boxOverlapArea(,  geo.Box) float64 {
	 := []float64{.TopLeft.X, .TopLeft.X + .Width, .TopLeft.X, .TopLeft.X + .Width}
	 := []float64{.TopLeft.Y, .TopLeft.Y + .Height, .TopLeft.Y, .TopLeft.Y + .Height}
	slices.Sort()
	slices.Sort()
	return ([2] - [1]) * ([2] - [1])
}

func boxOverlapsLine( geo.Box, ,  *geo.Point,  float64) bool {
	 := func( *geo.Point) bool {
		return .TopLeft.X- <= .X &&
			.TopLeft.X+.Width+ >= .X &&
			.TopLeft.Y- <= .Y &&
			.TopLeft.Y+.Height+ >= .Y
	}
	if () || () {
		return true
	}

	 := .TopLeft.X - 
	 := .TopLeft.X + .Width + 
	 := .TopLeft.Y - 
	 := .TopLeft.Y + .Height + 
	 := geo.NewPoint(, )
	 := geo.NewPoint(, )
	 := geo.NewPoint(, )
	 := geo.NewPoint(, )
	return segmentsIntersect(, , , ) ||
		segmentsIntersect(, , , ) ||
		segmentsIntersect(, , , ) ||
		segmentsIntersect(, , , )
}

func segmentsIntersect(, , ,  *geo.Point) bool {
	 := orientation(, , )
	 := orientation(, , )
	 := orientation(, , )
	 := orientation(, , )
	if  == 0 &&  == 0 &&  == 0 &&  == 0 {
		return closedIntervalsOverlap(.X, .X, .X, .X) &&
			closedIntervalsOverlap(.Y, .Y, .Y, .Y)
	}
	return straddlesLine(, ) && straddlesLine(, )
}

func straddlesLine(,  float64) bool {
	return  == 0 ||  == 0 || ( < 0) != ( < 0)
}

func closedIntervalsOverlap(, , ,  float64) bool {
	,  := math.Min(, ), math.Max(, )
	,  := math.Min(, ), math.Max(, )
	return  <=  &&  <= 
}

func scoreNodeLabelOverlaps(, ,  int) float64 {
	return float64( +  + 2*)
}

func scoreEdgeLabelOverlaps(
	,  float64,
	, , , ,  int,
) float64 {
	 :=  /  * 2
	 += float64() * 10
	 += float64()
	 += float64() * 2
	 += float64() * 2
	 += float64()
	return 
}

func findSharedSegments( []*layoutgraph.Edge,  *limits.WorkGuard) ([]*geo.Segment, error) {
	if  := .Step();  != nil {
		return nil, 
	}
	 := make(map[float64][]*geo.Segment)
	 := make(map[float64][]*geo.Segment)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		for  := 0;  < len(.Points)-1; ++ {
			if  := .Step();  != nil {
				return nil, 
			}
			 := geo.NewSegment(.Points[].Copy(), .Points[+1].Copy())
			if .Start.X == .End.X {
				if .End.Y < .Start.Y {
					.End.Y, .Start.Y = .Start.Y, .End.Y
				}
				[.Start.X] = append([.Start.X], )
			} else if .Start.Y == .End.Y {
				if .End.X < .Start.X {
					.End.X, .Start.X = .Start.X, .End.X
				}
				[.Start.Y] = append([.Start.Y], )
			}
		}
	}

	 := make([]*geo.Segment, 0, max(len(), len()))
	 := func( map[float64][]*geo.Segment,  bool) error {
		 := func( *geo.Point) float64 {
			if  {
				return .X
			}
			return .Y
		}
		 := func( *geo.Point,  float64) {
			if  {
				.X = 
			} else {
				.Y = 
			}
		}

		for ,  := range  {
			if  := .Step();  != nil {
				return 
			}
			if len() == 1 {
				continue
			}
			if  := sortSharedSegments(, , );  != nil {
				return 
			}

			 := [0]
			var  *geo.Segment
			for  := 1;  < len(); ++ {
				if  := .Step();  != nil {
					return 
				}
				 := []
				if (.End) > (.Start) {
					if  == nil {
						 = geo.NewSegment(.Start.Copy(), .Start.Copy())
						(.End, math.Min((.End), (.End)))
					} else {
						 := math.Min((.End), (.End))
						(.End, math.Max((.End), ))
					}
				} else if  != nil {
					 = append(, )
					 = nil
				}
				if (.End) > (.End) {
					 = 
				}
			}
			if  != nil {
				 = append(, )
			}
		}
		return nil
	}
	if  := (, false);  != nil {
		return nil, 
	}
	if  := (, true);  != nil {
		return nil, 
	}
	return , nil
}

func sortSharedSegments( []*geo.Segment,  func(*geo.Point) float64,  *limits.WorkGuard) error {
	if len() < 2 {
		return nil
	}
	 := make([]*geo.Segment, len())
	 := func(,  *geo.Segment) bool {
		if (.Start) == (.Start) {
			return (.End) < (.End)
		}
		return (.Start) < (.Start)
	}
	 := 
	for  := 1;  < len(); {
		for  := 0;  < len();  += 2 *  {
			 := min(+, len())
			 := min(+2*, len())
			, ,  := , , 
			for  <  &&  <  {
				if  := .Step();  != nil {
					return 
				}
				if ([], []) {
					[] = []
					++
				} else {
					[] = []
					++
				}
				++
			}
			for  <  {
				if  := .Step();  != nil {
					return 
				}
				[] = []
				++
				++
			}
			for  <  {
				if  := .Step();  != nil {
					return 
				}
				[] = []
				++
				++
			}
		}
		,  = , 
		if  > len()/2 {
			break
		}
		 *= 2
	}
	if len() > 0 && &[0] != &[0] {
		copy(, )
	}
	return nil
}