// Copyright (c) 2012, 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 components

import (
	
	

	
	basegraph 
	
)

// componentGroupGraphPlacer is ELK 0.8.1's ComponentGroupGraphPlacer. It
// packs disconnected components whose external-port dummies constrain which
// sectors can share a placement group.
type componentGroupGraphPlacer struct {
	componentGroups []*componentGroup
}

func ( *componentGroupGraphPlacer) (
	 *layered.LGraphArena,
	 []layered.LGraphID,
	 layered.LGraphID,
) error {
	.componentGroups = nil
	for ,  := range  {
		if  ==  {
			return fmt.Errorf("components: target graph cannot be a component group member")
		}
	}
	 := .Graph()
	.LayerlessNodes = nil
	if len() == 0 {
		.Size = geometry.Point{}
		return nil
	}

	 := .Graph([0])
	.Properties = .Properties.Clone()
	for ,  := range  {
		.addComponent(, )
	}

	 := geometry.Point{}
	 := basegraph.Get(
		&.Properties, layered.SpacingComponentComponent)
	for ,  := range .componentGroups {
		 := .placeComponents(, , )
		offsetGraphs(, .components(), )
		 = .Add()
	}
	.Size = geometry.Point{X: .X - , Y: .Y - }

	if basegraph.Get(&.Properties, connectedComponentsCompaction) &&
		basegraph.Get(&.Properties, layered.EdgeRoutingOption) ==
			layered.EdgeRoutingOrthogonal {
		if  := compactExternalComponentGroups(
			, , , );  != nil {
			return 
		}
	}
	for ,  := range .componentGroups {
		moveGraphs(, , .components(), geometry.Point{})
	}
	return nil
}

func ( *componentGroupGraphPlacer) (
	 *layered.LGraphArena,
	 layered.LGraphID,
) {
	for ,  := range .componentGroups {
		if .add(, ) {
			return
		}
	}
	.componentGroups = append(
		.componentGroups, newComponentGroup(, ))
}

func ( *componentGroupGraphPlacer) (
	 *layered.LGraphArena,
	 *componentGroup,
	 float64,
) geometry.Point {
	 := .placeComponentsInRows(, .componentsFor(sidesNone), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesNorth), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesSouth), )
	 := .placeComponentsVertically(, .componentsFor(sidesWest), )
	 := .placeComponentsVertically(, .componentsFor(sidesEast), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesNorthWest), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesNorthEast), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesSouthWest), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesEastSouth), )
	 := .placeComponentsVertically(, .componentsFor(sidesEastWest), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesNorthSouth), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesNorthEastWest), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesEastSouthWest), )
	 := .placeComponentsVertically(, .componentsFor(sidesNorthSouthWest), )
	 := .placeComponentsVertically(, .componentsFor(sidesNorthEastSouth), )
	 := .placeComponentsHorizontally(, .componentsFor(sidesNorthEastSouthWest), )

	 := max4(.X, .X, .X, .X)
	 := max4(.X, .X, .X, .X)
	 := .X
	 := max4(.X, .X, .X, .X)
	 := max4(.Y, .Y, .Y, .Y)
	 := max4(.Y, .Y, .Y, .Y)
	 := .Y
	 := max4(.Y, .Y, .Y, .Y)

	offsetGraphs(, .componentsFor(sidesNone), geometry.Point{
		X:  + ,
		Y:  + ,
	})
	offsetGraphs(, .componentsFor(sidesNorthEastSouthWest), geometry.Point{
		X:  + ,
		Y:  + ,
	})
	offsetGraphs(, .componentsFor(sidesNorth), geometry.Point{
		X:  + ,
	})
	offsetGraphs(, .componentsFor(sidesSouth), geometry.Point{
		X:  + ,
		Y:  +  + ,
	})
	offsetGraphs(, .componentsFor(sidesWest), geometry.Point{
		Y:  + ,
	})
	offsetGraphs(, .componentsFor(sidesEast), geometry.Point{
		X:  +  + ,
		Y:  + ,
	})
	offsetGraphs(, .componentsFor(sidesNorthEast), geometry.Point{
		X:  +  + ,
	})
	offsetGraphs(, .componentsFor(sidesSouthWest), geometry.Point{
		Y:  +  + ,
	})
	offsetGraphs(, .componentsFor(sidesEastSouth), geometry.Point{
		X:  +  + ,
		Y:  +  + ,
	})
	offsetGraphs(, .componentsFor(sidesEastWest), geometry.Point{
		Y: ,
	})
	offsetGraphs(, .componentsFor(sidesNorthSouth), geometry.Point{
		X: ,
	})
	offsetGraphs(, .componentsFor(sidesEastSouthWest), geometry.Point{
		Y:  +  + ,
	})
	offsetGraphs(, .componentsFor(sidesNorthEastSouth), geometry.Point{
		X:  +  + ,
	})

	return geometry.Point{
		X: max4(+++,
			.X, .X, .X),
		Y: max4(+++,
			.Y, .Y, .Y),
	}
}

func (*componentGroupGraphPlacer) (
	 *layered.LGraphArena,
	 []layered.LGraphID,
	 float64,
) geometry.Point {
	 := geometry.Point{}
	for ,  := range  {
		 := .Graph()
		offsetGraph(, , geometry.Point{X: .X})
		.X += .Size.X + 
		.Y = math.Max(.Y, .Size.Y)
	}
	if .Y > 0 {
		.Y += 
	}
	return 
}

func (*componentGroupGraphPlacer) (
	 *layered.LGraphArena,
	 []layered.LGraphID,
	 float64,
) geometry.Point {
	 := geometry.Point{}
	for ,  := range  {
		 := .Graph()
		offsetGraph(, , geometry.Point{Y: .Y})
		.Y += .Size.Y + 
		.X = math.Max(.X, .Size.X)
	}
	if .X > 0 {
		.X += 
	}
	return 
}

func (*componentGroupGraphPlacer) (
	 *layered.LGraphArena,
	 []layered.LGraphID,
	 float64,
) geometry.Point {
	if len() == 0 {
		return geometry.Point{}
	}
	,  := 0.0, 0.0
	for ,  := range  {
		 := .Graph().Size
		 = math.Max(, .X)
		 += .X * .Y
	}
	// The float cast is in the Java source and survives GWT.
	 := float64(float32(math.Sqrt())) * basegraph.Get(
		&.Graph([0]).Properties, layered.AspectRatio)
	 = math.Max(, )

	, , ,  := 0.0, 0.0, 0.0, 
	for ,  := range  {
		 := .Graph().Size
		if +.X >  {
			 = 0
			 +=  + 
			 = 0
		}
		offsetGraph(, , geometry.Point{X: , Y: })
		 = math.Max(, +.X)
		 = math.Max(, .Y)
		 += .X + 
	}
	return geometry.Point{
		X:  + ,
		Y:  +  + ,
	}
}

func offsetGraphs(
	 *layered.LGraphArena,
	 []layered.LGraphID,
	 geometry.Point,
) {
	for ,  := range  {
		offsetGraph(, , )
	}
}

func max4(, , ,  float64) float64 {
	return math.Max(math.Max(, ), math.Max(, ))
}