/*
 * generated by Xtext
 */
package edu.kit.iti.formal.pse.worthwhile.scoping;

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

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.xtext.resource.EObjectDescription;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
import org.eclipse.xtext.scoping.impl.SimpleScope;

import edu.kit.iti.formal.pse.worthwhile.model.ast.ASTNode;
import edu.kit.iti.formal.pse.worthwhile.model.ast.FunctionCall;
import edu.kit.iti.formal.pse.worthwhile.model.ast.FunctionDeclaration;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Program;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Statement;
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.AstNodeParentHelper;

/**
 * This class contains custom scoping description.
 * 
 * see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping on how and when to use it
 * 
 */
public class WorthwhileScopeProvider extends AbstractDeclarativeScopeProvider {

	/**
	 * Provides the scope for a function call's function reference.
	 * 
	 * @param context
	 *                The function call to provide the scope for.
	 * @param reference
	 *                The corresponding EReference in the Ecore model.
	 * @return A scope in which to look for the referenced function.
	 */
	public final IScope scope_FunctionCall_function(final FunctionCall context, final EReference reference) {
		// Find the containing program.
		Program containingProgram = AstNodeParentHelper.findParentProgram(context);
		FunctionDeclaration containingFunctionDeclaration = AstNodeParentHelper
		                .findParentFunctionDeclaration(context);

		// Collect all function declarations until the containing function declaration
		ScopeFinder scopeFinder = new ScopeFinder(containingFunctionDeclaration);
		containingProgram.accept(scopeFinder);
		
		List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
		for (FunctionDeclaration funcdecl: scopeFinder.getFunctionDeclarations()) {
			descriptions.add(EObjectDescription.create(funcdecl.getName(), funcdecl));
		}

		return new SimpleScope(IScope.NULLSCOPE, descriptions);
	}

	/**
	 * Provides the scope for a variable reference.
	 * 
	 * @param context
	 *                The variable reference to provide the scope for.
	 * @param reference
	 *                The corresponding EReference in the Ecore model.
	 * @return
	 */
	public final IScope scope_VariableReference_variable(final VariableReference context, final EReference reference) {
		// Find the containing statement
		ASTNode current = context;
		ASTNode container = AstNodeParentHelper.findParentStatement(context);
		IScope scope = IScope.NULLSCOPE;
		
		// Traverse the AST up to the containing program or function.
		while (container != null && !(container instanceof Program)
		                && !(container instanceof FunctionDeclaration)) {
		
			// On each level of the AST, find the preceding statements of the current one.
			current = container;
			container = (ASTNode) container.eContainer();
			
			ScopeFinder scopeFinder = new ScopeFinder(current);
			container.accept(scopeFinder);
			
			// Collect all variable descriptions from these statements
			List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
			
			for (VariableDeclaration vardec : scopeFinder.getVariableDeclarations()) {
				descriptions.add(EObjectDescription.create(vardec.getName(), vardec));
			}
			
			for (IEObjectDescription e : scope.getAllElements()) {
				System.out.println(e.getName());
			}
			
			// Create a new scope.
			scope = new SimpleScope(scope, descriptions);
			
			for (IEObjectDescription e : scope.getAllElements()) {
				System.out.println(e.getName());
			}
		}

		return scope;
	}

	/**
	 * Gets a list of the parameter descriptions of a {@link FunctionDeclaration}.
	 * 
	 * @param funcdec
	 *                The function declarations whose parameters to return.
	 * @return A list of the {@link IEObjectDescription}s of the given function's parameters.
	 */
	private Iterable<IEObjectDescription> getParameters(final FunctionDeclaration funcdec) {
		List<IEObjectDescription> result = new ArrayList<IEObjectDescription>();
		for (VariableDeclaration param : funcdec.getParameters()) {
			result.add(EObjectDescription.create(param.getName(), param));
		}
		return result;
	}

}

@@ -3754,287 +3754,79 @@
 %0A%09%09%09
-for (IEObjectDescription e : scope.getAllElements()) %7B%0A%09%09%09%09System.out.println(e.getName());%0A%09%09%09%7D%0A%09%09%09%0A%09%09%09// Create a new scope.%0A%09%09%09scope = new SimpleScope(scope, descriptions);%0A%09%09%09%0A%09%09%09for (IEObjectDescription e : scope.getAllElements()) %7B%0A%09%09%09%09System.out.println(e.getName());%0A%09%09%09%7D
+// Create a new scope.%0A%09%09%09scope = new SimpleScope(scope, descriptions);
 %0A%09%09%7D

Remove debug output in scoping provider