package org.testng.internal;


import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import org.testng.ITestMethodFinder;
import org.testng.ITestNGMethod;
import org.testng.annotations.IConfigurationAnnotation;
import org.testng.annotations.ITestAnnotation;
import org.testng.collections.Lists;
import org.testng.internal.annotations.AnnotationHelper;
import org.testng.internal.annotations.IAnnotationFinder;
import org.testng.xml.XmlTest;

/**
 * The default strategy for finding test methods:  look up
 * annotations @Test in front of methods.
 */
public class TestNGMethodFinder implements ITestMethodFinder {
  private static final int BEFORE_SUITE = 1;
  private static final int AFTER_SUITE = 2;
  private static final int BEFORE_TEST = 3;
  private static final int AFTER_TEST = 4;
  private static final int BEFORE_CLASS = 5;
  private static final int AFTER_CLASS = 6;
  private static final int BEFORE_TEST_METHOD = 7;
  private static final int AFTER_TEST_METHOD = 8;
  private static final int BEFORE_GROUPS = 9;
  private static final int AFTER_GROUPS = 10;

  private static final Comparator<ITestNGMethod> NO_COMPARISON = new Comparator<ITestNGMethod>() {
    @Override
    public int compare(ITestNGMethod o1, ITestNGMethod o2) {
      return 0;
    }
  };

  private RunInfo runInfo = null;
  private IAnnotationFinder annotationFinder = null;
  private final Comparator<ITestNGMethod> comparator;

  public TestNGMethodFinder(RunInfo runInfo, IAnnotationFinder annotationFinder) {
    this(runInfo, annotationFinder, NO_COMPARISON);
  }

  public TestNGMethodFinder(RunInfo runInfo, IAnnotationFinder annotationFinder,
      Comparator<ITestNGMethod> comparator) {
    this.runInfo = runInfo;
    this.annotationFinder = annotationFinder;
    this.comparator = comparator;
  }

  @Override
  public ITestNGMethod[] getTestMethods(Class<?> clazz, XmlTest xmlTest) {
    return AnnotationHelper.findMethodsWithAnnotation(clazz, ITestAnnotation.class, annotationFinder, xmlTest);
  }

  @Override
  public ITestNGMethod[] getBeforeClassMethods(Class cls) {
    return findConfiguration(cls, BEFORE_CLASS);
  }

  @Override
  public ITestNGMethod[] getAfterClassMethods(Class cls) {
    return findConfiguration(cls, AFTER_CLASS);
  }

  @Override
  public ITestNGMethod[] getBeforeTestMethods(Class cls) {
    return findConfiguration(cls, BEFORE_TEST_METHOD);
  }

  @Override
  public ITestNGMethod[] getAfterTestMethods(Class cls) {
    return findConfiguration(cls, AFTER_TEST_METHOD);
  }

  @Override
  public ITestNGMethod[] getBeforeSuiteMethods(Class cls) {
    return findConfiguration(cls, BEFORE_SUITE);
  }

  @Override
  public ITestNGMethod[] getAfterSuiteMethods(Class cls) {
    return findConfiguration(cls, AFTER_SUITE);
  }

  @Override
  public ITestNGMethod[] getBeforeTestConfigurationMethods(Class clazz) {
    return findConfiguration(clazz, BEFORE_TEST);
  }

  @Override
  public ITestNGMethod[] getAfterTestConfigurationMethods(Class clazz) {
    return findConfiguration(clazz, AFTER_TEST);
  }

  @Override
  public ITestNGMethod[] getBeforeGroupsConfigurationMethods(Class clazz) {
    return findConfiguration(clazz, BEFORE_GROUPS);
  }

  @Override
  public ITestNGMethod[] getAfterGroupsConfigurationMethods(Class clazz) {
    return findConfiguration(clazz, AFTER_GROUPS);
  }

  private ITestNGMethod[] findConfiguration(final Class clazz, final int configurationType) {
    List<ITestNGMethod> vResult = Lists.newArrayList();

    Set<Method> methods = ClassHelper.getAvailableMethods(clazz);

    for (Method m : methods) {
      IConfigurationAnnotation configuration = AnnotationHelper.findConfiguration(annotationFinder, m);

      if (null == configuration) {
        continue;
      }

      boolean create;
      boolean isBeforeSuite = false;
      boolean isAfterSuite = false;
      boolean isBeforeTest = false;
      boolean isAfterTest = false;
      boolean isBeforeClass = false;
      boolean isAfterClass = false;
      boolean isBeforeTestMethod = false;
      boolean isAfterTestMethod = false;
      String[] beforeGroups = null;
      String[] afterGroups = null;

      switch(configurationType) {
        case BEFORE_SUITE:
          create = configuration.getBeforeSuite();
          isBeforeSuite = true;
          break;
        case AFTER_SUITE:
          create = configuration.getAfterSuite();
          isAfterSuite = true;
          break;
        case BEFORE_TEST:
          create = configuration.getBeforeTest();
          isBeforeTest = true;
          break;
        case AFTER_TEST:
          create = configuration.getAfterTest();
          isAfterTest = true;
          break;
        case BEFORE_CLASS:
          create = configuration.getBeforeTestClass();
          isBeforeClass = true;
          break;
        case AFTER_CLASS:
          create = configuration.getAfterTestClass();
          isAfterClass = true;
          break;
        case BEFORE_TEST_METHOD:
          create = configuration.getBeforeTestMethod();
          isBeforeTestMethod = true;
          break;
        case AFTER_TEST_METHOD:
          create = configuration.getAfterTestMethod();
          isAfterTestMethod = true;
          break;
        case BEFORE_GROUPS:
          beforeGroups = configuration.getBeforeGroups();
          create = beforeGroups.length > 0;
          isBeforeTestMethod = true;
          break;
        case AFTER_GROUPS:
          afterGroups = configuration.getAfterGroups();
          create = afterGroups.length > 0;
          isBeforeTestMethod = true;
          break;
        default:
          throw new AssertionError("Unexpected value: " + configurationType);
      }

      if(create) {
        addConfigurationMethod(clazz,
                               vResult,
                               m,
                               isBeforeSuite,
                               isAfterSuite,
                               isBeforeTest,
                               isAfterTest,
                               isBeforeClass,
                               isAfterClass,
                               isBeforeTestMethod,
                               isAfterTestMethod,
                               beforeGroups,
                               afterGroups,
                               null); /* @@@ */
      }
    }

    List<ITestNGMethod> excludedMethods = Lists.newArrayList();
    boolean unique = configurationType == BEFORE_SUITE || configurationType == AFTER_SUITE;
    return MethodHelper.collectAndOrderMethods(Lists.newArrayList(vResult),
                                              false /* forTests */,
        runInfo,
        annotationFinder,
                                              unique,
                                              excludedMethods, comparator);

  }

  private void addConfigurationMethod(Class<?> clazz,
                                      List<ITestNGMethod> results,
                                      Method method,
                                      boolean isBeforeSuite,
                                      boolean isAfterSuite,
                                      boolean isBeforeTest,
                                      boolean isAfterTest,
                                      boolean isBeforeClass,
                                      boolean isAfterClass,
                                      boolean isBeforeTestMethod,
                                      boolean isAfterTestMethod,
                                      String[] beforeGroups,
                                      String[] afterGroups,
                                      Object instance)
  {
    if(method.getDeclaringClass().isAssignableFrom(clazz)) {
      ITestNGMethod confMethod = new ConfigurationMethod(new ConstructorOrMethod(method),
          annotationFinder,
                                                         isBeforeSuite,
                                                         isAfterSuite,
                                                         isBeforeTest,
                                                         isAfterTest,
                                                         isBeforeClass,
                                                         isAfterClass,
                                                         isBeforeTestMethod,
                                                         isAfterTestMethod,
                                                         beforeGroups,
                                                         afterGroups,
                                                         instance);
      results.add(confMethod);
    }
  }

}

@@ -23,16 +23,83 @@
 ernal;%0A%0A
+import static org.testng.internal.TestNGMethodFinder.MethodType.*;%0A
 %0Aimport 
@@ -734,444 +734,166 @@
 %7B%0A  
-private static final int BEFORE_SUITE = 1;%0A  private static final int AFTER_SUITE = 2;%0A  private static final int BEFORE_TEST = 3;%0A  private static final int AFTER_TEST = 4;%0A  private static final int BEFORE_CLASS = 5;%0A  private static final int AFTER_CLASS = 6;%0A  private static final int BEFORE_TEST_METHOD = 7;%0A  private static final int AFTER_TEST_METHOD = 8;%0A  private static final int BEFORE_GROUPS = 9;%0A  private static final int
+enum MethodType %7B%0A    BEFORE_SUITE, AFTER_SUITE, BEFORE_TEST, AFTER_TEST, BEFORE_CLASS, AFTER_CLASS,%0A    BEFORE_TEST_METHOD, AFTER_TEST_METHOD, BEFORE_GROUPS,
  AFT
@@ -905,14 +905,12 @@
 OUPS
- = 10;
+%0A  %7D
 %0A%0A  
@@ -3232,19 +3232,26 @@
 , final 
-int
+MethodType
  configu

Use enum instead of constants