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

package layered

import (
	
	
	

	
	basegraph 
)

// copyTypedProperties reproduces LGraphElement.copyProperties and then
// normalizes metadata-layer string enums to the strongly typed values used by
// the native pipeline.
func copyTypedProperties( *basegraph.PropertyMap,  *basegraph.PropertyMap) {
	.CopyFrom()
	setEnum(, , DirectionOption, ParseDirection)
	setEnum(, , PortSideOption, ParsePortSide)
	setEnum(, , Hierarchy, parseHierarchyHandling)
	setEnum(, , PortConstraintsOption, parsePortConstraints)
	setEnum(, , EdgeRoutingOption, parseEdgeRouting)
	setEnum(, , AlignmentOption, parseAlignment)
	setEnum(, , CycleBreaking, ParseCycleBreakingStrategy)
	setEnum(, , Layering, ParseLayeringStrategy)
	setEnum(, , CrossingMinimization, parseCrossingMinimization)
	setEnum(, , NodePlacement, parseNodePlacement)
	setEnum(, , NetworkSimplexRecomputeNodePlacement, parseNodePlacement)
	setEnum(, , NetworkSimplexNodeFlexibility, parseNodeFlexibility)
	setEnum(, , NetworkSimplexNodeFlexibilityDefault, parseNodeFlexibility)
	setEnum(, , BKFixedAlignment, parseFixedAlignment)
	setEnum(, , BKEdgeStraightening, parseEdgeStraightening)
	setEnum(, , SplineRoutingModeOption, parseSplineRoutingMode)
	setEnum(, , PostCompactionStrategy, parseGraphCompactionStrategy)
	setEnum(, , PostCompactionConstraints, parseConstraintCalculationStrategy)
	setEnum(, , NodePromotionStrategyOption, parseNodePromotionStrategy)
	setEnum(, , PortSortingStrategyOption, parsePortSortingStrategy)
	setEnum(, , WrappingStrategyOption, parseWrappingStrategy)
	setEnum(, , WrappingCuttingStrategy, parseCuttingStrategy)
	setEnum(, , WrappingValidifyStrategy, parseValidifyStrategy)
	setEnum(, , ConsiderModelOrder, parseOrderingStrategy)
	setEnum(, , ComponentOrdering, parseComponentOrderingStrategy)
	setEnum(, , LongEdgeOrdering, parseLongEdgeOrderingStrategy)
	setEnum(, , CycleBreakingGroupOrder, parseGroupOrderStrategy)
	setEnum(, , CrossingMinimizationGroupOrder, parseGroupOrderStrategy)
	setEnum(, , LayerUnzippingStrategyOption, parseLayerUnzippingStrategy)
	setEnum(, , GreedySwitch, parseGreedySwitch)
	setEnum(, , GreedySwitchHierarchical, parseGreedySwitch)
	setEnum(, , LayerConstraintOption, parseLayerConstraint)
	setEnum(, , InteractiveReferencePointOption, parseInteractiveReferencePoint)
	setEnum(, , DirectionCongruencyOption, parseDirectionCongruency)
	setEnum(, , EdgeLabelsPlacement, parseEdgeLabelPlacement)
	setEnum(, , LabelSideOption, parseLabelSide)
	setEnum(, , SelfLoopDistribution, parseSelfLoopDistribution)
	setEnum(, , SelfLoopOrdering, parseSelfLoopOrdering)
	setEnum(, , CenterEdgeLabelPlacement, parseCenterEdgeLabelPlacement)
	setEnum(, , EdgeLabelSideSelectionOption, parseEdgeLabelSideSelection)

	copyInt(, , RandomSeed)
	copyInt(, , Thoroughness)
	copyInt(, , CoffmanGrahamLayerBound)
	copyInt(, , MinWidthUpperBound)
	copyInt(, , MinWidthUpperLayerScaling)
	copyInt(, , GreedySwitchActivationThreshold)
	copyInt(, , PriorityDirection)
	copyInt(, , PriorityShortness)
	copyInt(, , PriorityStraightness)
	copyInt(, , PortIndex)
	copyInt(, , LayerIDOption)
	copyInt(, , PositionIDOption)
	copyInt(, , PositionChoiceConstraint)
	copyInt(, , LayerChoiceConstraint)
	copyInt(, , NodePromotionMaxIterations)
	copyInt(, , HighDegreeNodeThreshold)
	copyInt(, , HighDegreeNodeTreeHeight)
	copyInt(, , LayerUnzippingLayerSplit)
	copyInt(, , CycleBreakingGroupID)
	copyInt(, , CrossingMinimizationGroupID)
	copyInt(, , ComponentGroupID)
	copyInt(, , CycleBreakingPreferredSourceID)
	copyInt(, , CycleBreakingPreferredTargetID)
	copyInt(, , WrappingCuttingMSDFreedom)
	copyBool(, , NoLayout)
	copyBool(, , SeparateComponents)
	copyBool(, , EdgeLabelsInline)
	copyBool(, , FavorStraightEdges)
	copyBool(, , ForceNodeModelOrder)
	copyBool(, , SemiInteractive)
	copyBool(, , GeneratePositionAndLayerIDs)
	copyBool(, , FeedbackEdges)
	copyBool(, , MergeEdges)
	copyBool(, , MergeHierarchyEdges)
	copyBool(, , UnnecessaryBendpoints)
	copyBool(, , NoModelOrder)
	copyBool(, , PortModelOrder)
	copyBool(, , LayerUnzippingMinimizeEdgeLength)
	copyBool(, , LayerUnzippingResetOnLongEdges)
	copyBool(, , HighDegreeNodeTreatment)
	copyBool(, , WrappingMultiEdgeImproveCuts)
	copyBool(, , WrappingMultiEdgeImproveWrappedEdges)

	for ,  := range []*basegraph.Property[float64]{
		&AspectRatio, &EdgeThickness, &PortBorderOffset,
		&LinearSegmentsDeflectionDampening, &HierarchicalSweepiness,
		&SpacingComponentComponent,
		&SpacingEdgeEdge, &SpacingEdgeLabel, &SpacingEdgeNode,
		&SpacingLabelLabel, &SpacingLabelNode, &SpacingLabelPortHorizontal,
		&SpacingLabelPortVertical, &SpacingNodeNode, &SpacingNodeSelfLoop,
		&SpacingPortPort, &SpacingBaseValue, &SpacingEdgeNodeBetweenLayers,
		&SpacingEdgeEdgeBetweenLayers, &SpacingNodeNodeBetweenLayers,
		&PolylineSlopedEdgeZoneWidth,
		&SplineSloppyLayerSpacingFactor,
		&WrappingAdditionalEdgeSpacing, &WrappingCorrectionFactor,
		&WrappingMultiEdgeDistancePenalty,
		&CrossingCounterNodeInfluence, &CrossingCounterPortInfluence,
	} {
		copyFloat(, , *)
	}

	// elkjs accepts these historical non-layered identifiers as unique
	// suffixes. The core codec preserves them exactly.
	copyFloatAlias(, , SpacingNodeNodeBetweenLayers,
		"org.eclipse.elk.spacing.nodeNodeBetweenLayers")
	copyFloatAlias(, , SpacingEdgeNodeBetweenLayers,
		"org.eclipse.elk.spacing.edgeNodeBetweenLayers")
	copyFloatAlias(, , SpacingEdgeEdgeBetweenLayers,
		"org.eclipse.elk.spacing.edgeEdgeBetweenLayers")
}

func setEnum[ any](
	,  *basegraph.PropertyMap,
	 basegraph.Property[],
	 func(string) (, bool),
) {
	,  := .Raw(.ID)
	if ! {
		return
	}
	if ,  := .();  {
		basegraph.Set(, , )
		return
	}
	if ,  := (fmt.Sprint());  {
		basegraph.Set(, , )
	}
}

func copyInt(,  *basegraph.PropertyMap,  basegraph.Property[int]) {
	,  := .Raw(.ID)
	if ! {
		return
	}
	switch typed := .(type) {
	case int:
		basegraph.Set(, , )
	case int32:
		basegraph.Set(, , int())
	case int64:
		basegraph.Set(, , int())
	case float64:
		basegraph.Set(, , int())
	case string:
		if ,  := strconv.Atoi();  == nil {
			basegraph.Set(, , )
		}
	}
}

func copyBool(,  *basegraph.PropertyMap,  basegraph.Property[bool]) {
	,  := .Raw(.ID)
	if ! {
		return
	}
	switch typed := .(type) {
	case bool:
		basegraph.Set(, , )
	case string:
		if ,  := strconv.ParseBool();  == nil {
			basegraph.Set(, , )
		}
	}
}

func copyFloat(,  *basegraph.PropertyMap,  basegraph.Property[float64]) {
	copyFloatAlias(, , , .ID)
}

func copyFloatAlias(,  *basegraph.PropertyMap,  basegraph.Property[float64],  string) {
	,  := .Raw()
	if ! {
		return
	}
	var  float64
	switch typed := .(type) {
	case float64:
		 = 
	case float32:
		 = float64()
	case int:
		 = float64()
	case int32:
		 = float64()
	case int64:
		 = float64()
	case string:
		,  := strconv.ParseFloat(, 64)
		if  != nil {
			return
		}
		 = 
	default:
		return
	}
	basegraph.Set(, , )
}

func parseHierarchyHandling( string) (HierarchyHandling, bool) {
	switch strings.ToUpper() {
	case "INHERIT":
		return HierarchyInherit, true
	case "INCLUDE_CHILDREN":
		return HierarchyIncludeChildren, true
	case "SEPARATE_CHILDREN":
		return HierarchySeparateChildren, true
	default:
		return 0, false
	}
}

func parsePortConstraints( string) (PortConstraints, bool) {
	switch strings.ToUpper() {
	case "UNDEFINED":
		return PortConstraintsUndefined, true
	case "FREE":
		return PortConstraintsFree, true
	case "FIXED_SIDE":
		return PortConstraintsFixedSide, true
	case "FIXED_ORDER":
		return PortConstraintsFixedOrder, true
	case "FIXED_RATIO":
		return PortConstraintsFixedRatio, true
	case "FIXED_POS":
		return PortConstraintsFixedPosition, true
	default:
		return 0, false
	}
}

func parseEdgeRouting( string) (EdgeRouting, bool) {
	switch strings.ToUpper() {
	case "UNDEFINED":
		return EdgeRoutingUndefined, true
	case "POLYLINE":
		return EdgeRoutingPolyline, true
	case "ORTHOGONAL":
		return EdgeRoutingOrthogonal, true
	case "SPLINES":
		return EdgeRoutingSplines, true
	default:
		return 0, false
	}
}

func parseAlignment( string) (Alignment, bool) {
	switch strings.ToUpper() {
	case "AUTOMATIC":
		return AlignmentAutomatic, true
	case "LEFT":
		return AlignmentLeft, true
	case "RIGHT":
		return AlignmentRight, true
	case "CENTER":
		return AlignmentCenter, true
	case "TOP":
		return AlignmentTop, true
	case "BOTTOM":
		return AlignmentBottom, true
	default:
		return 0, false
	}
}

func parseCrossingMinimization( string) (CrossingMinimizationStrategy, bool) {
	switch strings.ToUpper() {
	case "LAYER_SWEEP":
		return CrossingMinimizationLayerSweep, true
	case "MEDIAN_LAYER_SWEEP":
		return CrossingMinimizationMedianLayerSweep, true
	case "INTERACTIVE":
		return CrossingMinimizationInteractive, true
	case "NONE":
		return CrossingMinimizationNone, true
	default:
		return 0, false
	}
}

func parseNodePlacement( string) (NodePlacementStrategy, bool) {
	switch strings.ToUpper() {
	case "SIMPLE":
		return NodePlacementSimple, true
	case "INTERACTIVE":
		return NodePlacementInteractive, true
	case "LINEAR_SEGMENTS":
		return NodePlacementLinearSegments, true
	case "BRANDES_KOEPF":
		return NodePlacementBrandesKoepf, true
	case "NETWORK_SIMPLEX":
		return NodePlacementNetworkSimplex, true
	default:
		return 0, false
	}
}

func parseNodeFlexibility( string) (NodeFlexibility, bool) {
	switch strings.ToUpper() {
	case "NONE":
		return NodeFlexibilityNone, true
	case "PORT_POSITION":
		return NodeFlexibilityPortPosition, true
	case "NODE_SIZE_WHERE_SPACE_PERMITS":
		return NodeFlexibilitySizeWhereSpacePermits, true
	case "NODE_SIZE":
		return NodeFlexibilitySize, true
	default:
		return 0, false
	}
}

func parseInteractiveReferencePoint( string) (InteractiveReferencePoint, bool) {
	switch strings.ToUpper() {
	case "CENTER":
		return InteractiveReferenceCenter, true
	case "TOP_LEFT":
		return InteractiveReferenceTopLeft, true
	default:
		return 0, false
	}
}

func parseFixedAlignment( string) (FixedAlignment, bool) {
	switch strings.ToUpper() {
	case "NONE":
		return FixedAlignmentNone, true
	case "LEFTUP":
		return FixedAlignmentLeftUp, true
	case "RIGHTUP":
		return FixedAlignmentRightUp, true
	case "LEFTDOWN":
		return FixedAlignmentLeftDown, true
	case "RIGHTDOWN":
		return FixedAlignmentRightDown, true
	case "BALANCED":
		return FixedAlignmentBalanced, true
	default:
		return 0, false
	}
}

func parseEdgeStraightening( string) (EdgeStraighteningStrategy, bool) {
	switch strings.ToUpper() {
	case "NONE":
		return EdgeStraighteningNone, true
	case "IMPROVE_STRAIGHTNESS":
		return EdgeStraighteningImprove, true
	default:
		return 0, false
	}
}

func parseSplineRoutingMode( string) (SplineRoutingMode, bool) {
	switch strings.ToUpper() {
	case "SLOPPY":
		return SplineRoutingSloppy, true
	case "CONSERVATIVE":
		return SplineRoutingConservative, true
	case "CONSERVATIVE_SOFT":
		return SplineRoutingConservativeSoft, true
	default:
		return 0, false
	}
}

func parseGraphCompactionStrategy( string) (GraphCompactionStrategy, bool) {
	 := []GraphCompactionStrategy{
		GraphCompactionNone, GraphCompactionLeft, GraphCompactionRight,
		GraphCompactionLeftRightConstraintLocking, GraphCompactionLeftRightConnectionLocking,
		GraphCompactionEdgeLength,
	}
	 := []string{
		"NONE", "LEFT", "RIGHT", "LEFT_RIGHT_CONSTRAINT_LOCKING",
		"LEFT_RIGHT_CONNECTION_LOCKING", "EDGE_LENGTH",
	}
	for ,  := range  {
		if strings.EqualFold(, ) {
			return [], true
		}
	}
	return 0, false
}

func parseConstraintCalculationStrategy( string) (ConstraintCalculationStrategy, bool) {
	switch strings.ToUpper() {
	case "QUADRATIC":
		return ConstraintCalculationQuadratic, true
	case "SCANLINE":
		return ConstraintCalculationScanline, true
	default:
		return 0, false
	}
}

func parseNodePromotionStrategy( string) (NodePromotionStrategy, bool) {
	 := []NodePromotionStrategy{
		NodePromotionNone, NodePromotionNikolov, NodePromotionNikolovPixel,
		NodePromotionNikolovImproved, NodePromotionNikolovImprovedPixel,
		NodePromotionDummyNodePercentage, NodePromotionNodeCountPercentage,
		NodePromotionNoBoundary, NodePromotionModelOrderLeftToRight,
		NodePromotionModelOrderRightToLeft,
	}
	 := []string{
		"NONE", "NIKOLOV", "NIKOLOV_PIXEL", "NIKOLOV_IMPROVED",
		"NIKOLOV_IMPROVED_PIXEL", "DUMMYNODE_PERCENTAGE", "NODECOUNT_PERCENTAGE",
		"NO_BOUNDARY", "MODEL_ORDER_LEFT_TO_RIGHT", "MODEL_ORDER_RIGHT_TO_LEFT",
	}
	for ,  := range  {
		if strings.EqualFold(, ) {
			return [], true
		}
	}
	return 0, false
}

func parsePortSortingStrategy( string) (PortSortingStrategy, bool) {
	switch strings.ToUpper() {
	case "INPUT_ORDER":
		return PortSortingInputOrder, true
	case "PORT_DEGREE":
		return PortSortingPortDegree, true
	default:
		return 0, false
	}
}

func parseWrappingStrategy( string) (WrappingStrategy, bool) {
	switch strings.ToUpper() {
	case "OFF":
		return WrappingOff, true
	case "SINGLE_EDGE":
		return WrappingSingleEdge, true
	case "MULTI_EDGE":
		return WrappingMultiEdge, true
	default:
		return 0, false
	}
}

func parseCuttingStrategy( string) (CuttingStrategy, bool) {
	switch strings.ToUpper() {
	case "ARD":
		return CuttingARD, true
	case "MSD":
		return CuttingMSD, true
	case "MANUAL":
		return CuttingManual, true
	default:
		return 0, false
	}
}

func parseValidifyStrategy( string) (ValidifyStrategy, bool) {
	switch strings.ToUpper() {
	case "NO":
		return ValidifyNo, true
	case "GREEDY":
		return ValidifyGreedy, true
	case "LOOK_BACK":
		return ValidifyLookBack, true
	default:
		return 0, false
	}
}

func parseOrderingStrategy( string) (OrderingStrategy, bool) {
	switch strings.ToUpper() {
	case "NONE":
		return OrderingNone, true
	case "NODES_AND_EDGES":
		return OrderingNodesAndEdges, true
	case "PREFER_EDGES":
		return OrderingPreferEdges, true
	case "PREFER_NODES":
		return OrderingPreferNodes, true
	default:
		return 0, false
	}
}

func parseLongEdgeOrderingStrategy( string) (LongEdgeOrderingStrategy, bool) {
	switch strings.ToUpper() {
	case "DUMMY_NODE_OVER":
		return LongEdgeDummyNodeOver, true
	case "DUMMY_NODE_UNDER":
		return LongEdgeDummyNodeUnder, true
	case "EQUAL":
		return LongEdgeEqual, true
	default:
		return 0, false
	}
}

func parseComponentOrderingStrategy( string) (ComponentOrderingStrategy, bool) {
	switch strings.ToUpper() {
	case "NONE":
		return ComponentOrderingNone, true
	case "INSIDE_PORT_SIDE_GROUPS":
		return ComponentOrderingInsidePortSideGroups, true
	case "GROUP_MODEL_ORDER":
		return ComponentOrderingGroupModelOrder, true
	case "MODEL_ORDER":
		return ComponentOrderingModelOrder, true
	default:
		return 0, false
	}
}

func parseGroupOrderStrategy( string) (GroupOrderStrategy, bool) {
	switch strings.ToUpper() {
	case "ONLY_WITHIN_GROUP":
		return GroupOrderOnlyWithinGroup, true
	case "MODEL_ORDER":
		return GroupOrderModelOrder, true
	case "ENFORCED":
		return GroupOrderEnforced, true
	default:
		return 0, false
	}
}

func parseLayerUnzippingStrategy( string) (LayerUnzippingStrategy, bool) {
	switch strings.ToUpper() {
	case "NONE":
		return LayerUnzippingNone, true
	case "ALTERNATING":
		return LayerUnzippingAlternating, true
	default:
		return 0, false
	}
}

func parseGreedySwitch( string) (GreedySwitchType, bool) {
	switch strings.ToUpper() {
	case "ONE_SIDED":
		return GreedySwitchOneSided, true
	case "TWO_SIDED":
		return GreedySwitchTwoSided, true
	case "OFF":
		return GreedySwitchOff, true
	default:
		return 0, false
	}
}

func parseLayerConstraint( string) (LayerConstraint, bool) {
	switch strings.ToUpper() {
	case "NONE":
		return LayerConstraintNone, true
	case "FIRST":
		return LayerConstraintFirst, true
	case "FIRST_SEPARATE":
		return LayerConstraintFirstSeparate, true
	case "LAST":
		return LayerConstraintLast, true
	case "LAST_SEPARATE":
		return LayerConstraintLastSeparate, true
	default:
		return 0, false
	}
}

func parseDirectionCongruency( string) (DirectionCongruency, bool) {
	switch strings.ToUpper() {
	case "READING_DIRECTION":
		return DirectionCongruencyReading, true
	case "ROTATION":
		return DirectionCongruencyRotation, true
	default:
		return 0, false
	}
}

func parseEdgeLabelPlacement( string) (EdgeLabelPlacement, bool) {
	switch strings.ToUpper() {
	case "CENTER":
		return EdgeLabelPlacementCenter, true
	case "HEAD":
		return EdgeLabelPlacementHead, true
	case "TAIL":
		return EdgeLabelPlacementTail, true
	default:
		return 0, false
	}
}

func parseLabelSide( string) (LabelSide, bool) {
	switch strings.ToUpper() {
	case "UNKNOWN":
		return LabelSideUnknown, true
	case "ABOVE":
		return LabelSideAbove, true
	case "BELOW":
		return LabelSideBelow, true
	case "INLINE":
		return LabelSideInline, true
	default:
		return 0, false
	}
}

func parseSelfLoopDistribution( string) (SelfLoopDistributionStrategy, bool) {
	switch strings.ToUpper() {
	case "EQUALLY":
		return SelfLoopDistributionEqually, true
	case "NORTH":
		return SelfLoopDistributionNorth, true
	case "NORTH_SOUTH":
		return SelfLoopDistributionNorthSouth, true
	default:
		return 0, false
	}
}

func parseSelfLoopOrdering( string) (SelfLoopOrderingStrategy, bool) {
	switch strings.ToUpper() {
	case "STACKED":
		return SelfLoopOrderingStacked, true
	case "REVERSE_STACKED":
		return SelfLoopOrderingReverseStacked, true
	case "SEQUENCED":
		return SelfLoopOrderingSequenced, true
	default:
		return 0, false
	}
}

func parseCenterEdgeLabelPlacement( string) (CenterEdgeLabelPlacementStrategy, bool) {
	 := []CenterEdgeLabelPlacementStrategy{
		CenterLabelMedianLayer, CenterLabelTailLayer, CenterLabelHeadLayer,
		CenterLabelSpaceEfficientLayer, CenterLabelWidestLayer, CenterLabelCenterLayer,
	}
	 := []string{"MEDIAN_LAYER", "TAIL_LAYER", "HEAD_LAYER", "SPACE_EFFICIENT_LAYER", "WIDEST_LAYER", "CENTER_LAYER"}
	for ,  := range  {
		if strings.EqualFold(, ) {
			return [], true
		}
	}
	return 0, false
}

func parseEdgeLabelSideSelection( string) (EdgeLabelSideSelection, bool) {
	 := []EdgeLabelSideSelection{
		EdgeLabelSideAlwaysUp, EdgeLabelSideAlwaysDown, EdgeLabelSideDirectionUp,
		EdgeLabelSideDirectionDown, EdgeLabelSideSmartUp, EdgeLabelSideSmartDown,
	}
	 := []string{"ALWAYS_UP", "ALWAYS_DOWN", "DIRECTION_UP", "DIRECTION_DOWN", "SMART_UP", "SMART_DOWN"}
	for ,  := range  {
		if strings.EqualFold(, ) {
			return [], true
		}
	}
	return 0, false
}

func addSpacing(,  geometry.Spacing) geometry.Spacing {
	return geometry.Spacing{
		Top: .Top + .Top, Right: .Right + .Right,
		Bottom: .Bottom + .Bottom, Left: .Left + .Left,
	}
}