package com.mobilesorcery.sdk.html5.debug.rewrite;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.core.runtime.Assert;
import org.eclipse.wst.jsdt.core.dom.ASTNode;
import org.eclipse.wst.jsdt.core.dom.BodyDeclaration;
import org.eclipse.wst.jsdt.core.dom.JSdoc;
import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite;
import com.mobilesorcery.sdk.core.IFilter;
import com.mobilesorcery.sdk.core.IProvider;
import com.mobilesorcery.sdk.html5.Html5Plugin;
import com.mobilesorcery.sdk.html5.debug.JSODDSupport;
import com.mobilesorcery.sdk.html5.debug.Position;
/**
* The base class for instrumenting JavaScript AST nodes
* @author Mattias Bybro, mattias.bybro@mosync.com
*
*/
public class NodeRewrite {
private static final NodeRewrite NULL = new NodeRewrite(null, null);
private ASTNode node;
protected ISourceSupport rewriter;
private ArrayList<NodeRewrite> rewrites = new ArrayList<NodeRewrite>();
private HashMap<ASTNode, NodeRewrite> rewritesByNode = new HashMap<ASTNode, NodeRewrite>();
private String blacklistReason = null;
public NodeRewrite(ISourceSupport source, ASTNode node) {
this.rewriter = source;
this.node = node;
if (node != null && (node.getFlags() & ASTNode.MALFORMED) != 0) {
setBlacklisted("Unknown syntactical error.");
}
// There is code that is ok that gets flagged MALFORMED, so we can't
// really throw an exception here.
//if (node != null && (node.getFlags() & ASTNode.MALFORMED) != 0) {
// System.err.println("MALFORMED!" + node);//throw new IllegalArgumentException();
//}
}
public void addChild(NodeRewrite rewrite) {
if (rewrite == this) {
throw new IllegalArgumentException();
}
if (!isAncestor(node, rewrite.getNode())) {
throw new IllegalArgumentException();
}
this.rewrites.add(rewrite);
this.rewritesByNode.put(rewrite.getNode(), rewrite);
}
private boolean isAncestor(ASTNode ancestor, ASTNode node) {
if (node == null) {
return false;
}
if (ancestor == null) {
return true;
}
if (ancestor == node.getParent()) {
return true;
} else {
return isAncestor(ancestor, node.getParent());
}
}
public ASTNode getNode() {
return node;
}
public boolean supports(IFilter<String> features, String feature) {
if (!Html5Plugin.getDefault().isFeatureSupported(feature)) {
return false;
}
if (features == null) {
// TODO: return whatever is enabled for this rewrite
return true;
} else {
return features.accept(feature);
}
}
public Position getPosition(ASTNode node, boolean before) {
if (node == null) {
return null;
}
return rewriter.getPosition(node, before);
}
public NodeRewrite getRewrite(ASTNode node) {
NodeRewrite rewrite = rewritesByNode.get(node);
return rewrite == null ? NodeRewrite.NULL : rewrite;
}
public void rewrite(IFilter<String> features, IRewrite rewrite) {
defaultRewrite(features, rewrite);
}
protected void defaultRewrite(IFilter<String> features, IRewrite rewrite) {;
TreeMap<Integer, NodeRewrite> sortedByPosition = new TreeMap<Integer, NodeRewrite>();
for (NodeRewrite rewriter : rewrites) {
sortedByPosition.put(getPosition(rewriter.getNode(), true).getPosition(), rewriter);
}
for (Map.Entry<Integer, NodeRewrite> rewriteEntry : sortedByPosition.entrySet()) {
NodeRewrite nodeRewrite = rewriteEntry.getValue();
if (nodeRewrite.isBlacklisted() == null) {
nodeRewrite.rewrite(features, rewrite);
}
}
/*if (rewrites.isEmpty()) {
return getSource(node);
}
TreeMap<Integer, NodeRewrite> sortedByPosition = new TreeMap<Integer, NodeRewrite>();
for (NodeRewrite rewriter : rewrites) {
sortedByPosition.put(getPosition(rewriter.getNode(), true).getPosition(), rewriter);
}
ASTNode replacedNode = getNode();
Position startPosition = getPosition(replacedNode,true);
Position endPosition = getPosition(replacedNode, false);
StringBuffer result = new StringBuffer();
String source = getSource();
int start = replacedNode == null ? 0 : startPosition.getPosition();
int length = replacedNode == null ? source.length() : endPosition.getPosition() - startPosition.getPosition();
int lastPos = start;
for (Integer position : sortedByPosition.keySet()) {
if (lastPos > position) {
lastPos = position; //throw new IllegalStateException();
}
String originalSnippet = source.substring(lastPos, position);
result.append(originalSnippet);
NodeRewrite rewrite = sortedByPosition.get(position);
String rewrittenSnippet = rewrite.rewrite(features);
result.append(rewrittenSnippet);
REWRITES += originalSnippet.length() + rewrittenSnippet.length();
ASTNode rewriteNode = rewrite.getNode();
int replacedLength = getPosition(rewriteNode, false).getPosition() - getPosition(rewriteNode, true).getPosition();
lastPos = position + replacedLength;
}
if (lastPos < start + length) {
REWRITES += start + length - lastPos;
result.append(source.substring(lastPos, start + length));
}
System.err.println("OOPS: " + REWRITES);
return result.toString();*/
}
protected String getSource(ASTNode node) {
Assert.isNotNull(node);
int start = getPosition(node, true).getPosition();
int end = getPosition(node, false).getPosition();
return rewriter.getSource(start, end);
}
protected String getSource() {
return rewriter.getSource();
}
protected void setBlacklisted(String reason) {
this.blacklistReason = reason;
}
public String isBlacklisted() {
return blacklistReason;
}
public static IFilter<String> include(final String... features) {
return new IFilter<String>() {
@Override
public boolean accept(String feature) {
for (int i = 0; i < features.length; i++) {
if (features[i].equals(feature)) {
return true;
}
}
return false;
}
};
}
}