package com.drawbridge.utils;
import java.util.HashSet;
import java.util.LinkedList;
import com.drawbridge.dm.DMImageFactory.DMImage;
import com.drawbridge.jsengine.ast.DBParser;
import com.drawbridge.jsengine.ast.DeclarationEvaluator;
import com.drawbridge.jsengine.ast.Evaluator;
import com.drawbridge.jsengine.ast.IntegerLiteralEvaluator;
import com.drawbridge.jsengine.ast.NoopEvaluator;
import com.drawbridge.jsengine.ast.NumberLiteralEvaluator;
import com.drawbridge.jsengine.ast.SpecialOperationEvaluator;
import com.drawbridge.text.TextPanel;
import com.google.caja.lexer.FilePosition;
public class ASTModification
{
public static enum ASTModificationType
{
MOD_LOCATION,
MOD_SIZE;
}
/**
* Allows modification of parts of the E-AST that refer to the given image. Usually used by the DM Panel.
*
* @param image
* @param mod
* @return
*/
public static <P> boolean modifyImageParams(DMImage image, ASTModification.ASTModificationType mod)
{
Utils.out.println(ASTModification.class, "modifyImageParams");
// Reset the recently changed evaluators
DBParser.getInstance().mRecentlyChangedEvaluators.clear();
Evaluator e = null;
switch (mod)
{
case MOD_LOCATION:
e = image.getEvaluatorNode(ASTModification.ASTModificationType.MOD_LOCATION);
break;
case MOD_SIZE:
e = image.getEvaluatorNode(ASTModification.ASTModificationType.MOD_SIZE);
break;
default:
return false;
}
if (e instanceof DeclarationEvaluator)
{
DeclarationEvaluator de = (DeclarationEvaluator) e;
Utils.out.println("Last modifer of " + mod.name() + " was a DeclarationEvaluator " + de.mChildren.size());
throw new RuntimeException("modifyImageParams not implemented yet");
}
else if (e instanceof SpecialOperationEvaluator)
{
// it's setTweenLocation/setTweenSize or loadImage
SpecialOperationEvaluator soEval = (SpecialOperationEvaluator) e;
HashSet<Evaluator> changedEvaluators = new HashSet<Evaluator>();
switch (mod)
{
case MOD_LOCATION:
NumberLiteralEvaluator<Integer> evalX = (NumberLiteralEvaluator<Integer>) soEval.mChildren.get(2);
NumberLiteralEvaluator<Integer> evalY = (NumberLiteralEvaluator<Integer>) soEval.mChildren.get(3);
if(DBParser.getInstance().containsEvaluator(evalY)){
Utils.err.println(ASTModification.class,"MOD_LOCATION_CONTAINS_EVALUATOR");
}
else{
Utils.err.println(ASTModification.class,"MOD_LOCATION_DOES_NOT_CONTAIN_EVALUATOR");
}
boolean changedX = modifyILEvaluatorValue(evalX, image.getX());
boolean changedY = modifyILEvaluatorValue(evalY, image.getY());
if(changedX)
changedEvaluators.add(evalX);
if(changedY)
changedEvaluators.add(evalY);
break;
case MOD_SIZE:
IntegerLiteralEvaluator evalW = (IntegerLiteralEvaluator) soEval.mChildren.get(4);
IntegerLiteralEvaluator evalH = (IntegerLiteralEvaluator) soEval.mChildren.get(5);
boolean changedW = modifyILEvaluatorValue(evalW, image.getWidth());
boolean changedH = modifyILEvaluatorValue(evalH, image.getHeight());
if(changedW)
changedEvaluators.add(evalW);
if(changedH)
changedEvaluators.add(evalH);
break;
}
DBParser.getInstance().mRecentlyChangedEvaluators = changedEvaluators;
if(TextPanel.hasInstance()){
TextPanel.getInstance().getDocument().repaint();
}
return true;
}
return false;
}
public interface JavaNumber{
}
/**
* Modifies the value in the evaluator
* @param e
* @param newValue
* @return boolean - True if the value has changed.
*/
public static <T> boolean modifyILEvaluatorValue(NumberLiteralEvaluator<T> e, T newValue)
{
T validNewValue = e.getValidValue((Double)newValue);
Utils.err.println(Utils.class, "ASTMODIFICATION");
int filePosDiff = e.getFPDiff(validNewValue); //this is probably very dodgy
e.modifyValue(null, validNewValue, true);
if (filePosDiff != 0) {
Utils.err.println(ASTModification.class, "Before: " + e.toString() + " " + e.getFilePosition().toString());
expandFPInContext(e, filePosDiff);
Utils.err.println(ASTModification.class, "After:" + e.getFilePosition().toString());
Evaluator ancestor = getEvalParent(e);
LinkedList<Evaluator> evals = DBParser.getInstance().getEvaluators();
if (evals.contains(ancestor)) {
int nextIndex = evals.indexOf(ancestor) + 1;
if (nextIndex < evals.size() && evals.get(nextIndex) instanceof NoopEvaluator) {
shiftFP(evals.get(nextIndex), filePosDiff);
}
}
}
if(validNewValue == newValue)
return true;
return false;
}
/**
* Recursively traverse E-AST, changing FilePositions of parents and siblings to the right
*
* @param Evaluator
* @param LengthDifference
*/
public static void expandFPInContext(Evaluator e, int lengthDiff)
{
// Widen fp
expandFP(e, lengthDiff);
Evaluator parent = e.mParent;
// Deal with direct ancestors
if (parent != null) {
Utils.out.println("Expanding parent:" + parent.toString() + " Before:" + parent.getFilePosition().toString() + "->");
expandFPInContext(parent, lengthDiff);
Utils.out.println(" " + parent.getFilePosition().toString());
}
// Deal with siblings
if (parent != null) {
LinkedList<Evaluator> siblings = parent.mChildren;
int startIndex = Integer.MAX_VALUE;
for (int i = 0; i < siblings.size(); i++) {
if(siblings.get(i) == e){
Utils.err.println("Found equal evaluators at " + i + " of " + siblings.size());
startIndex = i + 1;
}
if(i >= startIndex){
Utils.out.println("Shifting sibling:" + siblings.get(i).toString());
shiftFP(siblings.get(i), lengthDiff);
}
}
}
}
/**
* Changes the length of the FilePosition by the Length Difference
*
* @param FilePosition
* @param Length
* Difference
* @return Updated FilePosition
*/
public static void expandFP(Evaluator e, int diff)
{
FilePosition fp = e.getFilePosition();
e.setFilePosition(FilePosition.instance(fp.source(), fp.startLineNo(), fp.startCharInFile(), fp.startCharInLine(), Math.max(0, fp.length() + diff)));
}
/**
* Moves a file position by a given number of characters. Doesn't do any changes across lines
*
* @param FilePosition
* @param Character
* shift
* @return Updated FilePosition
*/
public static void shiftFP(Evaluator e, int shift)
{
FilePosition fp = e.getFilePosition();
e.setFilePosition(FilePosition.instance(fp.source(), fp.startLineNo(), fp.startCharInFile() + shift, fp.startCharInLine() + shift, fp.length()));
}
public static Evaluator getEvalParent(Evaluator e)
{
if (e.mParent != null) {
return getEvalParent(e.mParent);
}
else {
return e;
}
}
}