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

import (
	
	

	
)

type VerticalDirection uint8

const (
	VerticalBalanced VerticalDirection = iota
	VerticalDown
	VerticalUp
)

type HorizontalDirection uint8

const (
	HorizontalBalanced HorizontalDirection = iota
	HorizontalRight
	HorizontalLeft
)

// BKAlignedLayout contains all per-node data for one of the four directional
// Brandes-Koepf layouts. Pointer entries preserve Java's null-filled object
// arrays and make missing algorithm initialization fail loudly.
type BKAlignedLayout struct {
	Root       []*layered.LNodeID
	BlockSize  []*float64
	Align      []*layered.LNodeID
	InnerShift []*float64
	Sink       []*layered.LNodeID
	Shift      []*float64
	Y          []*float64
	VDirection VerticalDirection
	HDirection HorizontalDirection
	SU         []bool
	OD         []bool
	Graph      layered.LGraphID
}

func (
	 layered.LGraphID,
	 int,
	 VerticalDirection,
	 HorizontalDirection,
) *BKAlignedLayout {
	 := make([]bool, )
	for  := range  {
		[] = true
	}
	return &BKAlignedLayout{
		Root: make([]*layered.LNodeID, ), BlockSize: make([]*float64, ),
		Align: make([]*layered.LNodeID, ), InnerShift: make([]*float64, ),
		Sink: make([]*layered.LNodeID, ), Shift: make([]*float64, ),
		Y: make([]*float64, ), SU: make([]bool, ), OD: ,
		VDirection: , HDirection: , Graph: ,
	}
}

func ( *BKAlignedLayout) () {
	.Root = nil
	.BlockSize = nil
	.Align = nil
	.InnerShift = nil
	.Sink = nil
	.Shift = nil
	.Y = nil
}

func ( *BKAlignedLayout) ( *layered.LGraphArena) float64 {
	,  := math.Inf(1), math.Inf(-1)
	for ,  := range .Graph(.Graph).Layers {
		for ,  := range .Layer().Nodes {
			 := .Node().ID
			 := requireFloat(.Y[], "y")
			 := requireNode(.Root[], "root")
			 :=  + requireFloat(.BlockSize[.Node().ID], "block size")
			 = math.Min(, )
			 = math.Max(, )
		}
	}
	return  - 
}

func ( *BKAlignedLayout) (
	 *layered.LGraphArena,
	,  layered.LPortID,
) float64 {
	,  := *.Port().Node, *.Port().Node
	 := .Port()
	 := .Port()
	 := requireFloat(.Y[.Node().ID], "y") +
		requireFloat(.InnerShift[.Node().ID], "inner shift") +
		.Position.Y + .Anchor.Y
	 := requireFloat(.Y[.Node().ID], "y") +
		requireFloat(.InnerShift[.Node().ID], "inner shift") +
		.Position.Y + .Anchor.Y
	return  - 
}

func ( *BKAlignedLayout) (
	 *layered.LGraphArena,
	 layered.LNodeID,
	 float64,
) {
	 := 
	for {
		 := .Node().ID
		 := requireFloat(.Y[], "y") + 
		.Y[] = floatPointer()
		 = requireNode(.Align[], "align")
		if  ==  {
			return
		}
	}
}

func ( *BKAlignedLayout) (
	 *layered.LGraphArena,
	 layered.LNodeID,
	 float64,
	 *NeighborhoodInformation,
) float64 {
	 := 
	 := 
	for {
		 = requireNode(.Align[.Node().ID], "align")
		 := .MinY(, )
		if ,  := .upperNeighbor(, , );  {
			 = math.Min(, -(.MaxY(, )+layered.VerticalSpacing(, , )))
		}
		if  ==  {
			return 
		}
	}
}

func ( *BKAlignedLayout) (
	 *layered.LGraphArena,
	 layered.LNodeID,
	 float64,
	 *NeighborhoodInformation,
) float64 {
	 := 
	 := 
	for {
		 = requireNode(.Align[.Node().ID], "align")
		 := .MaxY(, )
		if ,  := .lowerNeighbor(, , );  {
			 = math.Min(, .MinY(, )-(+layered.VerticalSpacing(, , )))
		}
		if  ==  {
			return 
		}
	}
}

func ( *BKAlignedLayout) ( *layered.LGraphArena,  layered.LNodeID) float64 {
	 := .Node().ID
	 := requireNode(.Root[], "root")
	return requireFloat(.Y[.Node().ID], "y") +
		requireFloat(.InnerShift[], "inner shift") - .Node().Margin.Top
}

func ( *BKAlignedLayout) ( *layered.LGraphArena,  layered.LNodeID) float64 {
	 := .Node().ID
	 := requireNode(.Root[], "root")
	return requireFloat(.Y[.Node().ID], "y") +
		requireFloat(.InnerShift[], "inner shift") + .Node().Size.Y + .Node().Margin.Bottom
}

func ( *BKAlignedLayout) (
	 *layered.LGraphArena,
	 layered.LNodeID,
	 *NeighborhoodInformation,
) (layered.LNodeID, bool) {
	 := *.Node().Layer
	 := .NodeIndex[.Node().ID]
	if  < len(.Layer().Nodes)-1 {
		return .Layer().Nodes[+1], true
	}
	return 0, false
}

func ( *BKAlignedLayout) (
	 *layered.LGraphArena,
	 layered.LNodeID,
	 *NeighborhoodInformation,
) (layered.LNodeID, bool) {
	 := *.Node().Layer
	 := .NodeIndex[.Node().ID]
	if  > 0 {
		return .Layer().Nodes[-1], true
	}
	return 0, false
}

func ( *BKAlignedLayout) () string {
	 := ""
	switch .HDirection {
	case HorizontalRight:
		 = "RIGHT"
	case HorizontalLeft:
		 = "LEFT"
	}
	switch .VDirection {
	case VerticalDown:
		return  + "DOWN"
	case VerticalUp:
		return  + "UP"
	default:
		return  + "BALANCED"
	}
}

func nodePointer( layered.LNodeID) *layered.LNodeID { return & }
func floatPointer( float64) *float64                { return & }

func requireNode( *layered.LNodeID,  string) layered.LNodeID {
	if  == nil {
		panic(fmt.Sprintf("p4nodes: uninitialized %s", ))
	}
	return *
}

func requireFloat( *float64,  string) float64 {
	if  == nil {
		panic(fmt.Sprintf("p4nodes: uninitialized %s", ))
	}
	return *
}