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

const partitionConstraintEdgePriority = 1000

// PreprocessPartitions reverses edges from higher-indexed to lower-indexed
// partitions before cycle breaking. The elevated direction priority mirrors
// ELK's safeguard against the cycle breaker reversing the edge again.
func ( *layered.LGraphArena,  layered.LGraphID) {
	 := make([]layered.LNodeID, 0)
	for ,  := range .Graph().LayerlessNodes {
		if basegraph.Has(&.Node().Properties, core.PartitioningPartition) {
			 = append(, )
		}
	}
	var  []layered.LEdgeID
	for ,  := range .Graph().LayerlessNodes {
		 := .Node()
		,  := basegraph.TryGet(
			&.Properties, core.PartitioningPartition)
		if ! {
			continue
		}
		for ,  := range .NodeOutgoingEdges() {
			 := .Edge()
			if .Target == nil || .Port(*.Target).Node == nil {
				continue
			}
			 := .Node(*.Port(*.Target).Node)
			,  := basegraph.TryGet(
				&.Properties, core.PartitioningPartition)
			if  &&  >  ||
				! && reachesLowerPartition(
					, , , ) {
				 = append(, )
			}
		}
	}
	for ,  := range  {
		.ReverseEdge(, , true)
		 := partitionConstraintEdgePriority
		if ,  := basegraph.TryGet(
			&.Edge().Properties, layered.PriorityDirection);  {
			 += 
		}
		basegraph.Set(&.Edge().Properties, layered.PriorityDirection, )
	}
}

// reachesLowerPartition ports ELK 0.12's breadth-first search through nodes
// without a partition. The source edge is reversed when any reachable
// partitioned node has a lower partition ID; the remainder of that path is
// deliberately left to the ordinary cycle-breaking/layering pipeline.
func reachesLowerPartition(
	 *layered.LGraphArena,
	 layered.LNodeID,
	 int,
	 []layered.LNodeID,
) bool {
	 := make(map[layered.LNodeID]struct{})
	for ,  := range  {
		 := basegraph.Get(&.Node().Properties, core.PartitioningPartition)
		if  <  {
			[] = struct{}{}
		}
	}
	 := []layered.LNodeID{}
	 := map[layered.LNodeID]struct{}{: {}}
	for len() != 0 {
		 := [0]
		 = [1:]
		if ,  := [];  {
			return true
		}
		for ,  := range .NodeOutgoingEdges() {
			 := .EdgeTargetNode()
			if ,  := [];  {
				continue
			}
			[] = struct{}{}
			 = append(, )
		}
	}
	return false
}

// ProcessPartitionsBeforeLayering connects every node in a partition to every
// node in the next partition through disposable constraint ports and edges.
func ( *layered.LGraphArena,  layered.LGraphID) {
	 := make(map[int][]layered.LNodeID)
	 := make([]int, 0)
	for ,  := range .Graph().LayerlessNodes {
		,  := basegraph.TryGet(
			&.Node().Properties, core.PartitioningPartition)
		if ! {
			continue
		}
		if ,  := []; ! {
			 = append(, )
		}
		[] = append([], )
	}
	if len() < 2 {
		return
	}
	sort.Ints()
	for  := 0; +1 < len(); ++ {
		connectPartitions(,
			[[]],
			[[+1]])
	}
}

func connectPartitions(
	 *layered.LGraphArena,
	,  []layered.LNodeID,
) {
	for ,  := range  {
		 := .AddPort()
		.SetPortNode(, &)
		.SetPortSide(, layered.EastSide)
		basegraph.Set(&.Port().Properties, layered.PartitionDummy, true)

		for ,  := range  {
			 := .AddPort()
			.SetPortNode(, &)
			.SetPortSide(, layered.WestSide)
			basegraph.Set(&.Port().Properties, layered.PartitionDummy, true)

			 := .AddEdge()
			basegraph.Set(&.Edge().Properties, layered.PartitionDummy, true)
			.SetEdgeSource(, &)
			.SetEdgeTarget(, &)
		}
	}
}

// PostprocessPartitions detaches the disposable partition ports after
// layering. Their incident constraint edges consequently disappear from the
// graph topology, exactly as when ELK removes the ports from each node.
func ( *layered.LGraphArena,  layered.LGraphID) {
	for ,  := range .Graph().Layers {
		for ,  := range .Layer().Nodes {
			 := append([]layered.LPortID(nil), .Node().Ports...)
			for ,  := range  {
				if basegraph.Get(&.Port().Properties, layered.PartitionDummy) {
					.SetPortNode(, nil)
				}
			}
		}
	}
}