package routing

import (
	

	
	
	
)

type TunnelEntry struct {
	Node    *layoutgraph.Node
	OVGNode *OVGNode
}

func ( *layoutgraph.Node,  *OVGNode) *TunnelEntry {
	// Tunnel endpoints are unrestricted ports. Register their owner when the
	// entry is created so every production port uses the same per-owner metadata
	// representation before OVG canonicalization.
	.addPortMetadata(, ovgPortMetadata{})
	return &TunnelEntry{Node: , OVGNode: }
}

type Tunnel struct {
	EntryA *TunnelEntry
	EntryB *TunnelEntry
}

func (,  *TunnelEntry) *Tunnel {
	return &Tunnel{EntryA: , EntryB: }
}

type Range struct {
	start float64
	end   float64
}

func ( *Range) () float64 {
	return .end - .start
}

func tunnelRangesBetween( *layoutgraph.Graph, ,  *layoutgraph.Node,  bool,  *ovgBuildGuard) ( []*Range,  bool,  error) {
	if  := .check();  != nil {
		return nil, false, 
	}
	return tunnelRangesBetweenChecked(,
		,
		,
		,
		.step,
		.check,
		.isDescendantOf,
	)
}

func tunnelRangesBetweenGuarded( *layoutgraph.Graph, ,  *layoutgraph.Node,  bool,  *routeWorkGuard) ( []*Range,  bool,  error) {
	return tunnelRangesBetweenChecked(,
		,
		,
		,
		.step,
		.check,
		func(,  *layoutgraph.Node) (bool, error) {
			return isDescendantOfWithRouteGuard(, , )
		},
	)
}

func isDescendantOfWithRouteGuard(,  *layoutgraph.Node,  *routeWorkGuard) (bool, error) {
	for  := ; ; {
		if  := .step();  != nil {
			return false, 
		}
		if  ==  {
			return true, nil
		}
		if  == nil {
			return false, nil
		}
		switch {
		case .Container != nil:
			 = .Container
		case .Cluster != nil:
			 = .Cluster.Vessel
		case .Sequence != nil:
			 = .Sequence.Vessel
		default:
			return  == nil, nil
		}
	}
}

func tunnelRangesBetweenChecked( *layoutgraph.Graph,
	,  *layoutgraph.Node,
	 bool,
	 func() error,
	 func() error,
	 func(*layoutgraph.Node, *layoutgraph.Node) (bool, error),
) ( []*Range,  bool,  error) {
	if  := ();  != nil {
		return nil, false, 
	}
	 = .VisibilityGraphCandidate(true, false, true, , 0)
	var  bool
	if ! {
		if  := ();  != nil {
			return nil, false, 
		}
		 = .VisibilityGraphCandidate(false, false, true, , 0)
		if ! {
			return nil, false, nil
		}
	}

	{
		var ,  float64
		if  {
			 = math.Max(.TopLeft.Y, .TopLeft.Y)
			 = math.Min(.TopLeft.Y+.Height, .TopLeft.Y+.Height)
		} else {
			 := .TopLeft.X + .Width
			 := .TopLeft.X + .Width

			// sequence nodes have shorter ranges along Top/Bottom (except last node in sequence)
			if .Sequence != nil && .Sequence.Last() !=  {
				 -= shape.STEP_WEDGE_WIDTH
			}
			if .Sequence != nil && .Sequence.Last() !=  {
				 -= shape.STEP_WEDGE_WIDTH
			}

			 = math.Max(.TopLeft.X, .TopLeft.X)
			 = math.Min(, )
		}
		if  := ();  != nil {
			return nil, false, 
		}
		 = []*Range{{start: , end: }}
	}

	for ,  := range .Nodes {
		if  := ();  != nil {
			return nil, false, 
		}
		if  ==  ||  ==  {
			continue
		}
		,  := (, )
		if  != nil {
			return nil, false, 
		}
		,  := (, )
		if  != nil {
			return nil, false, 
		}
		,  := (, )
		if  != nil {
			return nil, false, 
		}
		,  := (, )
		if  != nil {
			return nil, false, 
		}
		if  ||  ||  ||  {
			continue
		}

		// We're reusing a function that assumes order, so the different order matters
		if .IsBlocked(, , true, ) || .IsBlocked(, , true, ) {
			return nil, false, nil
		}
		// Skip ones not in between
		if  {
			if !((.TopLeft.X < .TopLeft.X && .TopLeft.X < .TopLeft.X) ||
				(.TopLeft.X < .TopLeft.X && .TopLeft.X < .TopLeft.X)) {
				continue
			}
		} else {
			if !((.TopLeft.Y < .TopLeft.Y && .TopLeft.Y < .TopLeft.Y) ||
				(.TopLeft.Y < .TopLeft.Y && .TopLeft.Y < .TopLeft.Y)) {
				continue
			}
		}

		 := make([]*Range, 0)
		// For every range, a partial obstruction can do one of the following
		// (a) delete it entirely (it obscures the whole range)
		// (b) split it into 2 (it obscures a middle subrange of a range)
		// (c) shorten it (it obscures a non-middle subrange)
		// (d) nothing (it doesn't overlap with any ranges)
		for ,  := range  {
			if  := ();  != nil {
				return nil, false, 
			}
			if  {
				// (a)
				if .TopLeft.Y <= .start && (.TopLeft.Y+.Height) >= .end {
					continue
				}
				// (b)
				if .TopLeft.Y > .start && (.TopLeft.Y+.Height) < .end {
					 = append(,
						[]*Range{
							{start: .start, end: .TopLeft.Y},
							{start: .TopLeft.Y + .Height, end: .end},
						}...)
					continue
				}
				// (c) obscures start
				if .TopLeft.Y <= .start && (.TopLeft.Y+.Height) < .end && (.TopLeft.Y+.Height) > .start {
					 = append(, &Range{start: .TopLeft.Y + .Height, end: .end})
					continue
				}
				// (c) obscures end
				if .TopLeft.Y > .start && (.TopLeft.Y+.Height) >= .end && .TopLeft.Y < .end {
					 = append(, &Range{start: .start, end: .TopLeft.Y})
					continue
				}

				// (d)
				 = append(, )
			} else {
				if .TopLeft.X <= .start && (.TopLeft.X+.Width) >= .end {
					continue
				}
				if .TopLeft.X > .start && (.TopLeft.X+.Width) < .end {
					 = append(,
						[]*Range{
							{start: .start, end: .TopLeft.X},
							{start: .TopLeft.X + .Width, end: .end},
						}...)
					continue
				}
				if .TopLeft.X <= .start && (.TopLeft.X+.Width) < .end && (.TopLeft.X+.Width) > .start {
					 = append(, &Range{start: .TopLeft.X + .Width, end: .end})
					continue
				}
				if .TopLeft.X > .start && (.TopLeft.X+.Width) >= .end && .TopLeft.X < .end {
					 = append(, &Range{start: .start, end: .TopLeft.X})
					continue
				}
				 = append(, )
			}
		}
		 = make([]*Range, 0)
		if  := ();  != nil {
			return nil, false, 
		}
		// Filter out the ranges that are too short for even one tunnel
		for ,  := range  {
			if  := ();  != nil {
				return nil, false, 
			}
			if ! || .length() >= segmentSpacingBuffer {
				 = append(, )
			}
		}
	}

	return , , nil
}

func buildTunnelsBetween( *layoutgraph.Graph, ,  *layoutgraph.Node,  *ovgBuildGuard) ([]*Tunnel, error) {
	if  := .check();  != nil {
		return nil, 
	}
	,  := .isDescendantOf(, )
	if  != nil {
		return nil, 
	}
	,  := .isDescendantOf(, )
	if  != nil {
		return nil, 
	}
	if  ||  {
		return nil, nil
	}
	, ,  := tunnelRangesBetween(, , , true, )
	if  != nil {
		return nil, 
	}
	if  == nil {
		return nil, nil
	}

	 := 0.0
	for ,  := range .Edges {
		if  := .step();  != nil {
			return nil, 
		}
		if .Adjacent() ==  {
			++
		}
	}

	 := make([]*Tunnel, 0)
	for ,  := range  {
		if  := .step();  != nil {
			return nil, 
		}
		if  {
			 := math.Min(math.Floor((.end-.start)/segmentSpacingBuffer), )

			for  := 1.0;  <= ; ++ {
				if  := .step();  != nil {
					return nil, 
				}
				 := math.Round(.start + *(.end-.start)/(+1))
				,  := .newDerivedNode(geo.NewPoint(0, ))
				if  != nil {
					return nil, 
				}
				,  := .newDerivedNode(geo.NewPoint(0, ))
				if  != nil {
					return nil, 
				}
				if  := .step();  != nil {
					return nil, 
				}
				 := NewTunnel(NewTunnelEntry(, ), NewTunnelEntry(, ))
				if .TopLeft.X > .TopLeft.X {
					.EntryA.OVGNode.Point.X = .TopLeft.X
					.EntryB.OVGNode.Point.X = .TopLeft.X + .Width
				} else {
					.EntryA.OVGNode.Point.X = .TopLeft.X + .Width
					.EntryB.OVGNode.Point.X = .TopLeft.X
				}
				 = append(, )
				--
			}
		} else {
			 := math.Min(math.Floor((.end-.start)/segmentSpacingBuffer), )

			for  := 1.0;  <= ; ++ {
				if  := .step();  != nil {
					return nil, 
				}
				 := math.Round(.start + *(.end-.start)/(+1))
				,  := .newDerivedNode(geo.NewPoint(, 0))
				if  != nil {
					return nil, 
				}
				,  := .newDerivedNode(geo.NewPoint(, 0))
				if  != nil {
					return nil, 
				}
				if  := .step();  != nil {
					return nil, 
				}
				 := NewTunnel(NewTunnelEntry(, ), NewTunnelEntry(, ))
				if .TopLeft.Y > .TopLeft.Y {
					.EntryA.OVGNode.Point.Y = .TopLeft.Y
					.EntryB.OVGNode.Point.Y = .TopLeft.Y + .Height
				} else {
					.EntryA.OVGNode.Point.Y = .TopLeft.Y + .Height
					.EntryB.OVGNode.Point.Y = .TopLeft.Y
				}
				 = append(, )
				--
			}
		}
	}
	return , nil
}

func buildTunnels( *layoutgraph.Graph,  *ovgBuildGuard) ([]*Tunnel, error) {
	if  := .check();  != nil {
		return nil, 
	}
	 := make([]*Tunnel, 0)
	 := map[*layoutgraph.Node]struct{}{}
	for ,  := range .Clusters {
		if  := .step();  != nil {
			return nil, 
		}
		for ,  := range .Nodes {
			if  := .step();  != nil {
				return nil, 
			}
			[] = struct{}{}
		}
	}
	for  := range .NodeToTree {
		if  := .step();  != nil {
			return nil, 
		}
		[] = struct{}{}
	}

	 := make(map[*layoutgraph.Node]map[*layoutgraph.Node]bool)
	for ,  := range .Nodes {
		if  := .step();  != nil {
			return nil, 
		}
		if ,  := [];  {
			continue
		}
		if .IsTable() {
			// no tunnels for tables
			continue
		}
		if ,  := []; ! {
			[] = make(map[*layoutgraph.Node]bool)
		}
		for ,  := range .Edges {
			if  := .step();  != nil {
				return nil, 
			}
			 := .Adjacent()
			if  ==  {
				continue
			}
			if ,  := [];  {
				continue
			}
			if ,  := []; ! {
				[] = make(map[*layoutgraph.Node]bool)
			}
			if ,  := [][];  {
				continue
			}
			[][] = true
			[][] = true

			,  := buildTunnelsBetween(, , , )
			if  != nil {
				return nil, 
			}
			 = append(, ...)
		}
	}

	return , nil
}