package de.ovgu.cide.tools.interactionanalyzer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import cide.gast.ASTVisitor;
import cide.gast.IASTNode;
import cide.gast.ISourceFile;
import cide.gparser.ParseException;
import de.ovgu.cide.features.IFeature;
import de.ovgu.cide.features.source.ColoredSourceFile;
import de.ovgu.cide.features.source.ColoredSourceFileIteratorJob;
public class CollectStatisticsAndInteractionsJob extends
ColoredSourceFileIteratorJob {
public static class InteractionPosition {
InteractionPosition(IASTNode node, IFile file) {
start = node.getStartPosition();
length = node.getLength();
this.file = file;
name = nodeToStr(node, file);
}
public IFile file;
public int start, length;
public String name;
private static String nodeToStr(IASTNode node, IFile file) {
return file.getName() + " " + node.getClass().getSimpleName()
+ " (" + node.getStartPosition() + "-"
+ (node.getStartPosition() + node.getLength()) + ")";
}
}
public final Set<Set<IFeature>> interactions = new HashSet<Set<IFeature>>();
// occurrences by feature set
public final Map<Set<IFeature>, Set<InteractionPosition>> occurences = new HashMap<Set<IFeature>, Set<InteractionPosition>>();
// occurrences by individual feature, may overlap
public final Map<IFeature, Set<InteractionPosition>> occurencesByFeature = new HashMap<IFeature, Set<InteractionPosition>>();
public final Set<IFeature> usedFeatures = new HashSet<IFeature>();
public final Map<Derivative, Set<InteractionPosition>> derivatives = new HashMap<Derivative, Set<InteractionPosition>>();
public final Map<IFeature, Map<IFile, Set<Integer>>> locCounter = new HashMap<IFeature, Map<IFile, Set<Integer>>>();
private Tree tree;
private int annoationsCount = 0;
private int classCount = 0;
private int methodCount = 0;
private int fieldCount = 0;
public CollectStatisticsAndInteractionsJob(IProject project, Tree resultTree) {
super(project, "Collecting Interactions",
"Collecting Interactions from");
this.tree = resultTree;
}
@Override
protected void processSource(final ColoredSourceFile source)
throws CoreException {
try {
ISourceFile ast;
ast = source.getAST();
ast.accept(new ASTVisitor() {
/**
* collect derivative statistics
*/
public void postVisit(IASTNode node) {
boolean hasOwnColors = source.getColorManager()
.getOwnColors(node).size() > 0;
if (hasOwnColors) {
Set<IFeature> colors = source.getColorManager()
.getColors(node);
colors = cleanInteractions(colors);
if (colors.size() > 1)
interactions.add(colors);
if (!colors.isEmpty())
usedFeatures.addAll(colors);
addOccurence(colors, node, source.getResource());
addDerivative(node, source);
}
super.postVisit(node);
}
/**
* collect general statistics
*
* annotation counts only if neither parent nor previous sibling
* already has it (exception: annotations on files always count as annotation)
*/
@Override
public boolean visit(IASTNode node) {
// own colors cleared by parent colors, in case they overlap
Set<IFeature> ownColors = new HashSet<IFeature>(source
.getColorManager().getOwnColors(node));
if (node.getParent() != null)
ownColors.removeAll(source.getColorManager().getColors(
node.getParent()));
else
ownColors.addAll(source.getColorManager().getColors(node));
if (!ownColors.isEmpty()) {
IASTNode previousSibling = findPreviousSibling(node);
if (previousSibling == null
|| !sameColors(previousSibling, node))
annoationsCount++;
}
Set<IFeature> allColors = new HashSet<IFeature>(source
.getColorManager().getColors(node));
if (!allColors.isEmpty()) {
countLoc(source, allColors, node);
}
return super.visit(node);
}
private IASTNode findPreviousSibling(IASTNode node) {
IASTNode previousSibling = null;
if (node.getLocationInParent() != null) {
IASTNode[] siblings = node.getLocationInParent()
.getChildren();
for (IASTNode sibling : siblings) {
if (sibling == node)
break;
previousSibling = sibling;
}
}
return previousSibling;
}
private boolean sameColors(IASTNode previousSibling,
IASTNode node) {
return source
.getColorManager()
.getColors(node)
.equals(source.getColorManager().getColors(
previousSibling));
}
});
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void countLoc(ColoredSourceFile source, Set<IFeature> allColors,
IASTNode node) {
for (IFeature feature : allColors) {
Map<IFile, Set<Integer>> locPerFeature = locCounter.get(feature);
if (locPerFeature == null) {
locPerFeature = new HashMap<IFile, Set<Integer>>();
locCounter.put(feature, locPerFeature);
}
Set<Integer> locPerFile = locPerFeature.get(source.getResource());
if (locPerFile == null) {
locPerFile = new HashSet<Integer>();
locPerFeature.put(source.getResource(), locPerFile);
}
for (int i = node.getStartLine(); i <= node.getEndLine(); i++) {
locPerFile.add(i);
}
}
}
protected void finish() {
tree.getDisplay().syncExec(new Runnable() {
public void run() {
clearTree();
printAllInteractions();
printInteractionsByFeature();
printInteractionNumberDevelopment();
printDerivatives();
printAllOccurrences();
printAnnotationCount();
printFeatureLOC();
}
});
}
/**
* prints all occurrences of feature code. not related to interactions, but
* same collection process, therefore now own view yet.
*/
protected void printAllOccurrences() {
TreeItem allOccurrences = new TreeItem(tree, SWT.DEFAULT);
allOccurrences.setText("IFeature Code");
for (IFeature f : sort(usedFeatures)) {
createItem2(allOccurrences, f.getName(), occurencesByFeature.get(f));
}
setCountingCaption(allOccurrences);
}
private void printFeatureLOC() {
TreeItem featureLoc = new TreeItem(tree, SWT.DEFAULT);
featureLoc.setText("Feature LOC");
for (Entry<IFeature, Map<IFile, Set<Integer>>> entry : locCounter
.entrySet()) {
TreeItem featureItem = new TreeItem(featureLoc, SWT.DEFAULT);
featureItem.setText(entry.getKey().getName() + ": "
+ countLoc(entry.getValue()) + " LOC");
for (Entry<IFile, Set<Integer>> files : entry.getValue().entrySet()) {
TreeItem fileItem = new TreeItem(featureItem, SWT.DEFAULT);
fileItem.setText(files.getKey().getName() + ": "
+ files.getValue().size() + " LOC");
}
}
}
private int countLoc(Map<IFile, Set<Integer>> map) {
int result = 0;
for (Set<Integer> v : map.values())
result += v.size();
return result;
}
/**
* prints general statistics about the number of annotations
*/
protected void printAnnotationCount() {
TreeItem statisticsItem = new TreeItem(tree, SWT.DEFAULT);
statisticsItem.setText("General Statistics");
createItem2(statisticsItem, "Annoations: " + annoationsCount, null);
createItem2(statisticsItem, "Classes: " + classCount, null);
createItem2(statisticsItem, "Methods: " + methodCount, null);
createItem2(statisticsItem, "Fields: " + fieldCount, null);
}
private void clearTree() {
tree.removeAll();
}
private void printInteractionNumberDevelopment() {
List<IFeature> features = sort(usedFeatures);
Set<Set<IFeature>> leftInteractions = new HashSet<Set<IFeature>>(
interactions);
Set<IFeature> knownFeatures = new HashSet<IFeature>();
int idx = 0, foundInteractions = 0;
System.out.println("Stats:");
for (IFeature feature : features) {
idx++;
knownFeatures.add(feature);
for (Iterator<Set<IFeature>> iter = leftInteractions.iterator(); iter
.hasNext();) {
Set<IFeature> interaction = iter.next();
if (knownFeatures.containsAll(interaction)) {
foundInteractions++;
iter.remove();
}
}
System.out.println(idx + " (" + feature.getName() + ") - "
+ foundInteractions);
}
}
private void printAllInteractions() {
TreeItem allInteractions = new TreeItem(tree, SWT.DEFAULT);
allInteractions.setText("All interactions");
for (Set<IFeature> inter : interactions) {
String txt = getInteractionName(inter);
createItem(allInteractions, txt, inter);
System.out.println("[" + txt + "]");
}
setCountingCaption(allInteractions);
}
private void printDerivatives() {
TreeItem allDerivatives = new TreeItem(tree, SWT.DEFAULT);
allDerivatives.setText("All derivatives");
ArrayList<Derivative> derivativeList = new ArrayList<Derivative>(
derivatives.keySet());
Collections.sort(derivativeList);
for (Derivative d : derivativeList) {
createItem2(allDerivatives, d.getDerivativeStr(),
derivatives.get(d));
}
setCountingCaption(allDerivatives);
}
private void setCountingCaption(TreeItem i) {
i.setText(i.getText() + " (" + i.getItemCount() + ")");
}
private void printInteractionsByFeature() {
TreeItem allInteractions = new TreeItem(tree, SWT.DEFAULT);
allInteractions.setText("Interactions by IFeature");
for (IFeature f : sort(usedFeatures)) {
TreeItem featureItem = createItem(allInteractions, f.getName(),
null);
for (Set<IFeature> inter : interactions)
if (inter.contains(f))
createItem(featureItem, getInteractionName(inter), inter);
setCountingCaption(featureItem);
}
setCountingCaption(allInteractions);
}
private List<IFeature> sort(Set<IFeature> set) {
ArrayList<IFeature> result = new ArrayList<IFeature>(set);
Collections.sort(result);
return result;
}
private String getInteractionName(Set<IFeature> inter) {
String txt = "";
boolean first = true;
List<IFeature> l = sort(inter);
for (IFeature f : l) {
if (first)
first = false;
else
txt += " - ";
txt += f.getName();
}
return txt;
}
private TreeItem createItem(TreeItem parent, String text,
Set<IFeature> interaction) {
TreeItem r = new TreeItem(parent, SWT.DEFAULT);
r.setText(text);
if (interaction != null) {
Set<InteractionPosition> occ = occurences.get(interaction);
if (occ != null && !occ.isEmpty())
for (InteractionPosition pos : occ) {
TreeItem o = new TreeItem(r, SWT.DEFAULT);
o.setText(pos.name);
o.setData(pos);
}
setCountingCaption(r);
}
return r;
}
private TreeItem createItem2(TreeItem parent, String text,
Set<InteractionPosition> occurences) {
TreeItem r = new TreeItem(parent, SWT.DEFAULT);
r.setText(text);
if (occurences != null) {
for (InteractionPosition pos : occurences) {
TreeItem o = new TreeItem(r, SWT.DEFAULT);
o.setText(pos.name);
o.setData(pos);
}
setCountingCaption(r);
}
return r;
}
private void addOccurence(Set<IFeature> colors, IASTNode node, IFile file) {
InteractionPosition p = new InteractionPosition(node, file);
Set<InteractionPosition> occ = occurences.get(colors);
if (occ == null) {
occ = new HashSet<InteractionPosition>();
occurences.put(colors, occ);
}
occ.add(p);
for (IFeature color : colors) {
occ = occurencesByFeature.get(color);
if (occ == null) {
occ = new HashSet<InteractionPosition>();
occurencesByFeature.put(color, occ);
}
occ.add(p);
}
}
private void addDerivative(IASTNode node, ColoredSourceFile source) {
Derivative d = new TensorDerivative(node, source);
Set<InteractionPosition> occ = derivatives.get(d);
if (occ == null) {
occ = new HashSet<InteractionPosition>();
derivatives.put(d, occ);
}
occ.add(new InteractionPosition(node, source.getResource()));
}
private Set<IFeature> cleanInteractions(Set<IFeature> colors) {
HashSet<IFeature> result = new HashSet<IFeature>(colors);
for (IFeature f : colors) {
Set<IFeature> parent = f.getRequiredFeatures();
result.removeAll(parent);
}
return result;
}
}