// Copyright (c) 2015 Kiel University and others.
// Copyright (c) 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 layered

import (
	

	basegraph 
)

type spacingTables struct {
	horizontal [6][6]*basegraph.Property[float64]
	vertical   [6][6]*basegraph.Property[float64]
}

var (
	spacingsOnce sync.Once
	spacingsData spacingTables
)

func layeredSpacingTables() *spacingTables {
	spacingsOnce.Do(func() {
		 := func(,  NodeType, ,  *basegraph.Property[float64]) {
			spacingsData.vertical[][] = 
			spacingsData.vertical[][] = 
			spacingsData.horizontal[][] = 
			spacingsData.horizontal[][] = 
		}
		 := func(,  NodeType,  *basegraph.Property[float64]) {
			spacingsData.vertical[][] = 
			spacingsData.vertical[][] = 
		}

		(NormalNode, NormalNode, &SpacingNodeNode, &SpacingNodeNodeBetweenLayers)
		(NormalNode, LongEdgeNode, &SpacingEdgeNode, &SpacingEdgeNodeBetweenLayers)
		(NormalNode, NorthSouthPortNode, &SpacingEdgeNode)
		(NormalNode, ExternalPortNode, &SpacingEdgeNode)
		(NormalNode, LabelNode, &SpacingNodeNode, &SpacingNodeNodeBetweenLayers)

		(LongEdgeNode, LongEdgeNode, &SpacingEdgeEdge, &SpacingEdgeEdgeBetweenLayers)
		(LongEdgeNode, NorthSouthPortNode, &SpacingEdgeEdge)
		(LongEdgeNode, ExternalPortNode, &SpacingEdgeEdge)
		(LongEdgeNode, LabelNode, &SpacingEdgeNode, &SpacingEdgeNodeBetweenLayers)

		(NorthSouthPortNode, NorthSouthPortNode, &SpacingEdgeEdge)
		(NorthSouthPortNode, ExternalPortNode, &SpacingEdgeEdge)
		(NorthSouthPortNode, LabelNode, &SpacingLabelNode)

		(ExternalPortNode, ExternalPortNode, &SpacingPortPort)
		(ExternalPortNode, LabelNode, &SpacingLabelPortVertical, &SpacingLabelPortHorizontal)

		(LabelNode, LabelNode, &SpacingEdgeEdge, &SpacingEdgeEdge)

		(BreakingPointNode, BreakingPointNode, &SpacingEdgeEdge, &SpacingEdgeEdgeBetweenLayers)
		(BreakingPointNode, NormalNode, &SpacingEdgeNode, &SpacingEdgeNodeBetweenLayers)
		(BreakingPointNode, LabelNode, &SpacingEdgeNode, &SpacingEdgeNodeBetweenLayers)
		(BreakingPointNode, LongEdgeNode, &SpacingEdgeNode, &SpacingEdgeNodeBetweenLayers)
	})
	return &spacingsData
}

func individualOrDefault(
	 *LGraphArena,
	 LNodeID,
	 *basegraph.Property[float64],
) float64 {
	 := .Node()
	if ,  := basegraph.TryGet(&.Properties, SpacingIndividual);  {
		if ,  := basegraph.TryGet(&.Properties, *);  {
			return 
		}
	}
	return basegraph.Get(&.Graph(.NodeGraph()).Properties, *)
}

// IndividualOrDefault exposes LayeredSpacings.getIndividualOrDefault to
// source-shaped phase implementations.
func (
	 *LGraphArena,
	 LNodeID,
	 *basegraph.Property[float64],
) float64 {
	return individualOrDefault(, , )
}

func nodeSpacing(
	 *LGraphArena,
	,  LNodeID,
	 *[6][6]*basegraph.Property[float64],
) float64 {
	,  := .Node().Type, .Node().Type
	 := [][]
	if  == nil {
		panic("layered: unspecified spacing between node types")
	}
	 := individualOrDefault(, , )
	 := individualOrDefault(, , )
	if  >  {
		return 
	}
	return 
}

func ( *LGraphArena, ,  LNodeID) float64 {
	return nodeSpacing(, , , &layeredSpacingTables().horizontal)
}

func ( *LGraphArena, ,  LNodeID) float64 {
	return nodeSpacing(, , , &layeredSpacingTables().vertical)
}

func ( *LGraphArena,  LGraphID, ,  NodeType) float64 {
	 := layeredSpacingTables().horizontal[][]
	if  == nil {
		panic("layered: unspecified horizontal spacing between node types")
	}
	return basegraph.Get(&.Graph().Properties, *)
}

func ( *LGraphArena,  LGraphID, ,  NodeType) float64 {
	 := layeredSpacingTables().vertical[][]
	if  == nil {
		panic("layered: unspecified vertical spacing between node types")
	}
	return basegraph.Get(&.Graph().Properties, *)
}

// ApplySpacingBaseValue reproduces LayeredSpacings.withBaseValue. Explicit
// values remain authoritative; all absent dependent spacings are scaled by
// their ELK 0.8.1 default-to-nodeNode-default ratio.
func ( *basegraph.PropertyMap,  float64) {
	 := basegraph.Get(&basegraph.PropertyMap{}, SpacingNodeNode)
	basegraph.Set(, SpacingNodeNode, )
	 := []*basegraph.Property[float64]{
		&SpacingComponentComponent,
		&SpacingEdgeEdge,
		&SpacingEdgeLabel,
		&SpacingEdgeNode,
		&SpacingLabelLabel,
		&SpacingLabelNode,
		&SpacingLabelPortHorizontal,
		&SpacingLabelPortVertical,
		&SpacingNodeSelfLoop,
		&SpacingPortPort,
		&SpacingEdgeEdgeBetweenLayers,
		&SpacingEdgeNodeBetweenLayers,
		&SpacingNodeNodeBetweenLayers,
	}
	for ,  := range  {
		if basegraph.Has(, *) {
			continue
		}
		 := basegraph.Get(&basegraph.PropertyMap{}, *)
		basegraph.Set(, *, */)
	}
}