package layoutgraph

import (
	
	

	
)

const scoringCancellationCheckInterval = 64

// CrossingSegment is an oriented line segment used by crossing scoring.
type CrossingSegment struct {
	Start geo.Point
	End   geo.Point
}

func scoringCancellationError( context.Context,  int) error {
	if %scoringCancellationCheckInterval != 0 {
		return nil
	}
	if  := .Err();  != nil {
		return fmt.Errorf("EdgeLength: %w", )
	}
	return nil
}

// CountSegmentCrossings counts intersections between segments while ignoring
// pairs with equal starts or equal ends. It is the common geometric kernel used
// by layout cost evaluation and hierarchy rank optimization.
func ( []CrossingSegment) int64 {
	,  := countSegmentCrossingsWithCheck(, nil)
	return 
}

// CountSegmentCrossingsContext is CountSegmentCrossings with the layout
// engine's bounded cancellation checks.
func ( context.Context,  []CrossingSegment) (int64, error) {
	if  := .Err();  != nil {
		return 0, fmt.Errorf("EdgeLength: %w", )
	}
	,  := countSegmentCrossingsWithCheck(, func( int) error {
		return scoringCancellationError(, )
	})
	if  != nil {
		return 0, 
	}
	if  := .Err();  != nil {
		return 0, fmt.Errorf("EdgeLength: %w", )
	}
	return , nil
}

func countSegmentCrossingsWithCheck( []CrossingSegment,  func( int) error) (int64, error) {
	var  int64
	var , , ,  *geo.Point
	var , , ,  float64
	var  int
	for  := 0;  < len()-1; ++ {
		if  != nil {
			if  := ();  != nil {
				return 0, 
			}
		}
		 = &[].Start
		 = &[].End
		,  = .X, .X
		if  <  {
			,  = , 
		}
		,  = .Y, .Y
		if  <  {
			,  = , 
		}
		for  =  + 1;  < len(); ++ {
			if  != nil {
				if  := ( -  - 1);  != nil {
					return 0, 
				}
			}
			 = &[].Start
			 = &[].End
			if .X < .X {
				if .X <  {
					continue
				}
				if  < .X {
					continue
				}
			} else {
				if .X <  {
					continue
				}
				if  < .X {
					continue
				}
			}
			if .Y < .Y {
				if .Y <  {
					continue
				}
				if  < .Y {
					continue
				}
			} else {
				if .Y <  {
					continue
				}
				if  < .Y {
					continue
				}
			}

			if nonNilEquals(, ) || nonNilEquals(, ) {
				continue
			}
			if SegmentsCross(, , , ) {
				++
			}
		}
	}
	return , nil
}

// SegmentsCross reports whether two finite segments intersect. Parallel and
// overlapping segments do not count as crossings.
func (, , ,  *geo.Point) bool {
	 := ((.Y-.Y)*(.X-.X) - (.X-.X)*(.Y-.Y))
	if  == 0 {
		return false
	}
	 := ((.X-.X)*(.Y-.Y) - (.Y-.Y)*(.X-.X)) / 
	if  < 0 ||  > 1 {
		return false
	}
	 := ((.X-.X)*(.Y-.Y) - (.Y-.Y)*(.X-.X)) / 
	return  >= 0 &&  <= 1
}