package org.xtest.scoping;

import static java.util.Collections.singletonList;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtend.core.scoping.XtendImportedNamespaceScopeProvider;
import org.eclipse.xtend.core.xtend.XtendImport;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.ISelectable;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.Scopes;
import org.eclipse.xtext.scoping.impl.ImportNormalizer;
import org.eclipse.xtext.scoping.impl.MultimapBasedSelectable;
import org.eclipse.xtext.scoping.impl.ScopeBasedSelectable;
import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociations;
import org.eclipse.xtext.xbase.scoping.XbaseImportedNamespaceScopeProvider;
import org.xtest.xTest.Body;
import org.xtest.xTest.XMethodDef;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.inject.Inject;

/**
 * Change {@link XbaseImportedNamespaceScopeProvider} so that it does not process static imports.
 * Static imports are processed in {@link XtestStaticMethodsFeatureForTypeProvider}.
 * 
 * @author Michael Barry
 */
@SuppressWarnings("restriction")
public class XtestImportedNamespaceScopeProvider extends XtendImportedNamespaceScopeProvider {

    @Inject
    private IJvmModelAssociations associations;

    @Override
    protected IScope getLocalElementsScope(IScope parent, final EObject context,
            final EReference reference) {
        IScope result = parent;
        ISelectable allDescriptions = getAllDescriptions(context.eResource());
        ScopeBasedSelectable parentSelectable = new ScopeBasedSelectable(parent);
        QualifiedName name = getQualifiedNameOfLocalElement(context);
        boolean ignoreCase = isIgnoreCase(reference);
        if (context instanceof Body) {
            // explicitly add java.lang imports with correct import-selectable
            List<ImportNormalizer> javaLangImport = getDefaultImports();
            result = createImportScope(result, javaLangImport, parentSelectable,
                    reference.getEReferenceType(), isIgnoreCase(reference));
        }
        final List<ImportNormalizer> namespaceResolvers = getImportedNamespaceResolvers(context,
                ignoreCase);
        if (!namespaceResolvers.isEmpty()) {
            if (isRelativeImport() && name != null) {
                ImportNormalizer localNormalizer = doCreateImportNormalizer(name, true, ignoreCase);
                result = createImportScope(result, singletonList(localNormalizer), allDescriptions,
                        reference.getEReferenceType(), isIgnoreCase(reference));
            }
            result = createImportScope(result, namespaceResolvers, parentSelectable,
                    reference.getEReferenceType(), isIgnoreCase(reference));
        }
        if (name != null) {
            ImportNormalizer localNormalizer = doCreateImportNormalizer(name, true, ignoreCase);
            result = createImportScope(result, singletonList(localNormalizer), allDescriptions,
                    reference.getEReferenceType(), isIgnoreCase(reference));
        }

        return result;
    }

    @Override
    protected ISelectable internalGetAllDescriptions(final Resource resource) {
        // Filter out meythod type parameter declarations from global scope
        Iterable<EObject> allContents = Iterables.filter(new Iterable<EObject>() {
            @Override
            public Iterator<EObject> iterator() {
                return EcoreUtil.getAllContents(resource, false);
            }
        }, new Predicate<EObject>() {
            @Override
            public boolean apply(EObject input) {
                return input.eContainer() == null || !(input.eContainer() instanceof XMethodDef)
                        && associations.getPrimarySourceElement(input) == null;
            }
        });
        Iterable<IEObjectDescription> allDescriptions = Scopes.scopedElementsFor(allContents,
                getQualifiedNameProvider());
        return new MultimapBasedSelectable(allDescriptions);
    }

    @Override
    protected List<ImportNormalizer> internalGetImportedNamespaceResolvers(final EObject context,
            boolean ignoreCase) {
        if (!(context instanceof Body)) {
            return Collections.emptyList();
        }
        Body file = (Body) context;
        List<ImportNormalizer> importedNamespaceResolvers = Lists.newArrayList();
        for (XtendImport imp : file.getImports()) {
            if (!imp.isStatic()) {
                String value = imp.getImportedNamespace();
                if (value == null) {
                    value = imp.getImportedTypeName();
                }
                ImportNormalizer resolver = createImportedNamespaceResolver(value, ignoreCase);
                if (resolver != null) {
                    importedNamespaceResolvers.add(resolver);
                }
            }
        }
        return importedNamespaceResolvers;
    }
}

@@ -112,36 +112,8 @@
 s;%0D%0A
-import java.util.Iterator;%0D%0A
 impo
@@ -219,103 +219,8 @@
 e;%0D%0A
-import org.eclipse.emf.ecore.resource.Resource;%0D%0Aimport org.eclipse.emf.ecore.util.EcoreUtil;%0D%0A
 impo
@@ -568,22 +568,35 @@
 scoping.
+impl.Filtering
 Scope
-s
 ;%0D%0Aimpor
@@ -651,72 +651,8 @@
 r;%0D%0A
-import org.eclipse.xtext.scoping.impl.MultimapBasedSelectable;%0D%0A
 impo
@@ -963,53 +963,8 @@
 e;%0D%0A
-import com.google.common.collect.Iterables;%0D%0A
 impo
@@ -2075,30 +2075,30 @@
 alizer%3E 
-javaLang
+default
 Import
+s
  = getDe
@@ -2165,22 +2165,22 @@
 lt, 
-javaLang
+default
 Import
+s
 , pa
@@ -3298,26 +3298,24 @@
 %0A        %7D%0D%0A
-%0D%0A
         retu
@@ -3321,420 +3321,226 @@
 urn 
-result;%0D%0A    %7D%0D%0A%0D%0A    @Override%0D%0A    protected ISelectable internalGetAllDescriptions(final Resource resource) %7B%0D%0A        // Filter out meythod type parameter declarations from global scope%0D%0A        Iterable%3CEObject%3E allContents = Iterables.filter(new Iterable%3CEObject%3E() %7B%0D%0A            @Override%0D%0A            public Iterator%3CEObject%3E iterator() %7B%0D%0A                return EcoreUtil.getAllContents(resource, false
+new FilteringScope(result, new Predicate%3CIEObjectDescription%3E() %7B%0D%0A            @Override%0D%0A            public boolean apply(IEObjectDescription input) %7B%0D%0A                EObject eObjectOrProxy = input.getEObjectOrProxy(
 );%0D%0A
@@ -3555,48 +3555,54 @@
     
-%7D%0D%0A
     
-    %7D, new Predicate%3CEObject%3E() %7B
+return eObjectOrProxy.eContainer() == null
 %0D%0A  
@@ -3607,35 +3607,24 @@
             
-@Override%0D%0A
             
@@ -3627,107 +3627,27 @@
     
-public boolean apply(EObject input) %7B%0D%0A                return input.eContainer() == null %7C%7C !(input
+%7C%7C !(eObjectOrProxy
 .eCo
@@ -3748,252 +3748,58 @@
 ent(
-input) == null;%0D%0A            %7D%0D%0A        %7D);%0D%0A        Iterable%3CIEObjectDescription%3E allDescriptions = Scopes.scopedElementsFor(allContents,%0D%0A                getQualifiedNameProvider());%0D%0A        return new MultimapBasedSelectable(allDescriptions
+eObjectOrProxy) == null;%0D%0A            %7D%0D%0A        %7D
 );%0D%0A

Fix type parameters visible outside method