/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.intellij.execution.junit;

import com.intellij.compiler.CompilerConfiguration;
import com.intellij.execution.configurations.ConfigurationUtil;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.ide.util.ClassFilter;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilBase;
import org.jetbrains.annotations.NotNull;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class TestClassFilter implements ClassFilter.ClassFilterWithScope {
  private final PsiClass myBase;
  private final Project myProject;
  private final GlobalSearchScope myScope;

  private TestClassFilter(@NotNull PsiClass base, final GlobalSearchScope scope) {
    myBase = base;
    myProject = base.getProject();
    myScope = scope;
  }

  public PsiManager getPsiManager() { return PsiManager.getInstance(myProject); }

  public Project getProject() { return myProject; }

  public boolean isAccepted(final PsiClass aClass) {
    return ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(aClass) &&
           (aClass.isInheritor(myBase, true) || JUnitUtil.isTestClass(aClass))
           && !CompilerConfiguration.getInstance(getProject()).isExcludedFromCompilation(PsiUtilBase.getVirtualFile(aClass))
      ;
  }

  public TestClassFilter intersectionWith(final GlobalSearchScope scope) {
    return new TestClassFilter(myBase, myScope.intersectWith(scope));
  }

  public static TestClassFilter create(final SourceScope sourceScope, Module module) throws JUnitUtil.NoJUnitException {
    if (sourceScope == null) throw new JUnitUtil.NoJUnitException();
    PsiClass testCase = module == null ? JUnitUtil.getTestCaseClass(sourceScope) : JUnitUtil.getTestCaseClass(module);
    return new TestClassFilter(testCase, sourceScope.getGlobalSearchScope());
  }

  public static TestClassFilter create(final SourceScope sourceScope, Module module, final String pattern) throws JUnitUtil.NoJUnitException {
    if (sourceScope == null) throw new JUnitUtil.NoJUnitException();
    PsiClass testCase = module == null ? JUnitUtil.getTestCaseClass(sourceScope) : JUnitUtil.getTestCaseClass(module);
    final Pattern compilePattern = getCompilePattern(pattern);
    return new TestClassFilter(testCase, sourceScope.getGlobalSearchScope()){

      @Override
      public boolean isAccepted(PsiClass aClass) {
        return super.isAccepted(aClass) && compilePattern != null && compilePattern.matcher(aClass.getQualifiedName()).matches();
      }
    };
  }

  private static Pattern getCompilePattern(String pattern) {
    Pattern compilePattern;
    try {
      compilePattern = Pattern.compile(pattern);
    }
    catch (PatternSyntaxException e) {
      compilePattern = null;
    }
    return compilePattern;
  }

  public GlobalSearchScope getScope() { return myScope; }
  public PsiClass getBase() { return myBase; }
}

@@ -1142,16 +1142,67 @@
 tNull;%0A%0A
+import java.util.ArrayList;%0Aimport java.util.List;%0A
 import j
@@ -2990,60 +2990,306 @@
 nal 
-Pattern compilePattern = getCompilePattern(pattern);
+String%5B%5D patterns = pattern.split(%22%5C%5C%7C%5C%5C%7C%22);%0A    final List%3CPattern%3E compilePatterns = new ArrayList%3CPattern%3E();%0A    for (String p : patterns) %7B%0A      final Pattern compilePattern = getCompilePattern(p);%0A      if (compilePattern != null) %7B%0A        compilePatterns.add(compilePattern);%0A      %7D%0A    %7D
 %0A   
@@ -3363,17 +3363,16 @@
 ope())%7B%0A
-%0A
       @O
@@ -3438,23 +3438,20 @@
         
-return 
+if (
 super.is
@@ -3470,38 +3470,153 @@
 ass)
- && compilePattern != null && 
+) %7B%0A          final String qualifiedName = aClass.getQualifiedName();%0A          for (Pattern compilePattern : compilePatterns) %7B%0A            if (
 comp
@@ -3634,27 +3634,17 @@
 matcher(
-aClass.getQ
+q
 ualified
@@ -3647,18 +3647,16 @@
 fiedName
-()
 ).matche
@@ -3658,16 +3658,103 @@
 atches()
+) %7B%0A              return true;%0A            %7D%0A          %7D%0A        %7D%0A        return false
 ;%0A      
@@ -3866,16 +3866,16 @@
   try %7B%0A
-
       co
@@ -3908,24 +3908,31 @@
 pile(pattern
+.trim()
 );%0A    %7D%0A   

test pattern: accept search by multiple patterns separated by ||