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

// CrossMinType is LayerSweepCrossingMinimizer.CrossMinType. Declaration
// order follows ELK 0.8.1 and is observable through the zero value used by the
// phase-three provider.
type CrossMinType uint8

const (
	CrossMinBarycenter CrossMinType = iota
	CrossMinOneSidedGreedySwitch
	CrossMinTwoSidedGreedySwitch
)

// GraphInfoHolder collects all state initialized by a single IInitializable
// traversal of one graph.
type GraphInfoHolder struct {
	LGraph layered.LGraphID

	CurrentNodeOrder              [][]layered.LNodeID
	CurrentlyBestNodeAndPortOrder *SweepCopy
	BestNodeAndPortOrder          *SweepCopy
	PortPositions                 []int
	UseBottomUp                   bool
	ChildGraphs                   []layered.LGraphID
	HasExternalPorts              bool
	HasParent                     bool
	Parent                        *layered.LNodeID
	ParentGraphData               *GraphInfoHolder
	CrossMinType                  CrossMinType
	CrossMinimizer                crossingMinimizationHeuristic
	PortDistributor               sweepPortDistributor
	CrossingsCounter              *AllCrossingsCounter
	nPorts                        int
}

func (
	 *layered.LGraphArena,
	 layered.LGraphID,
	 CrossMinType,
	 []*GraphInfoHolder,
	 *javacompat.Random,
) (*GraphInfoHolder, error) {
	 := .Graph()
	,  := basegraph.TryGet(&.Properties, layered.Random)
	if ! ||  == nil {
		 = 
		basegraph.Set(&.Properties, layered.Random, )
	}
	 := make([][]layered.LNodeID, len(.Layers))
	for ,  := range .Layers {
		[] = append([]layered.LNodeID(nil), .Layer().Nodes...)
	}

	 := &GraphInfoHolder{
		LGraph:           ,
		CurrentNodeOrder: ,
		HasParent:        .ParentNode != nil,
		Parent:           copyNodeID(.ParentNode),
		CrossMinType:     ,
		CrossingsCounter: NewAllCrossingsCounter(len()),
	}
	if .HasParent {
		 := .Graph(.NodeGraph(*.Parent)).ID
		if  < 0 ||  >= len() {
			return nil, fmt.Errorf("p3order: parent graph index %d is not initialized", )
		}
		.ParentGraphData = []
	}
	.HasExternalPorts = basegraph.Get(&.Properties, layered.GraphProperties)&
		layered.GraphPropertyExternalPorts != 0

	 := NewLayerSweepTypeDecider(len())
	var  *ForsterConstraintResolver
	var  *BarycenterPortDistributor
	var  *GreedyPortDistributor
	var  *GreedySwitchHeuristic
	if  == CrossMinTwoSidedGreedySwitch {
		 = NewGreedyPortDistributor()
		.PortDistributor = 
	} else {
		// ISweepPortDistributor.create consumes one boolean for BARYCENTER and
		// ONE_SIDED_GREEDY_SWITCH, but none for TWO_SIDED_GREEDY_SWITCH.
		 := LayerTotalPortDistributor
		if .NextBoolean() {
			 = NodeRelativePortDistributor
		}
		 = NewBarycenterPortDistributor(, len())
		.PortDistributor = 
	}
	if  == CrossMinBarycenter {
		 = NewForsterConstraintResolver(, )
		 := NewBarycenterHeuristic(, , , )
		if basegraph.Get(&.Properties, layered.ForceNodeModelOrder) {
			.ModelOrder = NewModelOrderBarycenterHeuristic(true)
		}
		.CrossMinimizer = 
	} else {
		 = NewGreedySwitchHeuristic(, , )
		.CrossMinimizer = 
	}

	// IInitializable.init invokes every initializable at each level before
	// descending. Keep this flattened traversal source-shaped because node and
	// port scratch IDs are shared by several helpers.
	for ,  := range  {
		.InitAtLayerLevel(, , )
		if  != nil {
			.InitAtLayerLevel(, )
		}
		if  != nil {
			.InitAtLayerLevel(, )
		}
		 := *.Node([0]).Layer
		.Layer().ID = 
		if  != nil {
			.InitAtLayerLevel(, , )
		}

		for ,  := range  {
			if  := .Node().NestedGraph;  != nil {
				.ChildGraphs = append(.ChildGraphs, *)
			}
			.CrossingsCounter.InitAtNodeLevel(, , , )
			.InitAtNodeLevel(, , , )
			if  != nil {
				.InitAtNodeLevel(, , , )
			} else {
				.InitAtNodeLevel(, , , )
			}
			if  != nil {
				.InitAtNodeLevel(, , , )
			}

			for ,  := range .Node().Ports {
				.nPorts++
				.CrossingsCounter.InitAtPortLevel(, , , , )
				if  != nil {
					.InitAtPortLevel(, , , , )
				}
				if  != nil {
					.InitAtPortLevel()
				}
				for ,  := range .PortConnectedEdges() {
					.CrossingsCounter.InitAtEdgeLevel(
						, , , , , ,
					)
				}
			}
		}
	}
	.PortPositions = make([]int, .nPorts)
	.CrossingsCounter.InitAfterTraversal()
	if  != nil {
		.InitAfterTraversal()
	} else {
		.InitAfterTraversal()
	}
	if  != nil {
		.InitAfterTraversal()
	}
	.UseBottomUp = .UseBottomUp(
		, , .Parent, .CrossMinDeterministic(), ,
	)
	return , nil
}

func ( *GraphInfoHolder) () bool { return .UseBottomUp }

func ( *GraphInfoHolder) () bool {
	return .CrossMinType != CrossMinBarycenter
}

func ( *GraphInfoHolder) () bool {
	return .CrossMinType == CrossMinTwoSidedGreedySwitch
}

func ( *GraphInfoHolder) () *SweepCopy {
	if .CrossMinDeterministic() {
		return .CurrentlyBestNodeAndPortOrder
	}
	return .BestNodeAndPortOrder
}

func copyNodeID( *layered.LNodeID) *layered.LNodeID {
	if  == nil {
		return nil
	}
	 := *
	return &
}