// Copyright (c) 2011, 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 force

import (
	
	

	
)

// Split mirrors ComponentsProcessor.split, including its source-shaped DFS
// edge append behavior on cyclic components.
func ( *FGraph) []*FGraph {
	if !.SeparateConnectedComponents {
		return []*FGraph{}
	}
	 := make([]bool, len(.Nodes))
	 := make([][]*FEdge, len(.Nodes))
	for ,  := range .Edges {
		[.Source.ID] = append([.Source.ID], )
		[.Target.ID] = append([.Target.ID], )
	}
	 := make([]*FGraph, 0)
	var  func(*FNode, *FNode, *FGraph) *FGraph
	 = func(,  *FNode,  *FGraph) *FGraph {
		if [.ID] {
			return nil
		}
		[.ID] = true
		if  == nil {
			 = copyGraphProperties()
		}
		.Nodes = append(.Nodes, )
		for ,  := range [.ID] {
			if .Target ==  || .Source ==  {
				continue
			}
			if .Source !=  {
				(.Source, , )
			}
			if .Target !=  {
				(.Target, , )
			}
			.Edges = append(.Edges, )
			.Labels = append(.Labels, .Labels...)
		}
		return 
	}
	for ,  := range .Nodes {
		if  := (, nil, nil);  != nil {
			 = append(, )
		}
	}
	if len() > 1 {
		for ,  := range  {
			for ,  := range .Nodes {
				.ID = 
			}
		}
	}
	return 
}

func copyGraphProperties( *FGraph) *FGraph {
	return &FGraph{
		Origin:                      .Origin,
		Model:                       .Model,
		Iterations:                  .Iterations,
		Temperature:                 .Temperature,
		Repulsion:                   .Repulsion,
		SpacingNodeNode:             .SpacingNodeNode,
		AspectRatio:                 .AspectRatio,
		SeparateConnectedComponents: .SeparateConnectedComponents,
		Interactive:                 .Interactive,
		Padding:                     .Padding,
		Random:                      .Random,
		Priority:                    .Priority,
		BBUpLeft:                    .BBUpLeft,
		BBLowRight:                  .BBLowRight,
	}
}

// Recombine mirrors ComponentsProcessor.recombine.
func ( []*FGraph) *FGraph {
	if len() == 1 {
		return [0]
	}
	if len() == 0 {
		return &FGraph{}
	}
	for ,  := range  {
		 := 0
		,  := float64(math.MaxInt32), float64(math.MaxInt32)
		,  := float64(math.MinInt32), float64(math.MinInt32)
		for ,  := range .Nodes {
			 += .Priority
			 = math.Min(, .Position.X-.Size.X/2)
			 = math.Min(, .Position.Y-.Size.Y/2)
			 = math.Max(, .Position.X+.Size.X/2)
			 = math.Max(, .Position.Y+.Size.Y/2)
		}
		.Priority = 
		.BBUpLeft = geometry.Point{X: , Y: }
		.BBLowRight = geometry.Point{X: , Y: }
	}
	sort.SliceStable(, func(,  int) bool {
		if [].Priority != [].Priority {
			return [].Priority > [].Priority
		}
		 := [].BBLowRight.Sub([].BBUpLeft)
		 := [].BBLowRight.Sub([].BBUpLeft)
		return .X*.Y < .X*.Y
	})

	 := copyGraphProperties([0])
	,  := 0.0, 0.0
	for ,  := range  {
		 := .BBLowRight.Sub(.BBUpLeft)
		 = math.Max(, .X)
		 += .X * .Y
	}
	// ELK casts sqrt(totalArea) to float before multiplying by aspect ratio.
	 = math.Max(, float64(float32(math.Sqrt()))*.AspectRatio)
	 := .SpacingNodeNode
	, ,  := 0.0, 0.0, 0.0
	for ,  := range  {
		 := .BBLowRight.Sub(.BBUpLeft)
		if +.X >  {
			 = 0
			 +=  + 
			 = 0
		}
		moveGraph(, , , )
		 = math.Max(, .Y)
		 += .X + 
	}
	return 
}

func moveGraph(,  *FGraph, ,  float64) {
	 := geometry.Point{X: , Y: }.Sub(.BBUpLeft)
	for ,  := range .Nodes {
		.Position = .Position.Add()
		.Nodes = append(.Nodes, )
	}
	for ,  := range .Edges {
		for ,  := range .Bendpoints {
			.Position = .Position.Add()
		}
		.Edges = append(.Edges, )
	}
	for ,  := range .Labels {
		.Position = .Position.Add()
		.Labels = append(.Labels, )
	}
}