package org.codemap.callhierarchy;
import java.util.ArrayList;
import org.codemap.CodemapCore;
import org.codemap.MapPerProject;
import org.codemap.layers.Layer;
import org.codemap.util.ChangeTriggerValue;
import org.eclipse.jdt.internal.corext.callhierarchy.MethodWrapper;
import ch.akuhn.util.List;
public class CallModel {
private MethodCallNode rootNode;
private ChangeTriggerValue changeTrigger = new ChangeTriggerValue();
private boolean dirty = true;
private boolean enabled = false;
public void newRoot(MethodWrapper currentRootMethod) {
rootNode = new MethodCallNode(currentRootMethod, this);
}
public void expand(MethodWrapper source, List<MethodWrapper> targets) {
MethodCallPath nodePath = new MethodCallPath(source);
MethodCallNode toExpand = nodePath.walk(rootNode);
// we might be outside the current scope
if (toExpand == null) return;
toExpand.setChildren(targets);
}
public void collapse(MethodWrapper source) {
MethodCallPath nodePath = new MethodCallPath(source);
MethodCallNode toCollapse = nodePath.walk(rootNode);
// we might be outside the current scope
if (toCollapse == null) return;
toCollapse.clearChildren();
}
public void setDirty() {
CodemapCore plugin = CodemapCore.getPlugin();
if (plugin == null) return;
MapPerProject activeMap = plugin.getActiveMap();
if (activeMap == null) return;
Layer layer = activeMap.getLayer(CallOverlay.class);
if (layer == null) {
layer = new CallOverlay(this);
activeMap.addLayer(layer);
activeMap.redrawWhenChanges(changeTrigger.value());
}
changeTrigger.setChanged();
dirty = true;
}
public boolean isDirty() {
return dirty;
}
public void setClean() {
dirty = false;
}
public void enable() {
enabled = true;
setDirty();
}
public void disable() {
enabled = false;
setDirty();
}
public boolean isEnabled() {
return enabled;
}
public void accept(GraphConversionVisitor visitor) {
if (rootNode == null) return;
rootNode.accept(visitor);
}
}
class MethodCallPath {
ArrayList<MethodWrapper> path;
public MethodCallPath(MethodWrapper source) {
path = new ArrayList<MethodWrapper>(source.getLevel());
path.add(source);
MethodWrapper current = source;
MethodWrapper parent;
while( (parent = current.getParent()) != null) {
path.add(0, parent);
current = parent;
}
}
public MethodCallNode walk(MethodCallNode rootNode) {
if (path.size() <= 1) return rootNode;
MethodCallNode target = rootNode;
java.util.List<MethodWrapper> subList = path.subList(1, path.size());
for (MethodWrapper each: subList) {
target = target.getChild(each);
if (target == null) return null;
}
return target;
}
}
class MethodCallNode {
private MethodWrapper sourceMethod;
private ArrayList<MethodCallNode> children;
private CallModel model;
public MethodCallNode(MethodWrapper currentRootMethod, CallModel flowModel) {
model = flowModel;
sourceMethod = currentRootMethod;
children = new ArrayList<MethodCallNode>();
}
public void accept(GraphConversionVisitor visitor) {
visitor.visit(this);
for(MethodCallNode each: children) {
each.accept(visitor);
}
}
public void clearChildren() {
if (children.isEmpty()) return;
children.clear();
model.setDirty();
}
public void setChildren(List<MethodWrapper> targets) {
children.clear();
for (MethodWrapper each: targets) {
children.add(new MethodCallNode(each, model));
}
model.setDirty();
}
public MethodCallNode getChild(MethodWrapper wrapper) {
for (MethodCallNode child: children) {
if (child.represents(wrapper)) return child;
}
return null;
}
private boolean represents(MethodWrapper m) {
return sourceMethod.equals(m);
}
public MethodWrapper getSourceMethod() {
return sourceMethod;
}
public ArrayList<MethodCallNode> getChildren() {
return children;
}
}