package routing

import (
	

	
	
)

type TreeEdgePath struct {
	SourcePortNode            *OVGNode
	TargetPortNode            *OVGNode
	SourceMidpoint            *geo.Point
	TargetMidpoint            *geo.Point
	SourceOrientationToTarget geo.Orientation
}

func isSentinelEdgeSource( *layoutgraph.Tree) bool {
	return  != nil && .SentinelEdge != nil && .SentinelEdge.From == .Node
}

// get the S-shaped path information for the tree node's sentinelEdge
func treeEdgePath( *layoutgraph.Tree,  map[*layoutgraph.Node][]*OVGNode,  map[*OVGNode]map[layoutgraph.Arrowhead]struct{}) TreeEdgePath {
	,  := treeEdgePathForBuild(, , , nil)
	return 
}

func treeEdgePathForBuild( *layoutgraph.Tree,  map[*layoutgraph.Node][]*OVGNode,  map[*OVGNode]map[layoutgraph.Arrowhead]struct{},  *ovgBuildGuard) (TreeEdgePath, error) {
	 := func() error {
		if  == nil {
			return nil
		}
		return .step()
	}
	if  := ();  != nil {
		return TreeEdgePath{}, 
	}
	 := .SentinelNode()
	 := .Node

	 := .CenterPortIndex(.Orientation)
	 := .CenterPortIndex(.Orientation.GetOpposite())
	 := [][]
	 := [][]

	if ,  := [];  {
		// check the arrowhead on the parent
		 := .SentinelEdge.TargetArrowhead
		if !isSentinelEdgeSource() {
			 = .SentinelEdge.SourceArrowhead
		}
		if len() > 0 {
			if ,  := []; ! {
				var  *OVGNode
				 := math.Inf(1)
				// try to find a different port since we have a mismatched arrowhead
				for ,  := range .PortIndices(.Orientation) {
					if  := ();  != nil {
						return TreeEdgePath{}, 
					}
					if  ==  {
						continue
					}
					 := false
					 := [][]
					,  := []
					if ! {
						 = true
					} else if ,  := [][];  {
						 = true
					}
					if  {
						 := geo.EuclideanDistance(
							.Point.X,
							.Point.Y,
							.X,
							.Y,
						)
						if  <  {
							 = 
							 = 
						}
					}
				}
				if  != nil {
					 = 
				}
			}
		}
	}

	,  := alignedPortNodeForBuild(, , , )
	if  != nil {
		return TreeEdgePath{}, 
	}
	// alignedPortNodeForBuild may synthesize a port so that a nearly aligned tree
	// edge stays straight. addTreeNodes canonicalizes that coordinate into the
	// OVG and records it in the child's port list. Resolve it here on subsequent
	// route lookups; otherwise child-as-source routing starts from a fresh node
	// with no OVG edges, and shared points lose their canonical owner metadata.
	for ,  := range [] {
		if  := ();  != nil {
			return TreeEdgePath{}, 
		}
		if nonNilEquals(.Point, .Point) {
			 = 
			break
		}
	}

	,  := treeEdgeMidpoints(, .Orientation, .Point, .Point)

	// if we are the target, swap these around
	if isSentinelEdgeSource() {
		return TreeEdgePath{
			SourcePortNode:            ,
			TargetPortNode:            ,
			SourceMidpoint:            ,
			TargetMidpoint:            ,
			SourceOrientationToTarget: .Orientation,
		}, nil
	} else {
		return TreeEdgePath{
			SourcePortNode:            ,
			TargetPortNode:            ,
			SourceMidpoint:            ,
			TargetMidpoint:            ,
			SourceOrientationToTarget: .Orientation.GetOpposite(),
		}, nil
	}
}

func alignedPortNodeForBuild( *layoutgraph.Tree, ,  *OVGNode,  *ovgBuildGuard) (*OVGNode, error) {
	 := func(, ,  float64) bool {
		return math.Abs(-) <= 
	}
	 := .SentinelNode()
	 := .Node

	 := 5.

	// in some cases, parent.center = (100.5, 100) and child.center = (100, 150)
	// however, this is just a rounding error and then we compare equality by upto 1 in difference
	 := (.Center().X, .Center().X, treeChildAlignmentTolerance)
	 := .X != .X
	if .Orientation.IsVertical() &&  &&  {
		if .TopLeft.X+ < .X && .X < .TopLeft.X+.Width- {
			if  != nil {
				return .newDerivedNode(geo.NewPoint(.X, .Y))
			}
			return NewOVGNode(geo.NewPoint(.X, .Y)), nil
		}
	}

	 := (.Center().Y, .Center().Y, treeChildAlignmentTolerance)
	 := .Y != .Y
	if .Orientation.IsHorizontal() &&  &&  {
		if .TopLeft.Y+ < .Y && .Y < .TopLeft.Y+.Height- {
			if  != nil {
				return .newDerivedNode(geo.NewPoint(.X, .Y))
			}
			return NewOVGNode(geo.NewPoint(.X, .Y)), nil
		}
	}

	return , nil
}

// treeEdgeMidpoints computes the two bends in a tree edge's S-shaped route.
// The bend distance is relative to the parent, even when the child is farther
// away to accommodate an edge label.
func treeEdgeMidpoints( *layoutgraph.Node,  geo.Orientation, ,  *geo.Point) (*geo.Point, *geo.Point) {
	 := new(geo.Point)
	 := new(geo.Point)
	switch  {
	case geo.Left:
		.Y = .Y
		.Y = .Y
		 := .TopLeft.X - layoutgraph.TreeParentSpacing/2
		.X = 
		.X = 
	case geo.Right:
		.Y = .Y
		.Y = .Y
		 := .TopLeft.X + .Width + layoutgraph.TreeParentSpacing/2
		.X = 
		.X = 
	case geo.Top:
		.X = .X
		.X = .X
		 := .TopLeft.Y - layoutgraph.TreeParentSpacing/2
		.Y = 
		.Y = 
	case geo.Bottom:
		.X = .X
		.X = .X
		 := .TopLeft.Y + .Height + layoutgraph.TreeParentSpacing/2
		.Y = 
		.Y = 
	}
	return , 
}