/*
 * generated by Xtext
 */
package com.rockwellcollins.atc.resolute.scoping;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.Scopes;
import org.osate.aadl2.AadlPackage;
import org.osate.aadl2.AnnexLibrary;
import org.osate.aadl2.Classifier;
import org.osate.aadl2.ComponentClassifier;
import org.osate.aadl2.ComponentImplementation;
import org.osate.aadl2.Element;
import org.osate.aadl2.Subcomponent;
import org.osate.aadl2.ThreadSubcomponent;
import org.osate.aadl2.impl.DataPortImpl;
import org.osate.aadl2.impl.FeatureGroupImpl;
import org.osate.xtext.aadl2.properties.scoping.PropertiesScopeProvider;

import com.rockwellcollins.atc.resolute.resolute.FilterMapExpr;
import com.rockwellcollins.atc.resolute.resolute.FunctionDefinition;
import com.rockwellcollins.atc.resolute.resolute.NestedDotID;
import com.rockwellcollins.atc.resolute.resolute.ProveStatement;
import com.rockwellcollins.atc.resolute.resolute.QuantifiedExpr;
import com.rockwellcollins.atc.resolute.resolute.ResoluteSubclause;

/**
 * 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 ResoluteScopeProvider extends PropertiesScopeProvider {
    IScope scope_NamedElement(QuantifiedExpr ctx, EReference ref) {
        return Scopes.scopeFor(ctx.getArgs(), getScope(ctx.eContainer(), ref));
    }

    IScope scope_NamedElement(FunctionDefinition ctx, EReference ref) {
        return Scopes.scopeFor(ctx.getArgs(), getScope(ctx.eContainer(), ref));
    }

    IScope scope_NamedElement(FilterMapExpr ctx, EReference ref) {
        return Scopes.scopeFor(ctx.getArgs(), getScope(ctx.eContainer(), ref));
    }
    
    
    IScope scope_NamedElement(ProveStatement ctx, EReference ref) {
        EObject container = ctx.eContainer();
        assert(container instanceof ResoluteSubclause);
        container = container.eContainer();
        if(container instanceof ComponentImplementation){
            ComponentImplementation compImpl = (ComponentImplementation)container;
            return Scopes.scopeFor(compImpl.getAllModes(),  getScope(ctx.eContainer(), ref));
        }
        return getScope(ctx.eContainer(), ref);
    }
    
    
    IScope scope_NamedElement(NestedDotID ctx, EReference ref) {
        Set<Element> components = getCorrespondingAadlElement(ctx);
        return Scopes.scopeFor(components, getScope(ctx.eContainer(), ref));
    }

    
    private Set<Element> getCorrespondingAadlElement(NestedDotID id) {
        EObject container = id.eContainer();

        if (container instanceof NestedDotID) {
            NestedDotID parent = (NestedDotID) container;
            EList<EObject> refs = parent.eCrossReferences();

            if (refs.size() != 1) {
                return new HashSet<>(); // this will throw a parsing error
            }
            container = refs.get(0);

            if (container instanceof Subcomponent) {
                if(container instanceof ThreadSubcomponent){
                    container = ((ThreadSubcomponent)container).getThreadSubcomponentType();
                }else{
                    container = ((Subcomponent) container).getComponentImplementation();
                }
            } else {
                return new HashSet<>(); // this will throw a parsing error
            }
            
        } else {
            // travel out of the annex and get the component
            // classifier that the annex is contained in.
            while (!(container instanceof ComponentClassifier)) {
                container = container.eContainer();
            }
        }

        if (container == null) {
            return new HashSet<>(); // this will throw a parsing error
        }

        Set<Element> result = new HashSet<>();

        if (container instanceof ComponentClassifier) {
            ComponentClassifier compImpl = (ComponentClassifier) container;
            result.addAll(compImpl.getAllModes());
            if(compImpl instanceof ComponentImplementation){
                result.addAll(((ComponentImplementation)compImpl).getAllSubcomponents());
            }
          
        } else {
            assert(false);
        }


        return result;
    }
    
    
}
@@ -99,16 +99,39 @@
 ashSet;%0A
+import java.util.List;%0A
 import j
@@ -144,16 +144,16 @@
 il.Set;%0A
-
 %0Aimport 
@@ -822,16 +822,70 @@
 vider;%0A%0A
+import com.rockwellcollins.atc.resolute.resolute.Arg;%0A
 import c
@@ -1732,32 +1732,32 @@
 eference ref) %7B%0A
-
         return S
@@ -1817,32 +1817,474 @@
 (), ref));%0A    %7D
+%0A    %0A    IScope scope_NamedElement(Arg ctx, EReference ref) %7B%0A        if (ctx.eContainer() instanceof FilterMapExpr) %7B%0A            FilterMapExpr parent = (FilterMapExpr) ctx.eContainer();%0A            List%3CArg%3E visibleArgs = parent.getArgs().subList(0, parent.getArgs().indexOf(ctx));%0A            return Scopes.scopeFor(visibleArgs, getScope(parent.eContainer(), ref));%0A        %7D%0A        %0A        return getScope(ctx.eContainer(), ref);%0A    %7D
 %0A%0A    IScope sco

Fix scoping for multiple arguments in filter-map expressions