// Copyright (c) 2010, 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 
	
)

// SplitLongEdges makes the layering proper by inserting one dummy into each
// intervening layer of every long edge.
func ( *layered.LGraphArena,  layered.LGraphID) {
	 := .Graph().Layers
	if len() <= 2 {
		return
	}
	for  := 0; +1 < len(); ++ {
		,  := [], [+1]
		// Java's enhanced loops observe the layer's node count dynamically. A
		// dummy is added to nextLayer, never to layerID, so a direct range here
		// has the same behavior.
		for ,  := range .Layer().Nodes {
			for ,  := range .Node().Ports {
				for ,  := range append([]layered.LEdgeID(nil), .Port().OutgoingEdges...) {
					 := .EdgeTargetNode()
					 := .Node().Layer
					if  == nil || * ==  || * ==  {
						continue
					}
					if +2 >= len() {
						panic("layered: long edge points beyond the final layer")
					}
					 := createLongEdgeDummy(, , , )
					SplitEdgeAtDummy(, , )
				}
			}
		}
	}
}

func createLongEdgeDummy(
	 *layered.LGraphArena,
	 layered.LGraphID,
	 layered.LayerID,
	 layered.LEdgeID,
) layered.LNodeID {
	 := .AddNode()
	 := .Node()
	.Type = layered.LongEdgeNode
	basegraph.Set(&.Properties, layered.OriginalElement, layered.LEdgeOrigin())
	basegraph.Set(&.Properties, layered.PortConstraintsOption, layered.PortConstraintsFixedPosition)
	.SetNodeLayer(, &)
	return 
}

// SplitEdgeAtDummy reroutes edge into dummy and returns the new outgoing edge.
func (
	 *layered.LGraphArena,
	 layered.LEdgeID,
	 layered.LNodeID,
) layered.LEdgeID {
	 := .Edge()
	if .Target == nil {
		panic("layered: cannot split an edge without a target")
	}
	 := *.Target
	 := basegraph.Get(&.Properties, layered.EdgeThickness)
	if  < 0 {
		 = 0
		basegraph.Set(&.Properties, layered.EdgeThickness, )
	}
	 := .Node()
	.Size.Y = 
	 := math.Floor( / 2)

	 := .AddPort()
	.SetPortSide(, layered.WestSide)
	.SetPortNode(, &)
	.Port().Position.Y = 
	 := .AddPort()
	.SetPortSide(, layered.EastSide)
	.SetPortNode(, &)
	.Port().Position.Y = 

	.SetEdgeTarget(, &)
	 := .AddEdge()
	 := .Edge()
	.Properties.CopyFrom(&.Properties)
	basegraph.Unset(&.Properties, layered.JunctionPoints)
	.SetEdgeSource(, &)
	.SetEdgeTarget(, &)

	setLongEdgeDummyProperties(, , , )
	moveHeadLabels(, , )
	return 
}

func setLongEdgeDummyProperties(
	 *layered.LGraphArena,
	 layered.LNodeID,
	,  layered.LEdgeID,
) {
	 := .Node()
	 := .EdgeSourceNode()
	 := .EdgeTargetNode()
	if .Node().Type == layered.LongEdgeNode {
		basegraph.Set(&.Properties, layered.LongEdgeSource,
			basegraph.Get(&.Node().Properties, layered.LongEdgeSource))
		basegraph.Set(&.Properties, layered.LongEdgeTarget,
			basegraph.Get(&.Node().Properties, layered.LongEdgeTarget))
		basegraph.Set(&.Properties, layered.LongEdgeHasLabelDummies,
			basegraph.Get(&.Node().Properties, layered.LongEdgeHasLabelDummies))
		return
	}
	if .Node().Type == layered.LabelNode {
		basegraph.Set(&.Properties, layered.LongEdgeSource,
			basegraph.Get(&.Node().Properties, layered.LongEdgeSource))
		basegraph.Set(&.Properties, layered.LongEdgeTarget,
			basegraph.Get(&.Node().Properties, layered.LongEdgeTarget))
		basegraph.Set(&.Properties, layered.LongEdgeHasLabelDummies, true)
		return
	}
	if .Node().Type == layered.LabelNode {
		basegraph.Set(&.Properties, layered.LongEdgeSource,
			basegraph.Get(&.Node().Properties, layered.LongEdgeSource))
		basegraph.Set(&.Properties, layered.LongEdgeTarget,
			basegraph.Get(&.Node().Properties, layered.LongEdgeTarget))
		basegraph.Set(&.Properties, layered.LongEdgeHasLabelDummies, true)
		return
	}
	basegraph.Set(&.Properties, layered.LongEdgeSource, *.Edge().Source)
	basegraph.Set(&.Properties, layered.LongEdgeTarget, *.Edge().Target)
}

func moveHeadLabels( *layered.LGraphArena, ,  layered.LEdgeID) {
	,  := .Edge(), .Edge()
	 := .Labels[:0]
	for ,  := range .Labels {
		 := .Label()
		if basegraph.Get(&.Properties, layered.EdgeLabelsPlacement) != layered.EdgeLabelPlacementHead {
			 = append(, )
			continue
		}
		.Labels = append(.Labels, )
		if !basegraph.Has(&.Properties, layered.EndLabelEdge) {
			basegraph.Set(&.Properties, layered.EndLabelEdge, )
		}
	}
	.Labels = 
}

// JoinLongEdges removes long-edge dummies after routing. The dummy's Layer
// pointer intentionally remains set, matching ELK's postcondition.
func ( *layered.LGraphArena,  layered.LGraphID) {
	 := basegraph.Get(&.Graph().Properties, layered.UnnecessaryBendpoints)
	for ,  := range .Graph().Layers {
		 := .Layer().Nodes
		 := [:0]
		for ,  := range  {
			if .Node().Type == layered.LongEdgeNode {
				JoinLongEdgeAt(, , )
				continue
			}
			 = append(, )
		}
		.Layer().Nodes = 
	}
}

// JoinLongEdgeAt joins matching west-incoming and east-outgoing edges.
func ( *layered.LGraphArena,  layered.LNodeID,  bool) {
	 := .NodePortsOnSide(, layered.WestSide)
	 := .NodePortsOnSide(, layered.EastSide)
	if len() == 0 || len() == 0 {
		panic("layered: long-edge dummy has no west/east ports")
	}
	 := .Port([0]).IncomingEdges
	 := .Port([0]).OutgoingEdges
	if len() < len() {
		panic("layered: long-edge dummy edge lists are inconsistent")
	}
	 := .Port(.Node().Ports[0])
	 := .Node().Position.Add(.Position).Add(.Anchor)

	for len(.Port([0]).IncomingEdges) > 0 {
		 := .Port([0]).IncomingEdges[0]
		 := .Port([0]).OutgoingEdges[0]
		 := .Edge()
		 := *.Target
		 := indexEdge(.Port().IncomingEdges, )
		.SetEdgeTargetAt(, &, )
		.SetEdgeSource(, nil)
		.SetEdgeTarget(, nil)

		 := .Edge()
		if  {
			.BendPoints = append(.BendPoints, )
		}
		.BendPoints = append(.BendPoints, .BendPoints...)
		if ,  := basegraph.TryGet(&.Properties, layered.SplineControlPointSegments);  {
			,  := basegraph.TryGet(&.Properties, layered.SplineControlPointSegments)
			 = append(, ...)
			basegraph.Set(&.Properties, layered.SplineControlPointSegments, )
		}
		if ,  := basegraph.TryGet(
			&.Properties, layered.SplineCompactionSegments,
		);  {
			,  := basegraph.TryGet(
				&.Properties, layered.SplineCompactionSegments)
			 = append(
				, ...)
			basegraph.Set(&.Properties, layered.SplineCompactionSegments,
				)
		}
		.Labels = append(.Labels, .Labels...)
		if ,  := basegraph.TryGet(&.Properties, layered.JunctionPoints);  &&  != nil {
			,  := basegraph.TryGet(&.Properties, layered.JunctionPoints)
			 = append(, ...)
			basegraph.Set(&.Properties, layered.JunctionPoints, )
		}
	}
}

func indexEdge( []layered.LEdgeID,  layered.LEdgeID) int {
	for ,  := range  {
		if  ==  {
			return 
		}
	}
	panic("layered: edge is missing from adjacency list")
}