// Copyright (c) 2021 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 p3order

import (
	basegraph 
	
	
	
)

// ModelOrderBarycenterHeuristic is ELK 0.8.1's partial-order comparator used
// when model order is considered during crossing minimization.
type ModelOrderBarycenterHeuristic struct {
	ForceNodeModelOrder bool
	biggerThan          map[layered.LNodeID]map[layered.LNodeID]bool
	smallerThan         map[layered.LNodeID]map[layered.LNodeID]bool
}

func ( bool) *ModelOrderBarycenterHeuristic {
	return &ModelOrderBarycenterHeuristic{
		ForceNodeModelOrder: ,
		biggerThan:          make(map[layered.LNodeID]map[layered.LNodeID]bool),
		smallerThan:         make(map[layered.LNodeID]map[layered.LNodeID]bool),
	}
}

func ( *ModelOrderBarycenterHeuristic) (
	 *BarycenterHeuristic,
	 []layered.LNodeID,
) {
	 := func(,  layered.LNodeID) int {
		return .compare(, , )
	}
	if .ForceNodeModelOrder {
		for  := 1;  < len(); ++ {
			 := []
			 := 
			for  > 0 && ([-1], ) > 0 {
				[] = [-1]
				--
			}
			[] = 
		}
		.ClearTransitiveOrdering()
		return
	}
	javacompat.GWTStableSort(, )
}

func ( *ModelOrderBarycenterHeuristic) (
	 *BarycenterHeuristic,
	,  layered.LNodeID,
) int {
	if  := .compareTransitive(, );  != 0 {
		return 
	}
	,  := .Arena.Node(), .Arena.Node()
	if basegraph.Has(&.Properties, layered.ModelOrder) && basegraph.Has(&.Properties, layered.ModelOrder) {
		 := .Arena.Graph(.Arena.NodeGraph())
		 := basegraph.Get(&.Properties, layered.MaximumModelOrderNodes)
		 := compareInt(
			preserveorder.CalculateModelOrderOrGroupModelOrder(
				, &.Properties, &.Properties, ),
			preserveorder.CalculateModelOrderOrGroupModelOrder(
				, &.Properties, &.Properties, ),
		)
		if basegraph.Get(&.Properties, layered.CrossingMinimizationGroupOrder) ==
			layered.GroupOrderOnlyWithinGroup &&
			basegraph.Get(&.Properties, layered.CrossingMinimizationGroupID) !=
				basegraph.Get(&.Properties, layered.CrossingMinimizationGroupID) {
			 = 0
		}
		if  < 0 {
			.update(, )
			return 
		} else if  > 0 {
			.update(, )
			return 
		}
		// Since ELK 0.11, equal model-order values no longer freeze the
		// relative order. Fall back to the barycenter comparison so the
		// connected port geometry can break the tie.
	}
	 := .compareBarycenters(, )
	if  < 0 {
		.update(, )
	} else if  > 0 {
		.update(, )
	}
	return 
}

func ( *ModelOrderBarycenterHeuristic) (,  layered.LNodeID) int {
	.ensure()
	if .biggerThan[][] {
		return 1
	}
	.ensure()
	if .biggerThan[][] {
		return -1
	}
	if .smallerThan[][] {
		return -1
	}
	if .smallerThan[][] {
		return 1
	}
	return 0
}

// bigger/smaller names follow Java: update(bigger,smaller) records that the
// comparator found bigger < smaller in the final order.
func ( *ModelOrderBarycenterHeuristic) (,  layered.LNodeID) {
	.ensure()
	.ensure()
	 := keysOf(.biggerThan[])
	 := keysOf(.smallerThan[])
	.biggerThan[][] = true
	.smallerThan[][] = true
	for ,  := range  {
		.biggerThan[][] = true
		.smallerThan[][] = true
		for ,  := range  {
			.smallerThan[][] = true
		}
	}
	for ,  := range  {
		.smallerThan[][] = true
		.biggerThan[][] = true
		for ,  := range  {
			.biggerThan[][] = true
		}
	}
}

func ( *ModelOrderBarycenterHeuristic) ( layered.LNodeID) {
	if .biggerThan[] == nil {
		.biggerThan[] = make(map[layered.LNodeID]bool)
	}
	if .smallerThan[] == nil {
		.smallerThan[] = make(map[layered.LNodeID]bool)
	}
}

func ( *ModelOrderBarycenterHeuristic) () {
	.biggerThan = make(map[layered.LNodeID]map[layered.LNodeID]bool)
	.smallerThan = make(map[layered.LNodeID]map[layered.LNodeID]bool)
}

func keysOf( map[layered.LNodeID]bool) []layered.LNodeID {
	 := make([]layered.LNodeID, 0, len())
	for  := range  {
		 = append(, )
	}
	return 
}

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