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

package ordering

import (
	
	

	basegraph 
	
	
)

// AssignPortSides ports ELK 0.8.1's PortSideAssigner.
func ( *layered.LGraphArena,  *loops.Holder) error {
	switch basegraph.Get(&.Node(.LNode).Properties, layered.SelfLoopDistribution) {
	case layered.SelfLoopDistributionNorth:
		for ,  := range .HyperLoops {
			for ,  := range .Ports {
				if .Hidden {
					.SetPortSide(.LPort, layered.NorthSide)
				}
			}
		}

	case layered.SelfLoopDistributionNorthSouth:
		,  := 0, 0
		for ,  := range .HyperLoops {
			 := hiddenPorts()
			 := layered.NorthSide
			if  <=  {
				 += len()
			} else {
				 = layered.SouthSide
				 += len()
			}
			for ,  := range  {
				.SetPortSide(.LPort, )
			}
		}

	case layered.SelfLoopDistributionEqually:
		assignToAllSides(, )

	default:
		return fmt.Errorf("unsupported self-loop distribution strategy")
	}

	for ,  := range .PortOrder {
		if .Port().Side == layered.UndefinedSide {
			return fmt.Errorf("self-loop port %d remains unassigned", )
		}
	}
	return nil
}

type assignmentTarget struct {
	first, second layered.PortSide
}

var assignmentTargets = []assignmentTarget{
	{layered.NorthSide, layered.NorthSide},
	{layered.SouthSide, layered.SouthSide},
	{layered.EastSide, layered.EastSide},
	{layered.WestSide, layered.WestSide},
	{layered.WestSide, layered.NorthSide},
	{layered.NorthSide, layered.EastSide},
	{layered.SouthSide, layered.WestSide},
	{layered.EastSide, layered.SouthSide},
}

func assignToAllSides( *layered.LGraphArena,  *loops.Holder) {
	 := append([]*loops.HyperLoop(nil), .HyperLoops...)
	sort.SliceStable(, func(,  int) bool {
		return len([].Ports) > len([].Ports)
	})
	for ,  := range  {
		assignToTarget(, , assignmentTargets[%len(assignmentTargets)])
	}
}

func assignToTarget( *layered.LGraphArena,  *loops.HyperLoop,  assignmentTarget) {
	// Java sorts the loop's actual list here. List.sort is stable.
	if .first != .second {
		sort.SliceStable(.Ports, func(,  int) bool {
			 := .Port(.Ports[].LPort)
			 := .Port(.Ports[].LPort)
			return len(.IncomingEdges)-len(.OutgoingEdges) <
				len(.IncomingEdges)-len(.OutgoingEdges)
		})
	}
	 := len(.Ports) / 2
	for ,  := range .Ports {
		if !.Hidden {
			continue
		}
		 := .second
		if  <  {
			 = .first
		}
		.SetPortSide(.LPort, )
	}
}

func hiddenPorts( *loops.HyperLoop) []*loops.Port {
	 := make([]*loops.Port, 0, len(.Ports))
	for ,  := range .Ports {
		if .Hidden {
			 = append(, )
		}
	}
	return 
}