/*
* SwitchOperation.java
* @Author Oleg Gorobets
* Created: 05.09.2007
* CVS-ID: $Id:
*************************************************************************/
package org.swfparser.operation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import org.springframework.util.Assert;
import org.apache.log4j.Logger;
import org.swfparser.CodeUtil;
import org.swfparser.ExecutionContext;
import org.swfparser.Operation;
import org.swfparser.exception.StatementBlockException;
import org.swfparser.pattern.SwitchPattern;
import com.jswiff.swfrecords.actions.Action;
public class SwitchOperation extends AbstractCompoundOperation {
private static Logger logger = Logger.getLogger(SwitchOperation.class);
private Operation switchParam;
private Operation externalCondition;
private List<Operation> conditions = new ArrayList<Operation>();
private List<List<Operation>> switchStatements = new ArrayList<List<Operation>>();
private Set<Operation> leftConditionOperations = new HashSet<Operation>();
private Set<Operation> rightConditionOperations = new HashSet<Operation>();
private List<Operation> defaultOperations = new ArrayList<Operation>();
public SwitchOperation(ExecutionContext context, SwitchPattern pattern) throws StatementBlockException {
super(context);
externalCondition = stack.pop();
Map<Operation,Integer> opCountMap = new HashMap<Operation, Integer>();
Assert.isInstanceOf(EqualsOperation.class, externalCondition);
conditions.add( externalCondition );
leftConditionOperations.add(((EqualsOperation)externalCondition).getLeftOp());
rightConditionOperations.add(((EqualsOperation)externalCondition).getRightOp());
logger.debug("Cond.1 = "+externalCondition);
int idx = 2;
for (List<Action> actionBlock : pattern.getConditionBlocks()) {
executeWithSameStack(context, actionBlock, this);
EqualsOperation switchCondition = (EqualsOperation) stack.pop(); // emulate if statement
conditions.add( switchCondition );
leftConditionOperations.add( switchCondition.getLeftOp() );
rightConditionOperations.add( switchCondition.getRightOp() );
logger.debug("Cond."+(idx++)+" = "+switchCondition);
}
// if (leftConditionOperations.size() == 1) {
// switchParam = leftConditionOperations.iterator().next();
// conditions = getLeftOrRightOperations(false);
// } else if (rightConditionOperations.size() == 1) {
// switchParam = rightConditionOperations.iterator().next();
// conditions = getLeftOrRightOperations(true);
// }
// Assume left op is switch param
conditions = getLeftOrRightOperations(false);
switchParam = ((EqualsOperation)externalCondition).getLeftOp();
// Read statements
List<Stack<Operation>> stacksAfterSwitchBlocks = new ArrayList<Stack<Operation>>();
for (List<Action> actionBlock : pattern.getSwitchBlocks()) {
BlockExecutionResult executionResult = executeWithCopiedStack(context, actionBlock, this);
stacksAfterSwitchBlocks.add( executionResult.getStack() );
switchStatements.add( executionResult.getOperations() );
}
// Read default block
if (!pattern.getDefaultActions().isEmpty()) {
defaultOperations.addAll( executeWithCopiedStack(context, pattern.getDefaultActions(), this).getOperations() );
}
int i = 1;
for (Stack<Operation> s : stacksAfterSwitchBlocks) {
logger.debug("Dumping stack "+(i++)+":");
for (int j = s.size()-1; j>=0; j--) {
logger.debug("###S:"+s.get(j));
}
}
// set stack to the stack we get from executing \switch statements
if (equalStacks(stacksAfterSwitchBlocks)) {
context.setExecStack( copyExecutionStack(stacksAfterSwitchBlocks.get(0)) );
} else {
logger.error("Unequal stacks after switch operation!");
}
}
public String getStringValue(int level) {
StringBuffer buf = new StringBuffer()
.append(CodeUtil.getIndent(level))
.append("switch (")
.append(switchParam.getStringValue(level))
.append(") {\n");
for (int j=0; j<conditions.size(); j++) {
Operation cond = conditions.get(j);
buf
.append(CodeUtil.getIndent(level+1))
.append("case ")
.append(cond.getStringValue(0))
.append(":\n");
// switch statements
for (Operation op : switchStatements.get(j)) {
buf
.append(op.getStringValue(level+2))
.append(CodeUtil.endOfStatement(op))
.append("\n");
}
buf.append(CodeUtil.getIndent(level+1)).append("\n");
}
// default clause
if (!defaultOperations.isEmpty()) {
buf
.append(CodeUtil.getIndent(level+1))
.append("default:\n");
for (Operation op : defaultOperations) {
buf
.append(op.getStringValue(level+2))
.append(CodeUtil.endOfStatement(op))
.append("\n");
}
}
buf.append(CodeUtil.getIndent(level)).append("}");
return buf.toString();
}
private Operation getFirstCondition(Operation condition) {
if (condition instanceof EqualsOperation) {
return getSimpleOp ( ((EqualsOperation)condition).getLeftOp(), ((EqualsOperation)condition).getRightOp());
} else {
throw new IllegalArgumentException("Invalid condition in switch(): "+condition);
}
}
/**
* TODO: consider using op1 or op2
*
* @param op1
* @param op2
* @return
*/
private Operation getSimpleOp(Operation op1, Operation op2) {
return op1;
// if (op1 instanceof StackValue) {
// return op1;
// } else if (op2 instanceof StackValue) {
// return op2;
// } else {
// throw new IllegalArgumentException("Invalid type of condition args in switch(): "+op1+" and "+op2);
// }
}
private List<Operation> getLeftOrRightOperations(boolean left) {
List<Operation> newConditions = new ArrayList<Operation>();
for (Operation op : conditions) {
newConditions.add(left ? ((EqualsOperation)op).getLeftOp() : ((EqualsOperation)op).getRightOp());
}
return newConditions;
}
@Override
public String toString() {
return getClass().getSimpleName()+"("+switchParam+")";
}
}