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

import (
	

	
	
	
)

// Particle is ELK's FParticle. Position is a center for nodes and the
// top-left corner for labels, matching the Java implementation.
type Particle struct {
	Position     geometry.Point
	Size         geometry.Point
	Displacement geometry.Point
	Priority     int
	node         *FNode
	bendEdge     *FEdge
}

func ( *Particle) () float64 { return forceVectorLength(.Size) / 2 }

type FNode struct {
	Particle
	ID     int
	Origin graph.NodeID
}

type FLabel struct {
	Particle
	Origin  graph.LabelID
	Edge    *FEdge
	Text    string
	Inline  bool
	Spacing float64
}

type FBendpoint struct {
	Particle
	Edge *FEdge
}

type FEdge struct {
	Origin         graph.EdgeID
	Source, Target *FNode
	Bendpoints     []*FBendpoint
	Labels         []*FLabel
	Priority       int
	RepulsivePower int
}

type FGraph struct {
	Nodes      []*FNode
	Edges      []*FEdge
	Labels     []*FLabel
	Bendpoints []*FBendpoint
	Adjacency  [][]int

	Origin                      graph.NodeID
	Model                       string
	Iterations                  int
	Temperature                 float64
	Repulsion                   float64
	SpacingNodeNode             float64
	AspectRatio                 float64
	SeparateConnectedComponents bool
	Interactive                 bool
	Padding                     geometry.Spacing
	Random                      *javacompat.Random

	Priority   int
	BBUpLeft   geometry.Point
	BBLowRight geometry.Point
}

func ( *FGraph) () []*Particle {
	 := make([]*Particle, 0, len(.Nodes)+len(.Labels)+len(.Bendpoints))
	for ,  := range .Nodes {
		 = append(, &.Particle)
	}
	for ,  := range .Labels {
		 = append(, &.Particle)
	}
	for ,  := range .Bendpoints {
		 = append(, &.Particle)
	}
	return 
}

func ( *FGraph) () {
	.Adjacency = make([][]int, len(.Nodes))
	for  := range .Adjacency {
		.Adjacency[] = make([]int, len(.Nodes))
	}
	for ,  := range .Edges {
		.Adjacency[.Source.ID][.Target.ID] += .Priority
	}
}

func ( *FGraph) ( *Particle,  *Particle) int {
	if .node != nil && .node != nil {
		return .Adjacency[.node.ID][.node.ID] +
			.Adjacency[.node.ID][.node.ID]
	}
	if .bendEdge != nil && .bendEdge != nil && .bendEdge == .bendEdge {
		return .bendEdge.Priority
	}
	return 0
}

func ( *FEdge) () geometry.Point {
	 := .Target.Position.Sub(.Source.Position)
	return .Source.Position.Add(clipVector(, .Source.Size.X, .Source.Size.Y))
}

func ( *FEdge) () geometry.Point {
	 := .Source.Position.Sub(.Target.Position)
	return .Target.Position.Add(clipVector(, .Target.Size.X, .Target.Size.Y))
}

func clipVector( geometry.Point, ,  float64) geometry.Point {
	,  := /2, /2
	,  := 1.0, 1.0
	if math.Abs(.X) >  {
		 =  / math.Abs(.X)
	}
	if math.Abs(.Y) >  {
		 =  / math.Abs(.Y)
	}
	return .Scale(math.Min(, ))
}

func ( *FEdge) () {
	 := len(.Bendpoints)
	if  == 0 {
		return
	}
	 := float64(1 / float64(+1))
	 := .Target.Position.Sub(.Source.Position)
	 := geometry.Point{
		X: float64(.X * ),
		Y: float64(.Y * ),
	}
	 := .Source.Position
	for ,  := range .Bendpoints {
		 = .Add()
		.Position = 
	}
}

func ( *FLabel) () {
	 := .Edge.Source.Position
	 := .Edge.Target.Position
	if .Inline {
		.Position = .Add(.Sub().Scale(0.5)).Sub(.Size.Scale(0.5))
		return
	}
	 := .Spacing
	 := .Position
	if .X >= .X {
		if .Y >= .Y {
			.X = .X + (.X-.X)/2 + 
			.Y = .Y + (.Y-.Y)/2 -  - .Size.Y
		} else {
			.X = .X + (.X-.X)/2 + 
			.Y = .Y + (.Y-.Y)/2 + 
		}
	} else if .Y >= .Y {
		.X = .X + (.X-.X)/2 + 
		.Y = .Y + (.Y-.Y)/2 + 
	} else {
		.X = .X + (.X-.X)/2 + 
		.Y = .Y + (.Y-.Y)/2 -  - .Size.Y
	}
	.Position = 
}