package org.freeplane.plugin.script;
import java.util.ArrayList;
import org.apache.commons.lang.StringUtils;
import org.freeplane.core.util.HtmlUtils;
import org.freeplane.core.util.LogUtils;
import org.freeplane.features.map.NodeModel;
public class ScriptContext {
private static final class NodeWrapper {
private final NodeModel nodeModel;
private final String script;
public NodeWrapper(NodeModel nodeModel, String script) {
this.nodeModel = nodeModel;
// NOTE: to ignore the script for cycle detection comment out next line
this.script = script;
}
public NodeModel getNodeModel() {
return nodeModel;
}
// public String getScript() {
// return script;
// }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((nodeModel == null) ? 0 : nodeModel.hashCode());
result = prime * result + ((script == null) ? 0 : script.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NodeWrapper other = (NodeWrapper) obj;
if (nodeModel != other.nodeModel)
return false;
if (script == null) {
if (other.script != null)
return false;
}
return script.equals(other.script);
}
@Override
public String toString() {
return nodeModel + "[" + script + "]";
}
}
private final UniqueStack<NodeWrapper> stack = new UniqueStack<NodeWrapper>();
public ScriptContext() {
}
public void accessNode(final NodeModel accessedNode) {
FormulaUtils.accessNode(stack.last().getNodeModel(), accessedNode);
}
public void accessBranch(final NodeModel accessedNode) {
FormulaUtils.accessBranch(stack.last().getNodeModel(), accessedNode);
}
public void accessAll() {
FormulaUtils.accessAll(stack.last().getNodeModel());
}
public boolean push(NodeModel nodeModel, String script) {
final boolean success = stack.push(new NodeWrapper(nodeModel, script));
if (!success) {
LogUtils.warn("Circular reference detected! Traceback (innermost last):\n " //
+ stackTrace(nodeModel, script));
}
return success;
}
public void pop() {
stack.pop();
}
public NodeModel getStackFront() {
return stack.first().getNodeModel();
}
public String stackTrace(NodeModel nodeModel, String script) {
ArrayList<String> entries = new ArrayList<String>(stack.size());
for (NodeWrapper node : stack) {
entries.add(format(node.nodeModel, node.script, nodeModel));
}
entries.add(format(nodeModel, script, nodeModel));
return StringUtils.join(entries.iterator(), "\n -> ");
}
private String format(NodeModel nodeModel, String script, NodeModel nodeToHighlight) {
return (nodeToHighlight.equals(nodeModel) ? "* " : "") + nodeModel.createID() + " "
+ limitLength(deformat(nodeModel.getText()), 30) //
+ " -> " + limitLength(script, 60);
}
private String deformat(String string) {
return HtmlUtils.htmlToPlain(string).replaceAll("\\s+", " ");
}
private String limitLength(final String string, int maxLenght) {
if (string == null || maxLenght >= string.length())
return string;
maxLenght = maxLenght > 3 ? maxLenght - 3 : maxLenght;
return string.substring(0, maxLenght) + "...";
}
@Override
public String toString() {
return stack.toString();
}
}