padre-master/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/SwitchStatement.java
package org.eclipse.epsilon.eol.dom;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.epsilon.common.parse.AST;
import org.eclipse.epsilon.common.util.AstUtil;
import org.eclipse.epsilon.eol.compile.context.EolCompilationContext;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.exceptions.flowcontrol.EolBreakException;
import org.eclipse.epsilon.eol.exceptions.flowcontrol.EolContinueException;
import org.eclipse.epsilon.eol.execute.Return;
import org.eclipse.epsilon.eol.execute.context.IEolContext;
import org.eclipse.epsilon.eol.parse.EolParser;

public class SwitchStatement extends Statement {
	
	protected Expression conditionExpression;
	protected List<Case> cases = new ArrayList<Case>();
	protected Case _default;
	
	public SwitchStatement() {}
	
	public SwitchStatement(Expression conditionExpression, List<Case> cases, Case _default) {
		this.conditionExpression = conditionExpression;
		this.cases = cases;
		this._default = _default;
	}

	@Override
	public void build() {
		super.build();
		for (AST child : getChildren()) {
			if (child.getType() == EolParser.DEFAULT) {
				_default = (Case) child;
			}
			else if (child.getType() == EolParser.CASE){
				cases.add((Case) child);
			}
			else if (child instanceof Expression){
				conditionExpression = (Expression) child;
			}
		}
	}
	
	public List<Case> getCases() {
		return cases;
	}
	
	public Case getDefault() {
		return _default;
	}
	
	public Expression getConditionExpression() {
		return conditionExpression;
	}
	
	public void setConditionExpression(Expression conditionExpression) {
		this.conditionExpression = conditionExpression;
	}
	
	@Override
	public Object execute(IEolContext context) throws EolRuntimeException {
		
		AST switchValueAst = getFirstChild();
		
		Object switchValue = context.getExecutorFactory().executeAST(switchValueAst, context);
		
		AST nextCase = switchValueAst.getNextSibling();
		
		try {
			
			boolean continue_ = false;
			
			while (nextCase != null) {
				
				if (nextCase.getType() == EolParser.CASE) {
					AST caseValueAst = nextCase.getFirstChild();
					
					if (continue_ || equals(context.getExecutorFactory().executeAST(caseValueAst, context), switchValue)) {
						AST caseBodyStatement = caseValueAst.getNextSibling();
						try {
							Object result = context.getExecutorFactory().executeAST(caseBodyStatement, context);
							if (result instanceof Return) return result;
						}
						catch (EolContinueException ex) {
							continue_ = true;
						}
						
						if (!continue_) { break; }
						
					}
				}
				else if (nextCase.getType() == EolParser.DEFAULT) {
					AST defaultBodyStatement = nextCase.getFirstChild();
					Object result = context.getExecutorFactory().executeAST(defaultBodyStatement, context);
					if (result instanceof Return) return result;
					
				}
				
				nextCase = nextCase.getNextSibling();
				
			}
			
		}
		catch (EolBreakException e) {
			
		}
		
		return null;
	}
	
	@Override
	public void compile(EolCompilationContext context) {
		// TODO Auto-generated method stub
		
	}
	
	protected boolean equals(Object o1, Object o2) {
		if (o1 == null && o2 == null) return true;
		if (o1 == null || o2 == null) return false;
		return o1.equals(o2);
	}
	
	@Override
	public String rewrite(){
		
		String toString = "\n";
		
		AST p = getParent();
		while(p.getType() != EolParser.EOLMODULE)
		{
			if (p.getType() != EolParser.BLOCK)
			{
				toString += "\t";
			}
			p = p.getParent();
		}
			
		toString += "switch (" + getFirstChild().rewrite() + ")\n";
		
		toString += toString.substring(1, toString.indexOf("switch")) + "{\n";
		
		for(AST child : getChildren())
		{
			if (child.getType() == EolParser.CASE)
				toString += child.rewrite();
			
			if (child.getType() == EolParser.DEFAULT)
			{
				toString += "\n" + toString.substring(1, toString.indexOf("switch")) + "\t" + "default :\n" + child.getFirstChild().rewrite();
			}
				
		}
		
		toString += "\n" + toString.substring(0, toString.indexOf("switch")) + "}"; 
		return toString;
	}
}
