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

import (
	
	

	
)

// HyperEdgeSegment is the trunk of an ELK orthogonal hyperedge. Coordinate
// lists are kept sorted and duplicate-free exactly as in ELK 0.8.1.
type HyperEdgeSegment struct {
	strategy *routingDirectionStrategy

	Ports []layered.LPortID
	Mark  int

	RoutingSlot int
	Start       float64
	End         float64

	IncomingCoordinates []float64
	OutgoingCoordinates []float64

	OutgoingDependencies []*HyperEdgeSegmentDependency
	IncomingDependencies []*HyperEdgeSegmentDependency
	OutWeight            int
	CriticalOutWeight    int
	InWeight             int
	CriticalInWeight     int

	SplitPartner *HyperEdgeSegment
	SplitBy      *HyperEdgeSegment
}

func newHyperEdgeSegment( *routingDirectionStrategy) *HyperEdgeSegment {
	return &HyperEdgeSegment{strategy: , Start: math.NaN(), End: math.NaN()}
}

// NewBareSegment is new HyperEdgeSegment(null), used by ELK's self-loop
// RoutingSlotAssigner to reuse the weighted dependency cycle breaker.
func () *HyperEdgeSegment { return newHyperEdgeSegment(nil) }

// NewTestSegment creates a source-shaped segment without graph ports. It is
// exported for white-box conformance tests and cycle-routing helpers.
func (,  []float64) *HyperEdgeSegment {
	 := newHyperEdgeSegment(newRoutingDirectionStrategy(WestToEast))
	.IncomingCoordinates = append([]float64(nil), ...)
	.OutgoingCoordinates = append([]float64(nil), ...)
	sort.Float64s(.IncomingCoordinates)
	sort.Float64s(.OutgoingCoordinates)
	.RecomputeExtent()
	return 
}

func ( *HyperEdgeSegment) (
	 *layered.LGraphArena,
	 layered.LPortID,
	 map[layered.LPortID]*HyperEdgeSegment,
) {
	[] = 
	.Ports = append(.Ports, )
	 := .Port()
	 := .strategy.portPosition(, )
	if .Side == .strategy.sourcePortSide() {
		.IncomingCoordinates = insertSortedUnique(.IncomingCoordinates, )
	} else {
		.OutgoingCoordinates = insertSortedUnique(.OutgoingCoordinates, )
	}
	.RecomputeExtent()

	// LPort.getConnectedPorts() yields predecessors first, then successors.
	for ,  := range .IncomingEdges {
		 := *.Edge().Source
		if ,  := []; ! {
			.(, , )
		}
	}
	for ,  := range .OutgoingEdges {
		 := *.Edge().Target
		if ,  := []; ! {
			.(, , )
		}
	}
}

func insertSortedUnique( []float64,  float64) []float64 {
	for ,  := range  {
		// HyperEdgeSegment.java deliberately calls Double.floatValue here.
		// Keep the narrowing even though the list itself stores doubles.
		 := float64(float32())
		if  ==  {
			return 
		}
		if  >  {
			 = append(, 0)
			copy([+1:], [:])
			[] = 
			return 
		}
	}
	return append(, )
}

func ( *HyperEdgeSegment) () float64 { return .End - .Start }

func ( *HyperEdgeSegment) () bool {
	return len(.IncomingCoordinates)+len(.OutgoingCoordinates) > 2
}

func ( *HyperEdgeSegment) () bool {
	return .SplitPartner != nil && .SplitBy == nil
}

func ( *HyperEdgeSegment) () {
	.Start, .End = math.NaN(), math.NaN()
	.includeExtent(.IncomingCoordinates)
	.includeExtent(.OutgoingCoordinates)
}

func ( *HyperEdgeSegment) ( []float64) {
	if len() == 0 {
		return
	}
	if math.IsNaN(.Start) {
		.Start = [0]
	} else {
		.Start = math.Min(.Start, [0])
	}
	if math.IsNaN(.End) {
		.End = [len()-1]
	} else {
		.End = math.Max(.End, [len()-1])
	}
}

func ( *HyperEdgeSegment) () (*HyperEdgeSegment, *HyperEdgeSegment) {
	 := newHyperEdgeSegment(.strategy)
	 := newHyperEdgeSegment(.strategy)
	.IncomingCoordinates = append(.IncomingCoordinates, .IncomingCoordinates...)
	.SplitBy = .SplitBy
	.SplitPartner = 
	.RecomputeExtent()
	.OutgoingCoordinates = append(.OutgoingCoordinates, .OutgoingCoordinates...)
	.SplitPartner = 
	.RecomputeExtent()
	return , 
}

func ( *HyperEdgeSegment) ( float64) *HyperEdgeSegment {
	 := newHyperEdgeSegment(.strategy)
	.SplitPartner, .SplitPartner = , 
	.OutgoingCoordinates = append(.OutgoingCoordinates, .OutgoingCoordinates...)
	.OutgoingCoordinates = .OutgoingCoordinates[:0]
	.OutgoingCoordinates = append(.OutgoingCoordinates, )
	.IncomingCoordinates = append(.IncomingCoordinates, )
	.RecomputeExtent()
	.RecomputeExtent()
	for len(.IncomingDependencies) > 0 {
		.IncomingDependencies[0].Remove()
	}
	for len(.OutgoingDependencies) > 0 {
		.OutgoingDependencies[0].Remove()
	}
	return 
}