/*
* IfOperation.java
* @Author Oleg Gorobets
* Created: 25.07.2007
* CVS-ID: $Id:
*************************************************************************/
package org.swfparser.operation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import org.springframework.util.Assert;
import org.apache.log4j.Logger;
import org.swfparser.BooleanOperation;
import org.swfparser.CodeUtil;
import org.swfparser.DualUse;
import org.swfparser.ExecutionContext;
import org.swfparser.Operation;
import org.swfparser.SkipOperation;
import org.swfparser.exception.StatementBlockException;
import com.jswiff.swfrecords.actions.Action;
public class IfOperation extends AbstractCompoundOperation implements SkipOperation {
private static Logger logger = Logger.getLogger(IfOperation.class);
protected Operation condition;
// private List<Action> actions = new ArrayList<Action>();
protected List<Operation> operations = new ArrayList<Operation>();
protected boolean skip = false;
// public Operation readIf(Stack<Operation> stack, List<Action> actions, ExecutionContext context) throws StatementBlockException {
//
// }
public IfOperation(ExecutionContext context) {
super(context);
}
public IfOperation(Stack<Operation> stack, List<Action> actions, ExecutionContext context) throws StatementBlockException {
super(context);
this.condition = stack.pop();
Assert.isTrue(validateCondition(this.condition));
readActions(actions);
}
/**
* @param actions
* @return execution stack after reading actions
* @throws StatementBlockException
*/
protected Stack<Operation> readActions(List<Action> actions) throws StatementBlockException {
// Parse actions
context.getOperationStack().push(this);
logger.debug("stack before: "+context.getExecStack().size());
Stack<Operation> beforeStack = context.getExecStack();
Stack<Operation> newExecutionStack = copyExecutionStack( context.getExecStack() );
// Stack<Operation> newExecutionStack = new Stack<Operation>();
// Stack<Operation> beforeStack = context.getExecStack();
// for (Operation op : beforeStack) {
// newExecutionStack.push(op);
// }
boolean equalStacksBefore = Arrays.equals(context.getExecStack().toArray(), newExecutionStack.toArray());
Assert.isTrue(equalStacksBefore);
context.setExecStack(newExecutionStack);
statementBlock.setExecutionContext(context);
statementBlock.read(actions);
operations = statementBlock.getOperations();
logger.debug("stack after: "+context.getExecStack().size());
Stack<Operation> afterStack = context.getExecStack();
boolean equalStack = Arrays.equals(beforeStack.toArray(), afterStack.toArray());
// Do not write action at all if unequal stacks (|| or && actions) and empty operations inside.
if (!equalStack && operations.isEmpty()) {
skip = true;
}
// Check if after stack contains some dual use operations in the stack such as CallFunctionOperation etc.
if (!equalStack && beforeStack.size()<afterStack.size()) {
while (!afterStack.isEmpty() && (afterStack.peek() instanceof DualUse)) {
Operation dualUseOperation = afterStack.pop();
((DualUse)dualUseOperation).markAsStatement();
logger.debug("Adding dual-use "+dualUseOperation+" operation in the end of \"if\" statement");
operations.add(dualUseOperation);
}
}
// restore previous stack but with unequal stack handling
context.setExecStack(handleUnequalStack(condition, beforeStack, afterStack));
context.getOperationStack().pop();
return afterStack;
}
private boolean validateCondition(Operation op) {
logger.debug("Validating condition "+op);
return (op instanceof BooleanOperation || op instanceof ConvertOperation);
}
public int getArgsNumber() {
// TODO Auto-generated method stub
return 0;
}
protected String getLoopHeader() {
return "if";
}
protected String getHeaderLine() {
StringBuilder sourceCode = new StringBuilder();
sourceCode.append(getLoopHeader());
sourceCode.append(" (");
// .append(getInvertedString(condition,0))
sourceCode.append(((BooleanOperation) condition).getInvertedOperation().getStringValue(0));
sourceCode.append(") {");
return sourceCode.toString();
}
protected String getFooterLine() {
return "}";
}
public String getStringValue(int level) {
StringBuilder buf = new StringBuilder();
buf.append(CodeUtil.getIndent(level));
buf.append(getHeaderLine());
buf.append("\n");
for (Operation op : operations) {
buf.append(op.getStringValue(level+1));
buf.append(CodeUtil.endOfStatement(op));
buf.append("\n");
}
buf.append(CodeUtil.getIndent(level));
buf.append(getFooterLine());
return buf.toString();
// } else {
// //
// // Skip if() if no operations inside
// //
// StringBuffer buf = new StringBuffer()
// .append(getLoopHeader())
// .append(" (")
// .append(((BooleanOperation)condition).getInvertedOperation().getStringValue(level))
// .append(")");
//
// return CodeUtil.getIndent(level)+"// Empty "+buf.toString()+" skipped";
// return "";
// }
}
@Override
public String toString() {
return "If("+condition+")";
}
public boolean skip() {
return skip;
}
// protected String getInvertedString(Operation op, int level) {
// return (condition instanceof BooleanOperation)
// ? ((BooleanOperation)condition).getInvertedStringValue(level)
// : "!"+op.getStringValue(level);
// }
}