package edu.kit.iti.formal.pse.worthwhile.interpreter;

import edu.kit.iti.formal.pse.worthwhile.model.Value;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Expression;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Literal;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ReturnValueReference;
import edu.kit.iti.formal.pse.worthwhile.model.ast.SymbolReference;
import edu.kit.iti.formal.pse.worthwhile.model.ast.VariableDeclaration;
import edu.kit.iti.formal.pse.worthwhile.model.ast.VariableReference;
import edu.kit.iti.formal.pse.worthwhile.model.ast.util.AstNodeCreatorHelper;
import edu.kit.iti.formal.pse.worthwhile.model.ast.visitor.SubstitutionVisitor;

/**
 * This {@link SubstitutionVisitor} replaces {@link SymbolReference}s with {@link Literal}s representing the
 * {@link Value}s assigned to them by the execution state of an {@link InterpreterASTNodeVisitor}.
 * 
 * @author fabian
 */
public class SymbolReferenceResolver extends SubstitutionVisitor<Literal> {
	/**
	 * The execution state containing the {@link VariableDeclaration} to {@link Value} mapping that is used to
	 * resolve the {@link SymbolReference}s that occur in {@link Expression}s this visitor is applied to.
	 */
	private final InterpreterASTNodeVisitor interpreterState;

	/**
	 * Applies this {@link SymbolReferenceResolver} to the given {@link Expression}.
	 * 
	 * @param expression
	 *                the <code>Expression</code> in which {@link SymbolReference}s are resolved
	 * @param state
	 *                the {@link InterpreterASTNodeVisitor} whose execution state is used to resolve symbols in
	 *                <code>expression</code>
	 * @return <code>expression</code> with all symbols resolved that are mapped by <code>state</code>
	 */
	public static Expression apply(final Expression expression, final InterpreterASTNodeVisitor state) {
		final SymbolReferenceResolver visitor = new SymbolReferenceResolver(state);

		expression.accept(visitor);
		if (visitor.getFound()) {
			return visitor.getSubstitute();
		} else {
			return expression;
		}

	}

	/**
	 * @param interpreterState
	 *                an execution state containing the {@link VariableDeclaration} to {@link Value} mapping that is
	 *                used to resolve the {@link SymbolReference}s that occur in {@link Expression}s this visitor is
	 *                applied to
	 */
	SymbolReferenceResolver(final InterpreterASTNodeVisitor interpreterState) {
		// it is not necessary to clone the substitutes we set because they are not contained anywhere
		super(null, false);
		this.interpreterState = interpreterState;
	}

	@Override
	public final void visit(final ReturnValueReference returnValueReference) {
		// do not forget to visit index
		super.visit(returnValueReference);

		// when the InterpreterASTNodeVisitor is evaluating an Expression that contains ReturnValueReferences it
		// must have set a return value
		final Value value = this.interpreterState.getReturnValue();

		this.setSubstitute(AstNodeCreatorHelper.createLiteral(value));
		this.setFound(true);
	}

	@Override
	public final void visit(final VariableReference variableReference) {
		// do not forget to visit index
		super.visit(variableReference);

		final Value value = this.interpreterState.getSymbol(variableReference.getVariable());

		// since VariableReferences can refer to variables bound by a quantifier we do not require the state to
		// contain a mapping for all of them
		if (value != null) {
			this.setSubstitute(AstNodeCreatorHelper.createLiteral(value));
			this.setFound(true);
		}
	}
}

@@ -906,16 +906,184 @@
 ian%0A */%0A
+// TODO: as soon as we are using ArrayAccess instead of VariableReference's index from the original AST on we can reset%0A// the substitute generic type to Literal again%0A
 public c
@@ -1139,23 +1139,26 @@
 Visitor%3C
-Literal
+Expression
 %3E %7B%0A%09/**
@@ -3137,25 +3137,28 @@
 e();%0A%0A%09%09
-this.setS
+Expression s
 ubstitut
@@ -3150,33 +3150,35 @@
 ssion substitute
-(
+ = 
 AstNodeCreatorHe
@@ -3198,24 +3198,221 @@
 teral(value)
+;%0A%0A%09%09final Expression index = returnValueReference.getIndex();%0A%09%09if (index != null) %7B%0A%09%09%09substitute = AstNodeCreatorHelper.createArrayAccess(index, substitute);%0A%09%09%7D%0A%0A%09%09this.setSubstitute(substitute
 );%0A%09%09this.se
@@ -3839,25 +3839,28 @@
 l) %7B%0A%09%09%09
-this.setS
+Expression s
 ubstitut
@@ -3860,17 +3860,19 @@
 bstitute
-(
+ = 
 AstNodeC
@@ -3904,16 +3904,215 @@
 l(value)
+;%0A%0A%09%09%09final Expression index = variableReference.getIndex();%0A%09%09%09if (index != null) %7B%0A%09%09%09%09substitute = AstNodeCreatorHelper.createArrayAccess(index, substitute);%0A%09%09%09%7D%0A%0A%09%09%09this.setSubstitute(substitute
 );%0A%09%09%09th

Fix SymbolReferenceResolver ignores indexed references