// Copyright (c) 2011, 2019 Kiel University and others.
//
// SPDX-License-Identifier: EPL-2.0

package intermediate

import (
	basegraph 
	
)

// ProcessInvertedPorts inserts same-layer long-edge dummies for input ports on
// the east side and output ports on the west side.
func ( *layered.LGraphArena,  layered.LGraphID) error {
	 := append([]layered.LayerID(nil), .Graph().Layers...)
	var  *layered.LayerID
	 := make([]layered.LNodeID, 0)
	for ,  := range  {
		 := 
		 := 
		 = &
		for ,  := range  {
			.SetNodeLayer(, )
		}
		 = [:0]

		 := append([]layered.LNodeID(nil), .Layer().Nodes...)
		for ,  := range  {
			 := .Node()
			if .Type != layered.NormalNode ||
				!basegraph.Get(&.Properties, layered.PortConstraintsOption).IsSideFixed() {
				continue
			}
			 := append([]layered.LPortID(nil), .Ports...)
			for ,  := range  {
				 := .Port()
				if .Side != layered.EastSide || len(.IncomingEdges) == 0 {
					continue
				}
				for ,  := range append([]layered.LEdgeID(nil), .IncomingEdges...) {
					createEastInvertedPortDummy(, , , , &)
				}
			}
			for ,  := range  {
				 := .Port()
				if .Side != layered.WestSide || len(.OutgoingEdges) == 0 {
					continue
				}
				for ,  := range append([]layered.LEdgeID(nil), .OutgoingEdges...) {
					createWestInvertedPortDummy(, , , , &)
				}
			}
		}
	}
	for ,  := range  {
		.SetNodeLayer(, )
	}
	return nil
}

func createEastInvertedPortDummy(
	 *layered.LGraphArena,
	 layered.LGraphID,
	 layered.LPortID,
	 layered.LEdgeID,
	 *[]layered.LNodeID,
) {
	 := .Edge()
	if .Source == nil || .Target == nil || *.Target !=  ||
		.EdgeSourceNode() == *.Port().Node {
		return
	}
	, ,  := newInvertedPortDummy(, , )
	* = append(*, )
	.SetEdgeTarget(, &)
	 := copyInvertedDummyEdge(, )
	.SetEdgeSource(, &)
	.SetEdgeTarget(, &)
	setInvertedLongEdgeEndpoints(, , , )
	moveInvertedPortHeadLabels(, , , false)
}

func createWestInvertedPortDummy(
	 *layered.LGraphArena,
	 layered.LGraphID,
	 layered.LPortID,
	 layered.LEdgeID,
	 *[]layered.LNodeID,
) {
	 := .Edge()
	if .Source == nil || .Target == nil || *.Source !=  ||
		.EdgeTargetNode() == *.Port().Node {
		return
	}
	 := *.Target
	, ,  := newInvertedPortDummy(, , )
	* = append(*, )
	.SetEdgeTarget(, &)
	 := copyInvertedDummyEdge(, )
	.SetEdgeSource(, &)
	.SetEdgeTarget(, &)
	moveInvertedPortHeadLabels(, , , true)
	setInvertedLongEdgeEndpoints(, , , )
}

func newInvertedPortDummy(
	 *layered.LGraphArena,
	 layered.LGraphID,
	 layered.LEdgeID,
) (layered.LNodeID, layered.LPortID, layered.LPortID) {
	 := .AddNode()
	.Node().Type = layered.LongEdgeNode
	basegraph.Set(&.Node().Properties, layered.OriginalElement, layered.LEdgeOrigin())
	basegraph.Set(&.Node().Properties, layered.PortConstraintsOption,
		layered.PortConstraintsFixedPosition)
	 := .AddPort()
	.SetPortNode(, &)
	.SetPortSide(, layered.WestSide)
	 := .AddPort()
	.SetPortNode(, &)
	.SetPortSide(, layered.EastSide)
	return , , 
}

func copyInvertedDummyEdge( *layered.LGraphArena,  layered.LEdgeID) layered.LEdgeID {
	 := .AddEdge()
	.Edge().Properties.CopyFrom(&.Edge().Properties)
	basegraph.Unset(&.Edge().Properties, layered.JunctionPoints)
	return 
}

func moveInvertedPortHeadLabels(
	 *layered.LGraphArena,
	,  layered.LEdgeID,
	 bool,
) {
	 := make([]layered.LLabelID, 0, len(.Edge().Labels))
	for ,  := range .Edge().Labels {
		if basegraph.Get(&.Label().Properties, layered.EdgeLabelsPlacement) !=
			layered.EdgeLabelPlacementHead {
			 = append(, )
			continue
		}
		if ,  := basegraph.TryGet(&.Label().Properties, layered.EndLabelEdge); ! ||  {
			basegraph.Set(&.Label().Properties, layered.EndLabelEdge, )
		}
		.Edge().Labels = append(.Edge().Labels, )
	}
	.Edge().Labels = 
}

func setInvertedLongEdgeEndpoints(
	 *layered.LGraphArena,
	 layered.LNodeID,
	,  layered.LPortID,
) {
	if len(.Port().IncomingEdges) == 0 || len(.Port().OutgoingEdges) == 0 {
		return
	}
	 := *.Edge(.Port().IncomingEdges[0]).Source
	 := *.Edge(.Port().OutgoingEdges[0]).Target
	 := *.Port().Node
	 := *.Port().Node
	if .Node().Type == layered.LongEdgeNode {
		if ,  := basegraph.TryGet(&.Node().Properties, layered.LongEdgeSource);  {
			basegraph.Set(&.Node().Properties, layered.LongEdgeSource, )
		} else {
			basegraph.Unset(&.Node().Properties, layered.LongEdgeSource)
		}
	} else {
		basegraph.Set(&.Node().Properties, layered.LongEdgeSource, )
	}
	if .Node().Type == layered.LongEdgeNode {
		if ,  := basegraph.TryGet(&.Node().Properties, layered.LongEdgeTarget);  {
			basegraph.Set(&.Node().Properties, layered.LongEdgeTarget, )
		} else {
			basegraph.Unset(&.Node().Properties, layered.LongEdgeTarget)
		}
	} else {
		basegraph.Set(&.Node().Properties, layered.LongEdgeTarget, )
	}
}