// Copyright (c) 2011, 2015 Kiel University and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

package intermediate

import (
	

	
	
	basegraph 
	
)

// ProcessHypernodes moves simple hypernodes onto the first orthogonal join
// point of their outgoing hyperedge, matching HypernodesProcessor.
func ( *layered.LGraphArena,  layered.LGraphID) {
	for ,  := range .Graph().Layers {
		for ,  := range append([]layered.LNodeID(nil), .Layer().Nodes...) {
			 := .Node()
			if !basegraph.Get(&.Properties, core.Hypernode) || len(.Ports) > 2 {
				continue
			}
			, , ,  := 0, 0, 0, 0
			for ,  := range .Ports {
				switch .Port().Side {
				case layered.NorthSide:
					++
				case layered.EastSide:
					++
				case layered.SouthSide:
					++
				case layered.WestSide:
					++
				}
			}
			if  == 0 &&  == 0 {
				moveHypernode(, , ,  <= )
			}
		}
	}
}

func moveHypernode(
	 *layered.LGraphArena,
	 layered.LGraphID,
	 layered.LNodeID,
	 bool,
) {
	const  = float64(1<<31 - 1)
	 := make([]layered.LEdgeID, 0)
	 := 
	,  := , 
	if  {
		 = .Graph().Size.X
		for ,  := range append([]layered.LPortID(nil), .Node().Ports...) {
			for ,  := range append([]layered.LEdgeID(nil), .Port().OutgoingEdges...) {
				 := .Edge().BendPoints
				if len() == 0 {
					continue
				}
				 := [0]
				if .X <  {
					 =  - .X
					 = 
					 = [:0]
					 = .X
				}
				if .X <=  {
					 = append(, )
					if len() > 1 {
						 = math.Min(, math.Abs([1].Y-.Y))
					}
				}
			}
		}
	} else {
		// ELK 0.8.1 initializes bendX to Integer.MAX_VALUE before this
		// greater-than search. Preserve that observable source behavior.
		for ,  := range append([]layered.LPortID(nil), .Node().Ports...) {
			for ,  := range append([]layered.LEdgeID(nil), .Port().IncomingEdges...) {
				 := .Edge().BendPoints
				if len() == 0 {
					continue
				}
				 := [len()-1]
				if .X >  {
					 = .X - 
					 = 
					 = [:0]
					 = .X
				}
				if .X >=  {
					 = append(, )
					if len() > 1 {
						 = math.Min(,
							math.Abs([len()-2].Y-.Y))
					}
				}
			}
		}
	}

	 := .Node().Size
	if len() == 0 ||  <= .X/2 ||  <= .Y/2 {
		return
	}
	 := .AddPort()
	.SetPortNode(, &)
	.SetPortSide(, layered.NorthSide)
	.Port().Position.X = .X / 2
	 := .AddPort()
	.SetPortNode(, &)
	.SetPortSide(, layered.SouthSide)
	.Port().Position = geometry.Point{X: .X / 2, Y: .Y}

	for ,  := range  {
		 := .Edge().BendPoints
		var ,  geometry.Point
		if  {
			 = [0]
			.Edge().BendPoints = [1:]
			if len(.Edge().BendPoints) == 0 {
				 = internalPortAbsoluteAnchor(, *.Edge().Target)
			} else {
				 = .Edge().BendPoints[0]
			}
			if .Y >= .Y {
				.SetEdgeSource(, &)
			} else {
				.SetEdgeSource(, &)
			}
		} else {
			 = [len()-1]
			.Edge().BendPoints = [:len()-1]
			if len(.Edge().BendPoints) == 0 {
				 = internalPortAbsoluteAnchor(, *.Edge().Source)
			} else {
				 = .Edge().BendPoints[len(.Edge().BendPoints)-1]
			}
			if .Y >= .Y {
				.SetEdgeTarget(, &)
			} else {
				.SetEdgeTarget(, &)
			}
		}
		if ,  := basegraph.TryGet(&.Edge().Properties, layered.JunctionPoints);  {
			basegraph.Set(&.Edge().Properties, layered.JunctionPoints,
				removeFirstPoint(, ))
		}
	}
	.Node().Position.X =  - .X/2
}

func internalPortAbsoluteAnchor(
	 *layered.LGraphArena,
	 layered.LPortID,
) geometry.Point {
	 := .Port()
	 := .Position.Add(.Anchor)
	if .Node != nil {
		 = .Add(.Node(*.Node).Position)
	}
	return 
}

func removeFirstPoint( geometry.Chain,  geometry.Point) geometry.Chain {
	for ,  := range  {
		if  ==  {
			return append([:], [+1:]...)
		}
	}
	return 
}

// ProcessConstraints stores final layer and position identifiers on normal
// nodes for interactive-layout and generated-constraint output.
func ( *layered.LGraphArena,  layered.LGraphID) {
	for ,  := range .Graph().Layers {
		 := 0
		for ,  := range .Layer().Nodes {
			if .Node().Type != layered.NormalNode {
				continue
			}
			basegraph.Set(&.Node().Properties, layered.LayerIDOption, )
			basegraph.Set(&.Node().Properties, layered.PositionIDOption, )
			++
		}
	}
}