// Copyright (c) 2011, 2019 Kiel University and others.
// Copyright (c) 2026 The elk-go Authors.
//
// 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 p3order

import (
	

	
	basegraph 
	
)

// InteractiveCrossingMinimizer orders nodes by their previous vertical
// positions and reconstructs previous long-edge positions at each layer.
type InteractiveCrossingMinimizer struct{}

func (*InteractiveCrossingMinimizer) (
	 *layered.LGraphArena,
	 layered.LGraphID,
) layered.ProcessorConfiguration {
	var  layered.ProcessorConfiguration
	.
		AddBefore(layered.PhaseNodeOrdering, layered.LongEdgeSplitter).
		AddBefore(layered.PhaseNodePlacement, layered.InLayerConstraintProcessor).
		AddAfter(layered.PhaseEdgeRouting, layered.LongEdgeJoiner)
	if basegraph.Get(&.Graph().Properties, layered.GraphProperties)&layered.GraphPropertyNonFreePorts != 0 {
		.AddBefore(layered.PhaseNodeOrdering, layered.PortListSorter)
	}
	return 
}

func (*InteractiveCrossingMinimizer) ( *layered.LGraphArena,  layered.LGraphID) error {
	 := .Graph()
	 := make([][]layered.LNodeID, len(.Layers))
	for ,  := range .Layers {
		.Layer().ID = 
		[] = append([]layered.LNodeID(nil), .Layer().Nodes...)
	}
	 := NewBarycenterPortDistributor(NodeRelativePortDistributor, len())
	InitializeBarycenterPortDistributor(, , )

	 := 0
	for ,  := range .Layers {
		 := .Layer()
		 := 0.0
		 := 0
		for ,  := range .Nodes {
			 := .Node()
			if .Position.X > 0 {
				 += .Position.X + .Size.X/2
				++
			}
			for ,  := range .Ports {
				.Port().ID = 
				++
			}
		}
		if  > 0 {
			 /= float64()
		}

		 := make([]float64, len(.Nodes))
		for ,  := range .Nodes {
			.Node().ID = 
			[] = interactiveNodePosition(, , )
			if .Node().Type == layered.LongEdgeNode {
				basegraph.Set(&.Node().Properties, layered.OriginalDummyNodePosition, [])
			}
		}
		sort.SliceStable(.Nodes, func(,  int) bool {
			,  := .Nodes[], .Nodes[]
			 := compareInteractiveFloat([.Node().ID], [.Node().ID])
			if  == 0 {
				for ,  := range basegraph.Get(&.Node().Properties, layered.InLayerSuccessorConstraints) {
					if  ==  {
						return true
					}
				}
				for ,  := range basegraph.Get(&.Node().Properties, layered.InLayerSuccessorConstraints) {
					if  ==  {
						return false
					}
				}
			}
			return  < 0
		})
		.DistributePortsWhileSweeping(, , , true)
	}
	return nil
}
func interactiveNodePosition(
	 *layered.LGraphArena,
	 layered.LNodeID,
	 float64,
) float64 {
	 := .Node()
	switch .Type {
	case layered.LongEdgeNode:
		,  := basegraph.TryGet(&.Properties, layered.OriginalElement)
		if  && .Kind == layered.OriginLEdge {
			 := .Edge(.LEdge)
			 := basegraph.Get(&.Properties, layered.OriginalBendPoints).Clone()
			if basegraph.Get(&.Properties, layered.Reversed) {
				 = .Reverse()
			}
			if ,  := basegraph.TryGet(&.Properties, layered.LongEdgeSource);  {
				 := interactiveAbsoluteAnchor(, )
				if  <= .X {
					return .Y
				}
				 = append(geometry.Chain{}, ...)
			}
			if ,  := basegraph.TryGet(&.Properties, layered.LongEdgeTarget);  {
				 := interactiveAbsoluteAnchor(, )
				if .X <=  {
					return .Y
				}
				 = append(, )
			}
			if len() >= 2 {
				,  := [0], [1]
				 := 2
				for .X <  &&  < len() {
					,  = , []
					++
				}
				return .Y + (-.X)/(.X-.X)*(.Y-.Y)
			}
		}
	case layered.NorthSouthPortNode:
		if len(.Ports) > 0 {
			,  := basegraph.TryGet(&.Port(.Ports[0]).Properties, layered.OriginalElement)
			if  && .Kind == layered.OriginLPort {
				 := .Port(.LPort)
				if .Node != nil {
					 := .Node(*.Node)
					switch .Side {
					case layered.NorthSide:
						return .Position.Y
					case layered.SouthSide:
						return .Position.Y + .Size.Y
					}
				}
			}
		}
	}
	 := .Position.Y
	if basegraph.Get(&.Graph(.NodeGraph()).Properties, layered.InteractiveReferencePointOption) == layered.InteractiveReferenceCenter {
		 += .Size.Y / 2
	}
	return 
}

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

func compareInteractiveFloat(,  float64) int {
	if  <  {
		return -1
	}
	if  >  {
		return 1
	}
	return 0
}