package org.jetbrains.android.dom.converters;

import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.ResolveCache;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet;
import com.intellij.util.xml.ConvertContext;
import com.intellij.util.xml.Converter;
import com.intellij.util.xml.CustomReferenceConverter;
import com.intellij.util.xml.GenericDomValue;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

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

/**
 * @author Eugene.Kudelevsky
 */
public class OnClickConverter extends Converter<String> implements CustomReferenceConverter<String> {
  @NotNull
  @Override
  public PsiReference[] createReferences(GenericDomValue<String> value, PsiElement element, ConvertContext context) {
    final int length = element.getTextLength();
    if (length > 1) {
      return new PsiReference[]{new MyReference((XmlAttributeValue)element, new TextRange(1, length - 1))};
    }
    return PsiReference.EMPTY_ARRAY;
  }

  @Override
  public String fromString(@Nullable @NonNls String s, ConvertContext context) {
    return s;
  }

  @Override
  public String toString(@Nullable String s, ConvertContext context) {
    return s;
  }

  private static class MyReference extends PsiPolyVariantReferenceBase<XmlAttributeValue> {

    public MyReference(XmlAttributeValue value, TextRange range) {
      super(value, range, true);
    }

    @NotNull
    @Override
    public ResolveResult[] multiResolve(boolean incompleteCode) {
      return ResolveCache.getInstance(myElement.getProject())
        .resolveWithCaching(this, new ResolveCache.PolyVariantResolver<MyReference>() {
          @NotNull
          @Override
          public ResolveResult[] resolve(@NotNull MyReference myReference, boolean incompleteCode) {
            return resolveInner();
          }
        }, false, incompleteCode);
    }

    @NotNull
    private ResolveResult[] resolveInner() {
      final String methodName = myElement.getValue();
      if (methodName == null) {
        return ResolveResult.EMPTY_ARRAY;
      }

      final Project project = myElement.getProject();
      final PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);

      final PsiMethod[] methods = cache.getMethodsByName(methodName, GlobalSearchScope.projectScope(project));
      if (methods.length == 0) {
        return ResolveResult.EMPTY_ARRAY;
      }

      final List<ResolveResult> result = new ArrayList<ResolveResult>();
      for (PsiMethod method : methods) {
        if (checkSignature(method)) {
          result.add(new PsiElementResolveResult(method));
        }
      }
      return result.toArray(new ResolveResult[result.size()]);
    }

    private static boolean checkSignature(PsiMethod method) {
      if (method.getReturnType() != PsiType.VOID) {
        return false;
      }

      if (method.hasModifierProperty(PsiModifier.STATIC) ||
          method.hasModifierProperty(PsiModifier.ABSTRACT) ||
          !method.hasModifierProperty(PsiModifier.PUBLIC)) {
        return false;
      }

      final PsiClass aClass = method.getContainingClass();
      if (aClass == null || aClass.isInterface()) {
        return false;
      }

      final PsiParameter[] parameters = method.getParameterList().getParameters();
      if (parameters.length != 1) {
        return false;
      }

      final PsiType paramType = parameters[0].getType();
      if (!(paramType instanceof PsiClassType)) {
        return false;
      }

      final PsiClass paramClass = ((PsiClassType)paramType).resolve();
      return paramClass != null && AndroidUtils.VIEW_CLASS_NAME.equals(paramClass.getQualifiedName());
    }

    @NotNull
    @Override
    public Object[] getVariants() {
      final Project project = myElement.getProject();
      final GlobalSearchScope scope = ProjectScope.getAllScope(project);

      final PsiClass activityClass = JavaPsiFacade.getInstance(project).findClass(AndroidUtils.ACTIVITY_BASE_CLASS_NAME, scope);
      if (activityClass == null) {
        return EMPTY_ARRAY;
      }

      final List<Object> result = new ArrayList<Object>();
      final Set<String> methodNames = new HashSet<String>();

      ClassInheritorsSearch.search(activityClass, scope, true).forEach(new Processor<PsiClass>() {
        public boolean process(PsiClass c) {
          for (PsiMethod method : c.getMethods()) {
            if (checkSignature(method) && methodNames.add(method.getName())) {
              result.add(createLookupElement(method));
            }
          }
          return true;
        }
      });
      return ArrayUtil.toObjectArray(result);
    }
  }

  private static LookupElement createLookupElement(PsiMethod method) {
    final LookupElementBuilder builder = LookupElementBuilder.create(method, method.getName())
      .withIcon(method.getIcon(Iconable.ICON_FLAG_VISIBILITY))
      .withPresentableText(method.getName());
    final PsiClass containingClass = method.getContainingClass();
    return containingClass != null
           ? builder.withTailText(" (" + containingClass.getQualifiedName() + ')')
           : builder;
  }
}

@@ -151,24 +151,118 @@
 entBuilder;%0A
+import com.intellij.openapi.module.Module;%0Aimport com.intellij.openapi.module.ModuleUtilCore;%0A
 import com.i
@@ -470,103 +470,8 @@
 he;%0A
-import com.intellij.psi.search.GlobalSearchScope;%0Aimport com.intellij.psi.search.ProjectScope;%0A
 impo
@@ -2757,32 +2757,189 @@
 _ARRAY;%0A      %7D%0A
+      final Module module = ModuleUtilCore.findModuleForPsiElement(myElement);%0A%0A      if (module == null) %7B%0A        return ResolveResult.EMPTY_ARRAY;%0A      %7D
 %0A      final Pro
@@ -3131,46 +3131,46 @@
 me, 
-GlobalSearchScope.projectScope(project
+module.getModuleWithDependenciesScope(
 ));%0A
@@ -4655,69 +4655,153 @@
 nal 
-GlobalSearchScope scope = ProjectScope.getAllScope(project);%0A
+Module module = ModuleUtilCore.findModuleForPsiElement(myElement);%0A%0A      if (module == null) %7B%0A        return ResolveResult.EMPTY_ARRAY;%0A      %7D
 %0A   
@@ -4868,16 +4868,25 @@
 project)
+%0A        
 .findCla
@@ -4927,21 +4927,72 @@
 S_NAME, 
-scope
+module.getModuleWithDependenciesAndLibrariesScope(false)
 );%0A     
@@ -5233,13 +5233,47 @@
 ss, 
-s
+module.getModuleWithDependenciesS
 cope
+()
 , tr

fix scope