/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.thingml.compilers.checker;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.sintef.thingml.*;
import org.sintef.thingml.helpers.ConfigurationHelper;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
*
* @author sintef
*/
public class Tarjan<T extends ThingMLElement> {
int index;
List<Annotated<T>> Stack;
Set<Annotated<T>> vertices;
Configuration cfg;
List<List<T>> SCComponents;
public Tarjan(Configuration cfg, Set<T> vertices) {
this.cfg = cfg;
this.vertices = new HashSet<Annotated<T>>();
for (T el : vertices) {
Annotated<T> Ael = new Annotated<T>(el);
this.vertices.add(Ael);
}
index = 0;
Stack = new LinkedList<Annotated<T>>();
SCComponents = new LinkedList<List<T>>();
}
public Annotated<T> findElement(T el) {
for (Annotated<T> Ael : vertices) {
if (EcoreUtil.equals(Ael.el, el)) {
return Ael;
}
}
return null;
}
public List<Annotated<T>> findChildren(T el) {
List<Annotated<T>> res = new LinkedList<Annotated<T>>();
if (el instanceof Instance) {
for (Connector co : ConfigurationHelper.allConnectors(cfg)) {
if (EcoreUtil.equals(co.getCli().getInstance(), el)) {
res.add(findElement((T) co.getSrv().getInstance()));
}
}
} else {
if (el instanceof State) {
State s = (State) el;
for (Transition tr : s.getOutgoing()) {
if (tr.getEvent().isEmpty()) {
if (tr.getGuard() == null) {
res.add(findElement((T) tr.getTarget()));
}
}
}
}
}
return res;
}
public void StrongConnect(Annotated<T> v) {
v.id = index;
v.lowlink = index;
v.isVisited = true;
index++;
Stack.add(0, v);
for (Annotated<T> w : findChildren(v.el)) {
if (!w.isVisited) {
StrongConnect(w);
v.lowlink = Math.min(v.lowlink, w.lowlink);
} else {
if (Stack.contains(w)) {
v.lowlink = Math.min(v.lowlink, w.id);
}
}
}
if (v.id == v.lowlink) {
List<T> res = new LinkedList<T>();
Annotated<T> w;
do {
w = Stack.get(0);
res.add(w.el);
Stack.remove(0);
} while (!w.equals(v));
SCComponents.add(res);
}
}
public List<List<T>> findStronglyConnectedComponents() {
for (Annotated<T> v : vertices) {
if (!v.isVisited) {
StrongConnect(v);
}
}
return SCComponents;
}
private class Annotated<T> {
public T el;
public int id, lowlink;
public boolean isVisited;
public Annotated(T el) {
this.el = el;
this.isVisited = false;
}
boolean equals(Annotated<T> other) {
return EcoreUtil.equals((ThingMLElement) this.el, (ThingMLElement) other.el);
}
}
}