// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.JunctionChecker.connectedness;
import java.util.ArrayList;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.Channel;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.ChannelDiGraph;
public class StrongConnectednessCalculator {
private int index = 0;
private final ArrayList<Channel> stack = new ArrayList<>();
private final ArrayList<ArrayList<Channel>> SCC = new ArrayList<>();
private final int numberOfNodes;
private int calculatedNodes = 0;
private ArrayList<Channel> nsccchannels = new ArrayList<>();
private final ChannelDiGraph digraph;
int biggestPart = 0;
public StrongConnectednessCalculator(ChannelDiGraph digraph) {
this.digraph = digraph;
numberOfNodes = digraph.numberOfChannels();
}
private int findUncalculatedNodes() {
for (int i = 0; i < numberOfNodes; i++) {
if (digraph.getChannelAtPosition(i).getLowlink() == -1) {
return i;
}
}
return 0;
}
/**
* berechnet die starken Zusammenhangskomponenten
*/
public void calculateSCC() {
while (calculatedNodes != numberOfNodes) {
//log.trace("calculatedNodes: " + calculatedNodes + ", gesamtnodes: " + numberOfNodes);
tarjan(digraph.getChannelAtPosition(findUncalculatedNodes()));
}
//log.trace("Berechnung der starken Zusammenhangskomponenten beendet: \n " +numberOfNodes + " Nodes sind wie folgt aufgeteilt: ");
for (int i = 0; i < SCC.size(); i++) {
//log.trace("Komponente: " + i + " besteht aus " + SCC.get(i).size()+ " Knoten");
/**
* for (int j = 1; j < list.getNumberOfNodes(); j++) { if
* (list.getAdjacencyListnodes()[j].getIndex()== -1) {
* System.out.println("====");
* System.out.println(list.getAdjacencyListnodes
* ()[j].getNode().toString()); } }
**/
}
findBiggestPiece();
saveNotSCCChannel();
}
/**
* speichert alle Channel, die nicht stark zusammenhängend sind, in einer ArrayList
**/
private void saveNotSCCChannel() {
nsccchannels = new ArrayList<>();
for (int i = 0; i < SCC.size(); i++) {
if (i != biggestPart) {
nsccchannels.addAll(SCC.get(i));
}
}
//alle Channels auf nicht zusammenhängend setzen
for (int i = 0; i < nsccchannels.size(); i++) {
nsccchannels.get(i).setStrongConnected(false);
}
}
private void findBiggestPiece() {
int number = 0;
for (int i = 0; i < SCC.size(); i++) {
if (SCC.get(i).size() > number) {
biggestPart = i;
number = SCC.get(i).size();
}
}
}
public String showNotstronglyConnectednessParts() {
String s = new String();
for (int i = 0; i < SCC.size(); i++) {
if (i != biggestPart) {
s += "GraphKomponente: " + i + "\n";
for (int j = 0; j < SCC.get(i).size(); j++) {
s += "Channel: " + SCC.get(i).get(j).getNewid();
}
s += "\n";
}
}
return s;
}
/**
* gibt eine Arraylist mit all den Channels zurück, welche nicht
* im größten zusammenhägendem Teil des Channel-Digraphen sind
*/
public ArrayList<Channel> getNotConnectedChannels() {
return nsccchannels;
}
private void tarjan(Channel v) {
//log.trace("tarjan für channel aufgerufen mit id: " + v.getNewid());
v.setIndex(index);
v.setLowlink(index);
index++;
stack.add(0, v);
//log.trace("channel "+v.getNewid() + " hat nachbarn: " + v.getLeadsTo().size());
for (int i = 0; i < v.getLeadsTo().size(); i++) {
//log.trace("schleifendurchlauf: " + i);
Channel n = v.getLeadsTo().get(i).getToChannel();
if (n.getIndex() == -1) {
//log.trace("n hat index =-1");
tarjan(n);
v.setLowlink(Math.min(v.getLowlink(), n.getLowlink()));
} else if (stack.contains(n)) {
//log.trace("setze lowlink von n auf: " + v.getLowlink());
v.setLowlink(Math.min(v.getLowlink(), n.getLowlink()));
}
}
if (v.getLowlink() == v.getIndex()) {
Channel n;
ArrayList<Channel> component = new ArrayList<>();
do {
n = stack.remove(0);
component.add(n);
} while (n != v);
SCC.add(component);
calculatedNodes += component.size();
}
}
}