package org.testng;

import com.google.inject.Injector;
import com.google.inject.Module;

import org.testng.collections.ListMultiMap;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.internal.Attributes;
import org.testng.internal.ClassHelper;
import org.testng.internal.ClassInfoMap;
import org.testng.internal.ConfigurationGroupMethods;
import org.testng.internal.Constants;
import org.testng.internal.DynamicGraph;
import org.testng.internal.DynamicGraph.Status;
import org.testng.internal.IConfiguration;
import org.testng.internal.IInvoker;
import org.testng.internal.ITestResultNotifier;
import org.testng.internal.InvokedMethod;
import org.testng.internal.Invoker;
import org.testng.internal.MethodGroupsHelper;
import org.testng.internal.MethodHelper;
import org.testng.internal.MethodInstance;
import org.testng.internal.ResultMap;
import org.testng.internal.RunInfo;
import org.testng.internal.TestMethodWorker;
import org.testng.internal.TestNGClassFinder;
import org.testng.internal.TestNGMethodFinder;
import org.testng.internal.Utils;
import org.testng.internal.XmlMethodSelector;
import org.testng.internal.annotations.IAnnotationFinder;
import org.testng.internal.annotations.IListeners;
import org.testng.internal.annotations.Sets;
import org.testng.internal.thread.ThreadUtil;
import org.testng.internal.thread.graph.GraphThreadPoolExecutor;
import org.testng.internal.thread.graph.IThreadWorkerFactory;
import org.testng.internal.thread.graph.IWorker;
import org.testng.junit.IJUnitTestRunner;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlPackage;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * This class takes care of running one Test.
 *
 * @author Cedric Beust, Apr 26, 2004
 */
public class TestRunner
    implements ITestContext, ITestResultNotifier, IThreadWorkerFactory<ITestNGMethod>
{
  /* generated */
  private static final long serialVersionUID = 4247820024988306670L;
  private ISuite m_suite;
  private XmlTest m_xmlTest;
  private String m_testName;

  transient private List<XmlClass> m_testClassesFromXml= null;
  transient private List<XmlPackage> m_packageNamesFromXml= null;

  transient private IInvoker m_invoker= null;
  transient private IAnnotationFinder m_annotationFinder= null;

  /** ITestListeners support. */
  transient private List<ITestListener> m_testListeners = Lists.newArrayList();
  transient private List<IConfigurationListener> m_configurationListeners = Lists.newArrayList();

  transient private IConfigurationListener m_confListener= new ConfigurationListener();
  transient private boolean m_skipFailedInvocationCounts;

  /**
   * All the test methods we found, associated with their respective classes.
   * Note that these test methods might belong to different classes.
   * We pick which ones to run at runtime.
   */
  private ITestNGMethod[] m_allTestMethods = new ITestNGMethod[0];

  // Information about this test run

  private Date m_startDate = null;
  private Date m_endDate = null;

  /** A map to keep track of Class <-> IClass. */
  transient private Map<Class<?>, ITestClass> m_classMap = Maps.newHashMap();

  /** Where the reports will be created. */
  private String m_outputDirectory= Constants.getDefaultValueFor(Constants.PROP_OUTPUT_DIR);

  // The XML method selector (groups/methods included/excluded in XML)
  private XmlMethodSelector m_xmlMethodSelector = new XmlMethodSelector();

  private static int m_verbose = 1;

  //
  // These next fields contain all the configuration methods found on this class.
  // At initialization time, they just contain all the various @Configuration methods
  // found in all the classes we are going to run.  When comes the time to run them,
  // only a subset of them are run:  those that are enabled and belong on the same class as
  // (or a parent of) the test class.
  //
  /** */
  private ITestNGMethod[] m_beforeSuiteMethods = {};
  private ITestNGMethod[] m_afterSuiteMethods = {};
  private ITestNGMethod[] m_beforeXmlTestMethods = {};
  private ITestNGMethod[] m_afterXmlTestMethods = {};
  private List<ITestNGMethod> m_excludedMethods = Lists.newArrayList();
  private ConfigurationGroupMethods m_groupMethods = null;

  // Meta groups
  private Map<String, List<String>> m_metaGroups = Maps.newHashMap();

  // All the tests that were run along with their result
  private IResultMap m_passedTests = new ResultMap();
  private IResultMap m_failedTests = new ResultMap();
  private IResultMap m_failedButWithinSuccessPercentageTests = new ResultMap();
  private IResultMap m_skippedTests = new ResultMap();

  private RunInfo m_runInfo= new RunInfo();

  // The host where this test was run, or null if run locally
  private String m_host;

  // Defined dynamically depending on <test preserve-order="true/false">
  private transient IMethodInterceptor m_methodInterceptor;

  private transient ClassMethodMap m_classMethodMap;
  private transient TestNGClassFinder m_testClassFinder;
  private transient IConfiguration m_configuration;

  protected TestRunner(IConfiguration configuration,
                    ISuite suite,
                    XmlTest test,
                    String outputDirectory,
                    IAnnotationFinder finder,
                    boolean skipFailedInvocationCounts,
                    List<IInvokedMethodListener> invokedMethodListeners)
  {
    init(configuration, suite, test, outputDirectory, finder, skipFailedInvocationCounts,
        invokedMethodListeners);
  }

  public TestRunner(IConfiguration configuration, ISuite suite, XmlTest test,
      boolean skipFailedInvocationCounts,
      List<IInvokedMethodListener> listeners) {
    init(configuration, suite, test, suite.getOutputDirectory(),
        suite.getAnnotationFinder(test.getAnnotations()),
        skipFailedInvocationCounts, listeners);
  }

  private void init(IConfiguration configuration,
                    ISuite suite,
                    XmlTest test,
                    String outputDirectory,
                    IAnnotationFinder annotationFinder,
                    boolean skipFailedInvocationCounts,
                    List<IInvokedMethodListener> invokedMethodListeners)
  {
    m_configuration = configuration;
    m_xmlTest= test;
    m_suite = suite;
    m_testName = test.getName();
    m_host = suite.getHost();
    m_testClassesFromXml= test.getXmlClasses();
    m_skipFailedInvocationCounts = skipFailedInvocationCounts;
    setVerbose(test.getVerbose());

    boolean preserveOrder = "true".equalsIgnoreCase(test.getPreserveOrder());
    m_methodInterceptor = preserveOrder ? new PreserveOrderMethodInterceptor()
        : new InstanceOrderingMethodInterceptor();

    m_packageNamesFromXml= test.getXmlPackages();
    if(null != m_packageNamesFromXml) {
      for(XmlPackage xp: m_packageNamesFromXml) {
        m_testClassesFromXml.addAll(xp.getXmlClasses());
      }
    }

    m_annotationFinder= annotationFinder;
    m_invoker = new Invoker(m_configuration, this, this, m_suite.getSuiteState(),
        m_skipFailedInvocationCounts, invokedMethodListeners);

    if (suite.getParallel() != null) {
      log(3, "Running the tests in '" + test.getName() + "' with parallel mode:" + suite.getParallel());
    }

    setOutputDirectory(outputDirectory);

    // Finish our initialization
    init();
  }

  public IInvoker getInvoker() {
    return m_invoker;
  }

  public ITestNGMethod[] getBeforeSuiteMethods() {
    return m_beforeSuiteMethods;
  }

  public ITestNGMethod[] getAfterSuiteMethods() {
    return m_afterSuiteMethods;
  }

  public ITestNGMethod[] getBeforeTestConfigurationMethods() {
    return m_beforeXmlTestMethods;
  }

  public ITestNGMethod[] getAfterTestConfigurationMethods() {
    return m_afterXmlTestMethods;
  }

  private void init() {
    initMetaGroups(m_xmlTest);
    initRunInfo(m_xmlTest);

    // Init methods and class map
    // JUnit behavior is different and doesn't need this initialization step
    if(!m_xmlTest.isJUnit()) {
      initMethods();
    }

    initListeners();
    addConfigurationListener(m_confListener);
  }

  private class ListenerHolder {
    private List<Class<? extends ITestNGListener>> listenerClasses;
    private Class<? extends ITestNGListenerFactory> listenerFactoryClass;
  }

  /**
   * @return all the @Listeners annotations found in the current class and its
   * superclasses.
   */
  private ListenerHolder findAllListeners(Class<?> cls) {
    ListenerHolder result = new ListenerHolder();
    result.listenerClasses = Lists.newArrayList();

    do {
      IListeners l = (IListeners) m_annotationFinder.findAnnotation(cls, IListeners.class);
      if (l != null) {
        Class<? extends ITestNGListener>[] classes = l.getValue();
        for (Class<? extends ITestNGListener> c : classes) {
          result.listenerClasses.add(c);

          if (ITestNGListenerFactory.class.isAssignableFrom(c)) {
            if (result.listenerFactoryClass == null) {
              result.listenerFactoryClass = (Class<? extends ITestNGListenerFactory>) c;
            }
            else {
              throw new TestNGException("Found more than one class implementing" +
                  "ITestNGListenerFactory:" + c + " and " + result.listenerFactoryClass);
            }
          }
        }
      }
      cls = cls.getSuperclass();
    } while (cls != Object.class);

    return result;
  }

  private void initListeners() {
    //
    // Find all the listener factories and collect all the listeners requested in a
    // @Listeners annotation.
    //
    Set<Class<? extends ITestNGListener>> listenerClasses = Sets.newHashSet();
    Class<? extends ITestNGListenerFactory> listenerFactoryClass = null;

    for (IClass cls : getTestClasses()) {
      Class<? extends ITestNGListenerFactory> realClass = cls.getRealClass();
      ListenerHolder listenerHolder = findAllListeners(realClass);
      if (listenerFactoryClass == null) {
        listenerFactoryClass = listenerHolder.listenerFactoryClass;
      }
      listenerClasses.addAll(listenerHolder.listenerClasses);
    }

    //
    // Now we have all the listeners collected from @Listeners and at most one
    // listener factory collected from a class implementing ITestNGListenerFactory.
    // Instantiate all the requested listeners.
    //
    ITestNGListenerFactory listenerFactory = null;

    // If we found a test listener factory, instantiate it.
    try {
      if (m_testClassFinder != null) {
        IClass ic = m_testClassFinder.getIClass(listenerFactoryClass);
        if (ic != null) {
          listenerFactory = (ITestNGListenerFactory) ic.getInstances(false)[0];
        }
      }
      if (listenerFactory == null) {
        listenerFactory = listenerFactoryClass != null ? listenerFactoryClass.newInstance() : null;
      }
    }
    catch(Exception ex) {
      throw new TestNGException("Couldn't instantiate the ITestNGListenerFactory: "
          + ex);
    }

    // Instantiate all the listeners
    for (Class<? extends ITestNGListener> c : listenerClasses) {
      Object listener = listenerFactory != null ? listenerFactory.createListener(c) : null;
      if (listener == null) {
        listener = ClassHelper.newInstance(c);
      }

      if (listener instanceof IMethodInterceptor) {
        setMethodInterceptor((IMethodInterceptor) listener);
      }
      if (listener instanceof ISuiteListener) {
        m_suite.addListener((ISuiteListener) listener);
      }
      if (listener instanceof IInvokedMethodListener) {
        m_suite.addListener((ITestNGListener) listener);
      }
      if (listener instanceof ITestListener) {
        // At this point, the field m_testListeners has already been used in the creation
        addTestListener((ITestListener) listener);
      }
      if (listener instanceof IConfigurationListener) {
        addConfigurationListener((IConfigurationListener) listener);
      }
      if (listener instanceof IReporter) {
        m_suite.addListener((ITestNGListener) listener);
      }
      if (listener instanceof IConfigurable) {
        m_configuration.setConfigurable((IConfigurable) listener);
      }
      if (listener instanceof IHookable) {
        m_configuration.setHookable((IHookable) listener);
      }
      if (listener instanceof IExecutionListener) {
        IExecutionListener iel = (IExecutionListener) listener;
        iel.onExecutionStart();
        m_configuration.addExecutionListener(iel);
      }
    }
  }

  /**
   * Initialize meta groups
   */
  private void initMetaGroups(XmlTest xmlTest) {
    Map<String, List<String>> metaGroups = xmlTest.getMetaGroups();

    for (Map.Entry<String, List<String>> entry : metaGroups.entrySet()) {
      addMetaGroup(entry.getKey(), entry.getValue());
    }
  }

  private void initRunInfo(final XmlTest xmlTest) {
    // Groups
    m_xmlMethodSelector.setIncludedGroups(createGroups(m_xmlTest.getIncludedGroups()));
    m_xmlMethodSelector.setExcludedGroups(createGroups(m_xmlTest.getExcludedGroups()));
    m_xmlMethodSelector.setExpression(m_xmlTest.getExpression());

    // Methods
    m_xmlMethodSelector.setXmlClasses(m_xmlTest.getXmlClasses());

    m_runInfo.addMethodSelector(m_xmlMethodSelector, 10);

    // Add user-specified method selectors (only class selectors, we can ignore
    // script selectors here)
    if (null != xmlTest.getMethodSelectors()) {
      for (org.testng.xml.XmlMethodSelector selector : xmlTest.getMethodSelectors()) {
        if (selector.getClassName() != null) {
          IMethodSelector s = ClassHelper.createSelector(selector);

          m_runInfo.addMethodSelector(s, selector.getPriority());
        }
      }
    }
  }

  private void initMethods() {

    //
    // Calculate all the methods we need to invoke
    //
    List<ITestNGMethod> beforeClassMethods = Lists.newArrayList();
    List<ITestNGMethod> testMethods = Lists.newArrayList();
    List<ITestNGMethod> afterClassMethods = Lists.newArrayList();
    List<ITestNGMethod> beforeSuiteMethods = Lists.newArrayList();
    List<ITestNGMethod> afterSuiteMethods = Lists.newArrayList();
    List<ITestNGMethod> beforeXmlTestMethods = Lists.newArrayList();
    List<ITestNGMethod> afterXmlTestMethods = Lists.newArrayList();

    ClassInfoMap classMap = new ClassInfoMap(m_testClassesFromXml);
    m_testClassFinder= new TestNGClassFinder(classMap,
                                             null,
                                             m_xmlTest,
                                             m_configuration,
                                             this);
    ITestMethodFinder testMethodFinder
      = new TestNGMethodFinder<ITestNGMethod>(m_runInfo, m_annotationFinder);

    m_runInfo.setTestMethods(testMethods);

    //
    // Initialize TestClasses
    //
    IClass[] classes = m_testClassFinder.findTestClasses();

    for (IClass ic : classes) {

      // Create TestClass
      ITestClass tc = new TestClass(ic,
                                   testMethodFinder,
                                   m_annotationFinder,
                                   m_runInfo,
                                   m_xmlTest,
                                   classMap.getXmlClass(ic.getRealClass()));
      m_classMap.put(ic.getRealClass(), tc);
    }

    //
    // Calculate groups methods
    //
    Map<String, List<ITestNGMethod>> beforeGroupMethods =
        MethodGroupsHelper.findGroupsMethods(m_classMap.values(), true);
    Map<String, List<ITestNGMethod>> afterGroupMethods =
        MethodGroupsHelper.findGroupsMethods(m_classMap.values(), false);

    //
    // Walk through all the TestClasses, store their method
    // and initialize them with the correct ITestClass
    //
    for (ITestClass tc : m_classMap.values()) {
      fixMethodsWithClass(tc.getTestMethods(), tc, testMethods);
      fixMethodsWithClass(tc.getBeforeClassMethods(), tc, beforeClassMethods);
      fixMethodsWithClass(tc.getBeforeTestMethods(), tc, null);
      fixMethodsWithClass(tc.getAfterTestMethods(), tc, null);
      fixMethodsWithClass(tc.getAfterClassMethods(), tc, afterClassMethods);
      fixMethodsWithClass(tc.getBeforeSuiteMethods(), tc, beforeSuiteMethods);
      fixMethodsWithClass(tc.getAfterSuiteMethods(), tc, afterSuiteMethods);
      fixMethodsWithClass(tc.getBeforeTestConfigurationMethods(), tc, beforeXmlTestMethods);
      fixMethodsWithClass(tc.getAfterTestConfigurationMethods(), tc, afterXmlTestMethods);
      fixMethodsWithClass(tc.getBeforeGroupsMethods(), tc,
          MethodHelper.uniqueMethodList(beforeGroupMethods.values()));
      fixMethodsWithClass(tc.getAfterGroupsMethods(), tc,
          MethodHelper.uniqueMethodList(afterGroupMethods.values()));
    }

    //
    // Sort the methods
    //
    m_beforeSuiteMethods = MethodHelper.collectAndOrderMethods(beforeSuiteMethods,
                                                              false /* forTests */,
                                                              m_runInfo,
                                                              m_annotationFinder,
                                                              true /* unique */,
                                                              m_excludedMethods);

    m_beforeXmlTestMethods = MethodHelper.collectAndOrderMethods(beforeXmlTestMethods,
                                                              false /* forTests */,
                                                              m_runInfo,
                                                              m_annotationFinder,
                                                              true /* unique (CQ added by me)*/,
                                                              m_excludedMethods);

    m_allTestMethods = MethodHelper.collectAndOrderMethods(testMethods,
                                                                true /* forTest? */,
                                                                m_runInfo,
                                                                m_annotationFinder,
                                                                false /* unique */,
                                                                m_excludedMethods);
    m_classMethodMap = new ClassMethodMap(testMethods);

    m_afterXmlTestMethods = MethodHelper.collectAndOrderMethods(afterXmlTestMethods,
                                                              false /* forTests */,
                                                              m_runInfo,
                                                              m_annotationFinder,
                                                              true /* unique (CQ added by me)*/,
                                                              m_excludedMethods);

    m_afterSuiteMethods = MethodHelper.collectAndOrderMethods(afterSuiteMethods,
                                                              false /* forTests */,
                                                              m_runInfo,
                                                              m_annotationFinder,
                                                              true /* unique */,
                                                              m_excludedMethods);
    // shared group methods
    m_groupMethods = new ConfigurationGroupMethods(m_allTestMethods, beforeGroupMethods, afterGroupMethods);


  }

  private void fixMethodsWithClass(ITestNGMethod[] methods,
                                   ITestClass testCls,
                                   List<ITestNGMethod> methodList) {
    for (ITestNGMethod itm : methods) {
      itm.setTestClass(testCls);

      if (methodList != null) {
        methodList.add(itm);
      }
    }
  }

  public Collection<ITestClass> getTestClasses() {
    return m_classMap.values();
  }

  public void setTestName(String name) {
    m_testName = name;
  }

  public void setOutputDirectory(String od) {
    m_outputDirectory= od;
//  FIX: empty directories were created
//    if (od == null) { m_outputDirectory = null; return; } //for maven2
//    File file = new File(od);
//    file.mkdirs();
//    m_outputDirectory= file.getAbsolutePath();
  }

  private void addMetaGroup(String name, List<String> groupNames) {
    m_metaGroups.put(name, groupNames);
  }

  /**
   * Calculate the transitive closure of all the MetaGroups
   *
   * @param groups
   * @param unfinishedGroups
   * @param result           The transitive closure containing all the groups found
   */
  private void collectGroups(String[] groups,
                             List<String> unfinishedGroups,
                             Map<String, String> result) {
    for (String gn : groups) {
      List<String> subGroups = m_metaGroups.get(gn);
      if (null != subGroups) {

        for (String sg : subGroups) {
          if (null == result.get(sg)) {
            result.put(sg, sg);
            unfinishedGroups.add(sg);
          }
        }
      }
    }
  }

  private Map<String, String> createGroups(List<String> groups) {
    return createGroups(groups.toArray(new String[groups.size()]));
  }

  private Map<String, String> createGroups(String[] groups) {
    Map<String, String> result = Maps.newHashMap();

    // Groups that were passed on the command line
    for (String group : groups) {
      result.put(group, group);
    }

    // See if we have any MetaGroups and
    // expand them if they match one of the groups
    // we have just been passed
    List<String> unfinishedGroups = Lists.newArrayList();

    if (m_metaGroups.size() > 0) {
      collectGroups(groups, unfinishedGroups, result);

      // Do we need to loop over unfinished groups?
      while (unfinishedGroups.size() > 0) {
        String[] uGroups = unfinishedGroups.toArray(new String[unfinishedGroups.size()]);
        unfinishedGroups = Lists.newArrayList();
        collectGroups(uGroups, unfinishedGroups, result);
      }
    }

    //    Utils.dumpMap(result);
    return result;
  }

  /**
   * The main entry method for TestRunner.
   *
   * This is where all the hard work is done:
   * - Invoke configuration methods
   * - Invoke test methods
   * - Catch exceptions
   * - Collect results
   * - Invoke listeners
   * - etc...
   */
  public void run() {
    beforeRun();

    try {
      XmlTest test= getTest();
      if(test.isJUnit()) {
        privateRunJUnit(test);
      }
      else {
        privateRun(test);
      }
    }
    finally {
      afterRun();
    }
  }

  /** Before run preparements. */
  private void beforeRun() {
    //
    // Log the start date
    //
    m_startDate = new Date(System.currentTimeMillis());

    // Log start
    logStart();

    // Invoke listeners
    fireEvent(true /*start*/);

    // invoke @BeforeTest
    ITestNGMethod[] testConfigurationMethods= getBeforeTestConfigurationMethods();
    if(null != testConfigurationMethods && testConfigurationMethods.length > 0) {
      m_invoker.invokeConfigurations(null,
                                     testConfigurationMethods,
                                     m_xmlTest.getSuite(),
                                     m_xmlTest.getParameters(),
                                     null, /* no parameter values */
                                     null /* instance */);
    }
  }

  private void privateRunJUnit(XmlTest xmlTest) {
    ClassInfoMap cim = new ClassInfoMap(m_testClassesFromXml);
    final Set<Class<?>> classes = cim.getClasses();
    final List<ITestNGMethod> runMethods = Lists.newArrayList();
    List<IWorker<ITestNGMethod>> workers = Lists.newArrayList();
    // FIXME: directly referencing JUnitTestRunner which uses JUnit classes
    // may result in an class resolution exception under different JVMs
    // The resolution process is not specified in the JVM spec with a specific implementation,
    // so it can be eager => failure
    workers.add(new IWorker<ITestNGMethod>() {
      /**
       * @see org.testng.internal.IMethodWorker#getMaxTimeOut()
       */
      @Override
      public long getTimeOut() {
        return 0;
      }

      /**
       * @see java.lang.Runnable#run()
       */
      @Override
      public void run() {
        for(Class<?> tc: classes) {
          IJUnitTestRunner tr= ClassHelper.createTestRunner(TestRunner.this);
          try {
            tr.run(tc);
          }
          catch(Exception ex) {
            ex.printStackTrace();
          }
          finally {
            runMethods.addAll(tr.getTestMethods());
          }
        }
      }

      @Override
      public List<ITestNGMethod> getTasks() {
        throw new TestNGException("JUnit not supported");
      }

      @Override
      public int getPriority() {
        if (m_allTestMethods.length == 1) {
          return m_allTestMethods[0].getPriority();
        } else {
          return 0;
        }
      }

      @Override
      public int compareTo(IWorker<ITestNGMethod> other) {
        return getPriority() - other.getPriority();
      }
    });

    runWorkers(workers, "" /* JUnit does not support parallel */, null);
    m_allTestMethods= runMethods.toArray(new ITestNGMethod[runMethods.size()]);
  }

  private void privateRun(XmlTest xmlTest) {
    //
    // Calculate the lists of tests that can be run in sequence and in parallel
    //
    List<List<ITestNGMethod>> sequentialList= Lists.newArrayList();
    List<ITestNGMethod> parallelList= Lists.newArrayList();
    ListMultiMap<Integer, ITestNGMethod> sequentialMapList = Maps.newListMultiMap();

    String parallelMode = xmlTest.getParallel();
    boolean parallel = XmlSuite.PARALLEL_METHODS.equals(parallelMode)
        || "true".equalsIgnoreCase(parallelMode)
        || XmlSuite.PARALLEL_CLASSES.equals(parallelMode)
        || XmlSuite.PARALLEL_INSTANCES.equals(parallelMode);

    // @@@
    if (false) { // (!parallel) {
      // sequential
      computeTestLists(sequentialList, parallelList, sequentialMapList);

      int seqCount = 0;
      for (List<ITestNGMethod> l : sequentialList) {
        seqCount += l.size();
      }
      log(3, "Found " + seqCount + " sequential methods and " + parallelList.size()
          + " parallel methods");

      //
      // If the user specified preserve-order = true, we can't change the ordering
      // of the methods on the sequential list, since they are not free, however
      // we can still reorder the classes to reflect that order.
      //
      if ("true".equalsIgnoreCase(xmlTest.getPreserveOrder())) {
        // Note: modifying sequentialList
        sequentialList = preserveClassOrder(xmlTest, sequentialList);
      }

      //
      // Create the workers
      //
      List<TestMethodWorker> workers = Lists.newArrayList();

      createSequentialWorkers(sequentialList, xmlTest, m_classMethodMap, workers);
      ListMultiMap<Integer, TestMethodWorker> ml =
          createSequentialWorkers(sequentialMapList, xmlTest.getParameters(), m_classMethodMap);

      // All the parallel tests are placed in a separate worker, so they can be
      // invoked in parallel
      createParallelWorkers(parallelList, xmlTest, m_classMethodMap, workers);

//      m_testPlan =
//        new TestPlan(sequentialList, parallelList, cmm,
//          getBeforeSuiteMethods(), getAfterSuiteMethods(),
//          m_groupMethods, xmlTest);

      try {
        // Sort by priorities
        Collections.sort(workers);
        runWorkers(workers, xmlTest.getParallel(), ml);
      }
      finally {
        m_classMethodMap.clear();
      }
    }
    else {
      // parallel
      int threadCount = parallel ? xmlTest.getThreadCount() : 1;
      // Make sure we create a graph based on the intercepted methods, otherwise an interceptor
      // removing methods would cause the graph never to terminate (because it would expect
      // termination from methods that never get invoked).
      DynamicGraph<ITestNGMethod> graph = createDynamicGraph(intercept(m_allTestMethods));
      if (parallel) {
        if (graph.getNodeCount() > 0) {
          GraphThreadPoolExecutor<ITestNGMethod> executor =
              new GraphThreadPoolExecutor<ITestNGMethod>(graph, this,
                  threadCount, threadCount, 0, TimeUnit.MILLISECONDS,
                  new LinkedBlockingQueue<Runnable>());
          executor.run();
//          if (parallel) {
            try {
              long timeOut = m_xmlTest.getTimeOut(XmlTest.DEFAULT_TIMEOUT_MS);
              Utils.log("TestRunner", 2, "Starting executor for test " + m_xmlTest.getName()
                  + " with time out:" + timeOut + " milliseconds.");
              executor.awaitTermination(timeOut, TimeUnit.MILLISECONDS);
              executor.shutdownNow();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
//          }
        }
      } else {
        List<ITestNGMethod> freeNodes = graph.getFreeNodes();
        while (! freeNodes.isEmpty()) {
          List<IWorker<ITestNGMethod>> runnables = createWorkers(freeNodes);
          for (IWorker<ITestNGMethod> r : runnables) {
            r.run();
          }
          graph.setStatus(freeNodes, Status.FINISHED);
          freeNodes = graph.getFreeNodes();
        }
      }
    }
  }

  /**
   * Apply the method interceptor (if applicable) to the list of methods.
   */
  private ITestNGMethod[] intercept(ITestNGMethod[] methods) {
    if (m_methodInterceptor == null) return methods;

    IMethodInstance[] instances = methodsToMethodInstances(Arrays.asList(methods));

    List<IMethodInstance> resultInstances =
        m_methodInterceptor.intercept(Arrays.asList(instances), this);
    List<ITestNGMethod> result = Lists.newArrayList();
    for (IMethodInstance imi : resultInstances) {
      result.add(imi.getMethod());
    }

    return result.toArray(new ITestNGMethod[result.size()]);
  }

  /**
   * Reorder the methods to preserve the class order without changing the method ordering.
   */
  private List<List<ITestNGMethod>> preserveClassOrder(XmlTest test,
      List<List<ITestNGMethod>> lists) {

    List<List<ITestNGMethod>> result = Lists.newArrayList();

    Map<String, List<ITestNGMethod>> classes = Maps.newHashMap();
    List<XmlClass> sortedClasses = Lists.newArrayList();

    for (XmlClass c : test.getXmlClasses()) {
      classes.put(c.getName(), new ArrayList<ITestNGMethod>());
      sortedClasses.add(c);
    }

    // Sort the classes based on their order of appearance in the XML
    Collections.sort(sortedClasses, new Comparator<XmlClass>() {
      @Override
      public int compare(XmlClass arg0, XmlClass arg1) {
        return arg0.getIndex() - arg1.getIndex();
      }
    });

    // Put each method in their class bucket
    for (List<ITestNGMethod> ll : lists) {
      for (ITestNGMethod m : ll) {
        String declaredClass = m.getTestClass().getName();
        List<ITestNGMethod> l = classes.get(declaredClass);
        // The list might be null if the class came from somewhere else than XML,
        // e.g. a factory
        if (l == null) {
          l = Lists.newArrayList();
          classes.put(declaredClass, l);
        }
        l.add(m);
      }
    }
      // Recreate the list based on the class ordering
    List<ITestNGMethod> tmpResult = Lists.newArrayList();
      for (XmlClass xc : sortedClasses) {
        List<ITestNGMethod> methods = classes.get(xc.getName());
        tmpResult.addAll(methods);
      }
      result.add(tmpResult);
//    }

//    System.out.println(result);
    return result;
  }

  /**
   * Create a list of workers to run the methods passed in parameter.
   * Each test method is run in its own worker except in the following cases:
   * - The method belongs to a class that has @Test(sequential=true)
   * - The parallel attribute is set to "classes"
   * In both these cases, all the methods belonging to that class will then
   * be put in the same worker in order to run in the same thread.
   */
  @Override
  public List<IWorker<ITestNGMethod>> createWorkers(List<ITestNGMethod> methods) {
    List<IWorker<ITestNGMethod>> result;
    if (XmlSuite.PARALLEL_INSTANCES.equals(m_xmlTest.getParallel())) {
      result = createInstanceBasedParallelWorkers(methods);
    } else {
      result = createClassBasedParallelWorkers(methods);
    }
    return result;
  }

  /**
   * Create workers for parallel="classes" and similar cases.
   */
  private List<IWorker<ITestNGMethod>> createClassBasedParallelWorkers(List<ITestNGMethod> methods) {
    List<IWorker<ITestNGMethod>> result = Lists.newArrayList();
    // Methods that belong to classes with a sequential=true or parallel=classes
    // attribute must all be run in the same worker
    Set<Class> sequentialClasses = Sets.newHashSet();
    for (ITestNGMethod m : methods) {
      Class<? extends ITestClass> cls = m.getRealClass();
      org.testng.annotations.ITestAnnotation test =
        (org.testng.annotations.ITestAnnotation) m_annotationFinder.
          findAnnotation(cls,
              org.testng.annotations.ITestAnnotation.class);

      // If either sequential=true or parallel=classes, mark this class sequential
      if (test != null && (test.getSequential() || test.getSingleThreaded()) ||
          XmlSuite.PARALLEL_CLASSES.equals(m_xmlTest.getParallel())) {
        sequentialClasses.add(cls);
      }
    }

    List<IMethodInstance> methodInstances = Lists.newArrayList();
    for (ITestNGMethod tm : methods) {
      methodInstances.addAll(methodsToMultipleMethodInstances(tm));
    }

    //
    // Finally, sort the parallel methods by classes
    //
    methodInstances = m_methodInterceptor.intercept(methodInstances, this);
    Map<String, String> params = m_xmlTest.getParameters();

    Set<Class<?>> processedClasses = Sets.newHashSet();
    for (IMethodInstance im : methodInstances) {
      Class<?> c = im.getMethod().getTestClass().getRealClass();
      if (sequentialClasses.contains(c)) {
        if (!processedClasses.contains(c)) {
          processedClasses.add(c);
          if (System.getProperty("experimental") != null) {
            List<IMethodInstance>[] instances = createInstances(methodInstances);
            for (List<IMethodInstance> inst : instances) {
              TestMethodWorker worker = createTestMethodWorker(inst, params, c);
              result.add(worker);
            }
          }
          else {
            // Sequential class: all methods in one worker
            TestMethodWorker worker = createTestMethodWorker(methodInstances, params, c);
            result.add(worker);
          }
        }
      }
      else {
        // Parallel class: each method in its own worker
        TestMethodWorker worker = createTestMethodWorker(Arrays.asList(im), params, c);
        result.add(worker);
      }
    }

    // Sort by priorities
    Collections.sort(result);
    return result;
  }


  /**
   * Create workers for parallel="instances".
   */
  private List<IWorker<ITestNGMethod>>
      createInstanceBasedParallelWorkers(List<ITestNGMethod> methods) {
    List<IWorker<ITestNGMethod>> result = Lists.newArrayList();
    ListMultiMap<Object, ITestNGMethod> lmm = Maps.newListMultiMap();
    for (ITestNGMethod m : methods) {
      lmm.put(m.getInstance(), m);
    }
    for (Map.Entry<Object, List<ITestNGMethod>> es : lmm.getEntrySet()) {
      List<IMethodInstance> methodInstances = Lists.newArrayList();
      for (ITestNGMethod m : es.getValue()) {
        methodInstances.add(new MethodInstance(m));
      }
      TestMethodWorker tmw = new TestMethodWorker(m_invoker,
          methodInstances.toArray(new IMethodInstance[methodInstances.size()]),
          m_xmlTest.getSuite(),
          m_xmlTest.getParameters(),
          m_allTestMethods,
          m_groupMethods,
          m_classMethodMap,
          this);
      result.add(tmw);
    }

    return result;
  }

  private List<IMethodInstance>[] createInstances(List<IMethodInstance> methodInstances) {
    Map<Object, List<IMethodInstance>> map = Maps.newHashMap();
//    MapList<IMethodInstance[], Object> map = new MapList<IMethodInstance[], Object>();
    for (IMethodInstance imi : methodInstances) {
      for (Object o : imi.getInstances()) {
        System.out.println(o);
        List<IMethodInstance> l = map.get(o);
        if (l == null) {
          l = Lists.newArrayList();
          map.put(o, l);
        }
        l.add(imi);
      }
//      for (Object instance : imi.getInstances()) {
//        map.put(imi, instance);
//      }
    }
//    return map.getKeys();
    System.out.println(map);
    List[] result = new List[map.size()];
    int i = 0;
    for (List<IMethodInstance> imi : map.values()) {
      result[i++] = imi;
    }
    return result;
  }

  private TestMethodWorker createTestMethodWorker(
      List<IMethodInstance> methodInstances, Map<String, String> params,
      Class<?> c) {
    return new TestMethodWorker(m_invoker,
        findClasses(methodInstances, c),
        m_xmlTest.getSuite(),
        params,
        m_allTestMethods,
        m_groupMethods,
        m_classMethodMap,
        this);
  }

  private IMethodInstance[] findClasses(List<IMethodInstance> methodInstances, Class<?> c) {
    List<IMethodInstance> result = Lists.newArrayList();
    for (IMethodInstance mi : methodInstances) {
      if (mi.getMethod().getTestClass().getRealClass() == c) {
        result.add(mi);
      }
    }
    return result.toArray(new IMethodInstance[result.size()]);
  }

  private void createParallelWorkers(List<ITestNGMethod> parallel,
      XmlTest xmlTest, ClassMethodMap cmm, List<TestMethodWorker> workers) {

    if(parallel.isEmpty()) {
      return;
    }

    List<IMethodInstance> methodInstances = Lists.newArrayList();
    for (ITestNGMethod tm : parallel) {
      methodInstances.addAll(methodsToMultipleMethodInstances(tm));
    }

    //
    // Finally, sort the parallel methods by classes
    //
    methodInstances = m_methodInterceptor.intercept(methodInstances, this);

    if (getVerbose() >= 2) {
      log(3, "Will be run in random order:");
      for (IMethodInstance mi : methodInstances) {
        log(3, "  " + mi.getMethod());
        log(3, "      on instances");
        for(Object o: mi.getInstances()) {
          log(3, "     " + o);
        }
      }
      log(3, "===");
    }

    Map<String, String> params = xmlTest.getParameters();
    for (IMethodInstance mi : methodInstances) {
      workers.add(new TestMethodWorker(m_invoker,
                                       new IMethodInstance[] { mi },
                                       m_xmlTest.getSuite(),
                                       params,
                                       m_allTestMethods,
                                       m_groupMethods,
                                       cmm,
                                       this));
    }
  }

  /**
   * @return a Set of arrays of IMethodInstances. Each element in the array is a method that belongs
   * to the same class.
   */
  private Map<Class, Set<IMethodInstance>> groupMethodInstancesByClass(List<IMethodInstance> instances) {
      Map<Class, Set<IMethodInstance>> result = Maps.newHashMap();
      for (IMethodInstance mi : instances) {
          Class cl = mi.getMethod().getTestClass().getRealClass();
          Set<IMethodInstance> methods = result.get(cl);
          if (methods == null) {
              methods = new HashSet<IMethodInstance>();
              result.put(cl, methods);
          }
          methods.add(mi);
      }

      return result;
  }

  private void createSequentialWorkers(List<List<ITestNGMethod>> sequentialList,
      XmlTest xmlTest, ClassMethodMap cmm, List<TestMethodWorker> workers) {

    Map<String, String> params = xmlTest.getParameters();
    if(sequentialList.isEmpty()) {
      return;
    }

    Map<Object, List<ITestNGMethod>> map = Maps.newHashMap();

    for (List<ITestNGMethod> sl : sequentialList) {
      for (ITestNGMethod m : sl) {
        Object o = m.getInstance();
        List<ITestNGMethod> l = map.get(o);
        if (l == null) {
          l = Lists.newArrayList();
          map.put(o, l);
        }
        l.add(m);
      }
    }

    if (xmlTest.groupByInstances()) {
      for (Map.Entry<Object, List<ITestNGMethod>> es : map.entrySet()) {
        List<MethodInstance> instances = Lists.newArrayList();
        for (ITestNGMethod m : es.getValue()) {
          instances.add(new MethodInstance(m));
        }

        workers.add(new TestMethodWorker(m_invoker,
            instances.toArray(new MethodInstance[instances.size()]),
            m_xmlTest.getSuite(),
            params,
            m_allTestMethods,
            m_groupMethods,
            cmm,
            this));
      }
    } else {
      // All the sequential tests are place in one worker, guaranteeing they
      // will be invoked sequentially
      for (List<ITestNGMethod> sl : sequentialList) {
        workers.add(new TestMethodWorker(m_invoker,
                                         methodsToMethodInstances(sl),
                                         m_xmlTest.getSuite(),
                                         params,
                                         m_allTestMethods,
                                         m_groupMethods,
                                         cmm,
                                         this));
      }
    }

    if (getVerbose() >= 2) {
      log(3, "Will be run sequentially:");
      for (List<ITestNGMethod> l : sequentialList) {
        for (ITestNGMethod tm : l) {
          log(3, "  " + tm);
        }
        log(3, "====");
      }

      log(3, "===");
    }
  }

  private ListMultiMap<Integer, TestMethodWorker> createSequentialWorkers(ListMultiMap<Integer,
      ITestNGMethod> mapList, Map<String, String> params, ClassMethodMap cmm) {

    ListMultiMap<Integer, TestMethodWorker> result = Maps.newListMultiMap();
    // All the sequential tests are place in one worker, guaranteeing they
    // will be invoked sequentially
    for (Integer i : mapList.getKeys()) {
      result.put(i,
          new TestMethodWorker(m_invoker, methodsToMethodInstances(mapList.get(i)),
          m_xmlTest.getSuite(), params, m_allTestMethods, m_groupMethods, cmm, this));
    }

    if (getVerbose() >= 2) {
      log(3, "Will be run sequentially:" + result);
    }

    return result;
  }

  /**
   * @@@ remove this
   */
  private List<MethodInstance> methodsToMultipleMethodInstances(ITestNGMethod... sl) {
    List<MethodInstance> vResult = Lists.newArrayList();
    for (ITestNGMethod m : sl) {
      vResult.add(new MethodInstance(m));
    }

    return vResult;
  }

  private MethodInstance[] methodsToMethodInstances(List<ITestNGMethod> sl) {
    MethodInstance[] result = new MethodInstance[sl.size()];
    for (int i = 0; i < result.length; i++) {
      result[i] = new MethodInstance(sl.get(i));
    }

    return result;
  }

  //
  // Invoke the workers
  //
  private void runWorkers(List<? extends IWorker<ITestNGMethod>> workers, String parallelMode,
      ListMultiMap<Integer, TestMethodWorker> sequentialWorkers) {
    if (XmlSuite.PARALLEL_METHODS.equals(parallelMode)
        || "true".equalsIgnoreCase(parallelMode)
        || XmlSuite.PARALLEL_CLASSES.equals(parallelMode))
    {
      //
      // Parallel run
      //
      // Default timeout for individual methods:  same as the test global-time-out, but
      // overridden if a method defines its own.
      long maxTimeOut = m_xmlTest.getTimeOut(XmlTest.DEFAULT_TIMEOUT_MS);
      for (IWorker<ITestNGMethod> tmw : workers) {
        long mt = tmw.getTimeOut();
        if (mt > maxTimeOut) {
          maxTimeOut= mt;
        }
      }

      ThreadUtil.execute(workers, m_xmlTest.getThreadCount(), maxTimeOut, false);
//      ThreadUtil.execute(sequentialWorkers);
    }
    else {
      //
      // Sequential run
      //
      for (IWorker<ITestNGMethod> tmw : workers) {
        tmw.run();
      }
    }
  }

  private void afterRun() {
    // invoke @AfterTest
    ITestNGMethod[] testConfigurationMethods= getAfterTestConfigurationMethods();
    if(null != testConfigurationMethods && testConfigurationMethods.length > 0) {
      m_invoker.invokeConfigurations(null,
                                     testConfigurationMethods,
                                     m_xmlTest.getSuite(),
                                     m_xmlTest.getParameters(),
                                     null, /* no parameter values */
                                     null /* instance */);
    }

    //
    // Log the end date
    //
    m_endDate = new Date(System.currentTimeMillis());

    if (getVerbose() >= 3) {
      dumpInvokedMethods();
    }

    // Invoke listeners
    fireEvent(false /*stop*/);

    // Statistics
//    logResults();
  }

  /**
   * @param regexps
   * @param group
   * @return true if the map contains at least one regexp that matches the
   * given group
   */
  private boolean containsString(Map<String, String> regexps, String group) {
    for (String regexp : regexps.values()) {
      boolean match = Pattern.matches(regexp, group);
      if (match) {
        return true;
      }
    }

    return false;
  }

  private DynamicGraph<ITestNGMethod> createDynamicGraph(ITestNGMethod[] methods) {
    DynamicGraph<ITestNGMethod> result = new DynamicGraph<ITestNGMethod>();
    result.setComparator(new Comparator<ITestNGMethod>() {
      @Override
      public int compare(ITestNGMethod o1, ITestNGMethod o2) {
        return o1.getPriority() - o2.getPriority();
      }
    });

    Map<String, ITestNGMethod> map = Maps.newHashMap();
    ListMultiMap<String, ITestNGMethod> groups = Maps.newListMultiMap();

    for (ITestNGMethod m : methods) {
      map.put(/* m.getTestClass().getName() + "." + */ m.getMethodName(), m);
      for (String g : m.getGroups()) {
        groups.put(g, m);
      }
    }

    // A map of each priority and the list of methods that have this priority
//    ListMultiMap<Integer, ITestNGMethod> methodsByPriority = Maps.newListMultiMap();
//    for (ITestNGMethod m : methods) {
//      methodsByPriority.put(m.getPriority(), m);
//    }

    // The priority map will contain at least one entry for all the methods that have
    // a priority of zero (the default). If it has more than one entry, then we know that
    // some test methods specified priorities, so we need to create dependencies
    // that reflect the priority order.
//    boolean hasPriorities = methodsByPriority.getSize() > 1;

    for (ITestNGMethod m : methods) {
      result.addNode(m);

      // Priority
//      if (hasPriorities) {
//        for (Map.Entry<Integer, List<ITestNGMethod>> e : methodsByPriority.getEntrySet()) {
//          if (e.getKey() < m.getPriority()) {
//            for (ITestNGMethod dm : e.getValue()) {
//              result.addEdge(m, dm);
//            }
//          }
//        }
//      }

      // Dependent methods
      {
        String[] dependentMethods = m.getMethodsDependedUpon();
        if (dependentMethods != null) {
          for (String d : dependentMethods) {
            String shortMethodName = d.substring(d.lastIndexOf(".") + 1);
            ITestNGMethod dm = map.get(shortMethodName);
            if (dm == null) {
              throw new TestNGException("Method \"" + m
                  + "\" depends on nonexistent method \"" + d + "\"");
            }
            result.addEdge(m, dm);
          }
        }
      }

      // Dependent groups
      {
        String[] dependentGroups = m.getGroupsDependedUpon();
        for (String d : dependentGroups) {
          List<ITestNGMethod> dg = groups.get(d);
          if (dg == null) {
            throw new TestNGException("Method \"" + m
                + "\" depends on nonexistent group \"" + d + "\"");
          }
          for (ITestNGMethod ddm : dg) {
            result.addEdge(m, ddm);
          }
        }
      }

      // Preserve order
      if ("true".equalsIgnoreCase(getCurrentXmlTest().getPreserveOrder())) {
        // If preserve-order was specified and the class order is A, B
        // create a new set of dependencies where each method of B depends
        // on all the methods of A
        ListMultiMap<ITestNGMethod, ITestNGMethod> classDependencies
            = createClassDependencies(methods, getCurrentXmlTest());

        for (Map.Entry<ITestNGMethod, List<ITestNGMethod>> es : classDependencies.getEntrySet()) {
          for (ITestNGMethod dm : es.getValue()) {
            result.addEdge(dm, es.getKey());
          }
        }
      }

      // Group by instances
      if (getCurrentXmlTest().groupByInstances()) {
        ListMultiMap<ITestNGMethod, ITestNGMethod> instanceDependencies
            = createInstanceDependencies(methods, getCurrentXmlTest());

        for (Map.Entry<ITestNGMethod, List<ITestNGMethod>> es : instanceDependencies.getEntrySet()) {
          for (ITestNGMethod dm : es.getValue()) {
            result.addEdge(dm, es.getKey());
          }
        }

      }
    }

    List<ITestNGMethod> n = result.getFreeNodes();
    return result;
  }

  private ListMultiMap<ITestNGMethod, ITestNGMethod> createInstanceDependencies(
      ITestNGMethod[] methods, XmlTest currentXmlTest)
  {
    ListMultiMap<Object, ITestNGMethod> instanceMap = Maps.newListMultiMap();
    for (ITestNGMethod m : methods) {
      instanceMap.put(m.getInstance(), m);
    }

    ListMultiMap<ITestNGMethod, ITestNGMethod> result = Maps.newListMultiMap();
    Object previousInstance = null;
    for (Map.Entry<Object, List<ITestNGMethod>> es : instanceMap.getEntrySet()) {
      if (previousInstance == null) {
        previousInstance = es.getKey();
      } else {
        List<ITestNGMethod> previousMethods = instanceMap.get(previousInstance);
        Object currentInstance = es.getKey();
        List<ITestNGMethod> currentMethods = instanceMap.get(currentInstance);
        // Make all the methods from the current instance depend on the methods of
        // the previous instance
        for (ITestNGMethod cm : currentMethods) {
          for (ITestNGMethod pm : previousMethods) {
            result.put(cm, pm);
          }
        }
        currentInstance = previousInstance;
      }
    }

    return result;
  }

  private ListMultiMap<ITestNGMethod, ITestNGMethod> createClassDependencies(
      ITestNGMethod[] methods, XmlTest test)
  {
    Map<String, List<ITestNGMethod>> classes = Maps.newHashMap();
    List<XmlClass> sortedClasses = Lists.newArrayList();

    for (XmlClass c : test.getXmlClasses()) {
      classes.put(c.getName(), new ArrayList<ITestNGMethod>());
      sortedClasses.add(c);
    }

    // Sort the classes based on their order of appearance in the XML
    Collections.sort(sortedClasses, new Comparator<XmlClass>() {
      @Override
      public int compare(XmlClass arg0, XmlClass arg1) {
        return arg0.getIndex() - arg1.getIndex();
      }
    });

    Map<String, Integer> indexedClasses1 = Maps.newHashMap();
    Map<Integer, String> indexedClasses2 = Maps.newHashMap();
    int i = 0;
    for (XmlClass c : sortedClasses) {
      indexedClasses1.put(c.getName(), i);
      indexedClasses2.put(i, c.getName());
      i++;
    }

    ListMultiMap<String, ITestNGMethod> methodsFromClass = Maps.newListMultiMap();
    for (ITestNGMethod m : methods) {
      methodsFromClass.put(m.getTestClass().getName(), m);
    }

    ListMultiMap<ITestNGMethod, ITestNGMethod> result = Maps.newListMultiMap();
    for (ITestNGMethod m : methods) {
      int index = indexedClasses1.get(m.getTestClass().getName());
      if (index > 0) {
        // Make this method depend on all the methods of the class in the previous
        // index
        String classDependedUpon = indexedClasses2.get(index - 1);
        List<ITestNGMethod> methodsDependedUpon = methodsFromClass.get(classDependedUpon);
        for (ITestNGMethod mdu : methodsDependedUpon) {
          result.put(mdu, m);
        }
      }
    }

    return result;
  }

  /**
   * Creates the
   * @param sl the sequential list of methods
   * @param parallelList the list of methods that can be run in parallel
   */
  private void computeTestLists(List<List<ITestNGMethod>> sl,
      List<ITestNGMethod> parallelList, ListMultiMap<Integer, ITestNGMethod> outSequentialList) {

    Map<String, String> groupsDependedUpon = Maps.newHashMap();
    Map<String, String> methodsDependedUpon = Maps.newHashMap();

    Map<String, List<ITestNGMethod>> sequentialAttributeList = Maps.newHashMap();
    List<ITestNGMethod> sequentialList = Lists.newArrayList();

    for (int i= m_allTestMethods.length - 1; i >= 0; i--) {
      ITestNGMethod tm= m_allTestMethods[i];

      //
      // If the class this method belongs to has @Test(sequential = true), we
      // put this method in the sequential list right away
      //
      Class<?> cls= tm.getRealClass();
      org.testng.annotations.ITestAnnotation test =
        (org.testng.annotations.ITestAnnotation) m_annotationFinder.
          findAnnotation(cls, org.testng.annotations.ITestAnnotation.class);
      if (test != null) {
        if (test.getSequential() || test.getSingleThreaded()) {
          String className = tm.getTestClass().getName();
          List<ITestNGMethod> list = sequentialAttributeList.get(className);
          if (list == null) {
            list = Lists.newArrayList();
            sequentialAttributeList.put(className, list);
          }
          list.add(0, tm);
          continue;
        }
      }

      //
      // Otherwise, determine if it depends on other methods/groups or if
      // it is depended upon
      //
      String[] currentGroups = tm.getGroups();
      String[] currentGroupsDependedUpon= tm.getGroupsDependedUpon();
      String[] currentMethodsDependedUpon= tm.getMethodsDependedUpon();

      String thisMethodName = tm.getMethod().getDeclaringClass().getName()
        + "." + tm.getMethod().getName();
      if (currentGroupsDependedUpon.length > 0) {
        for (String gdu : currentGroupsDependedUpon) {
          groupsDependedUpon.put(gdu, gdu);
        }

        sequentialList.add(0, tm);
      }
      else if (currentMethodsDependedUpon.length > 0) {
        for (String cmu : currentMethodsDependedUpon) {
          methodsDependedUpon.put(cmu, cmu);
        }
        sequentialList.add(0, tm);
      }
      // Is there a method that depends on the current method?
      else if (containsString(methodsDependedUpon, thisMethodName)) {
        int index = 0;
        for (int j = 0; j < sequentialList.size(); j++) {
          ITestNGMethod m = sequentialList.get(j);
          if (arrayContains(m.getMethodsDependedUpon(), thisMethodName)) {
            index = j;
            break;
          }
        }
        // Insert the dependee as close to its dependent as possible (TESTNG-317)
        sequentialList.add(index, tm);
      }
      else if (currentGroups.length > 0) {
        boolean isSequential= false;

        for (String group : currentGroups) {
          if (containsString(groupsDependedUpon, group)) {
            sequentialList.add(0, tm);
            isSequential = true;

            break;
          }
        }
        if (!isSequential) {
          parallelList.add(0, tm);
        }
      }
      else {
        parallelList.add(0, tm);
      }
    }

    //
    // Put all the sequential methods in the output argument
    //
    if(sequentialList.size() > 0) {
      sl.add(sequentialList);
    }

    String previousGroup = "";
    int index = 0;
    for (ITestNGMethod m : sequentialList) {
      String[] g = m.getGroupsDependedUpon();
      if (g.length > 0 && !m.getGroupsDependedUpon()[0].equals(previousGroup)) {
        index++;
        previousGroup = m.getGroupsDependedUpon()[0];
      }
      outSequentialList.put(index, m);
    }
//    System.out.println("Map list:" + mapList);

    sl.addAll(sequentialAttributeList.values());
  }

  private boolean arrayContains(String[] array, String element) {
    for (String a : array) {
      if (element.equals(a)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Logs the beginning of the {@link #beforeRun()} .
   */
  private void logStart() {
    log(3,
        "Running test " + m_testName + " on " + m_classMap.size() + " " + " classes, "
        + " included groups:[" + mapToString(m_xmlMethodSelector.getIncludedGroups())
        + "] excluded groups:[" + mapToString(m_xmlMethodSelector.getExcludedGroups()) + "]");

    if (getVerbose() >= 3) {
      for (ITestClass tc : m_classMap.values()) {
        ((TestClass) tc).dump();
      }
    }
  }

  /**
   * Trigger the start/finish event.
   *
   * @param isStart <tt>true</tt> if the event is for start, <tt>false</tt> if the
   *                event is for finish
   */
  private void fireEvent(boolean isStart) {
    for (ITestListener itl : m_testListeners) {
      if (isStart) {
        itl.onStart(this);
      }
      else {
        itl.onFinish(this);
      }
    }
  }

  /////
  // ITestContext
  //
  @Override
  public String getName() {
    return m_testName;
  }

  /**
   * @return Returns the startDate.
   */
  @Override
  public Date getStartDate() {
    return m_startDate;
  }

  /**
   * @return Returns the endDate.
   */
  @Override
  public Date getEndDate() {
    return m_endDate;
  }

  @Override
  public IResultMap getPassedTests() {
    return m_passedTests;
  }

  @Override
  public IResultMap getSkippedTests() {
    return m_skippedTests;
  }

  @Override
  public IResultMap getFailedTests() {
    return m_failedTests;
  }

  @Override
  public IResultMap getFailedButWithinSuccessPercentageTests() {
    return m_failedButWithinSuccessPercentageTests;
  }

  @Override
  public String[] getIncludedGroups() {
    Map<String, String> ig= m_xmlMethodSelector.getIncludedGroups();
    String[] result= ig.values().toArray((new String[ig.size()]));

    return result;
  }

  @Override
  public String[] getExcludedGroups() {
    Map<String, String> eg= m_xmlMethodSelector.getExcludedGroups();
    String[] result= eg.values().toArray((new String[eg.size()]));

    return result;
  }

  @Override
  public String getOutputDirectory() {
    return m_outputDirectory;
  }

  /**
   * @return Returns the suite.
   */
  @Override
  public ISuite getSuite() {
    return m_suite;
  }

  @Override
  public ITestNGMethod[] getAllTestMethods() {
    return m_allTestMethods;
  }


  @Override
  public String getHost() {
    return m_host;
  }

  @Override
  public Collection<ITestNGMethod> getExcludedMethods() {
    Map<ITestNGMethod, ITestNGMethod> vResult = Maps.newHashMap();

    for (ITestNGMethod m : m_excludedMethods) {
      vResult.put(m, m);
    }

    return vResult.keySet();
  }

  /**
   * @see org.testng.ITestContext#getFailedConfigurations()
   */
  @Override
  public IResultMap getFailedConfigurations() {
    return m_failedConfigurations;
  }

  /**
   * @see org.testng.ITestContext#getPassedConfigurations()
   */
  @Override
  public IResultMap getPassedConfigurations() {
    return m_passedConfigurations;
  }

  /**
   * @see org.testng.ITestContext#getSkippedConfigurations()
   */
  @Override
  public IResultMap getSkippedConfigurations() {
    return m_skippedConfigurations;
  }

  //
  // ITestContext
  /////

  /////
  // ITestResultNotifier
  //

  @Override
  public void addPassedTest(ITestNGMethod tm, ITestResult tr) {
    m_passedTests.addResult(tr, tm);
  }

  @Override
  public Set<ITestResult> getPassedTests(ITestNGMethod tm) {
    return m_passedTests.getResults(tm);
  }

  @Override
  public Set<ITestResult> getFailedTests(ITestNGMethod tm) {
    return m_failedTests.getResults(tm);
  }

  @Override
  public Set<ITestResult> getSkippedTests(ITestNGMethod tm) {
    return m_skippedTests.getResults(tm);
  }

  @Override
  public void addSkippedTest(ITestNGMethod tm, ITestResult tr) {
    m_skippedTests.addResult(tr, tm);
  }

  @Override
  public void addInvokedMethod(InvokedMethod im) {
    synchronized(m_invokedMethods) {
      m_invokedMethods.add(im);
    }
  }

  @Override
  public void addFailedTest(ITestNGMethod testMethod, ITestResult result) {
    logFailedTest(testMethod, result, false /* withinSuccessPercentage */);
  }

  @Override
  public void addFailedButWithinSuccessPercentageTest(ITestNGMethod testMethod,
                                                      ITestResult result) {
    logFailedTest(testMethod, result, true /* withinSuccessPercentage */);
  }

  @Override
  public XmlTest getTest() {
    return m_xmlTest;
  }

  @Override
  public List<ITestListener> getTestListeners() {
    return m_testListeners;
  }

  @Override
  public List<IConfigurationListener> getConfigurationListeners() {
    return m_configurationListeners;
  }
  //
  // ITestResultNotifier
  /////

  private void logFailedTest(ITestNGMethod method,
                             ITestResult tr,
                             boolean withinSuccessPercentage) {
    /*
     * We should not remove a passed method from m_passedTests so that we can
     * account for the passed instances of this test method.
     */
    //m_passedTests.removeResult(method);
    if (withinSuccessPercentage) {
      m_failedButWithinSuccessPercentageTests.addResult(tr, method);
    }
    else {
      m_failedTests.addResult(tr, method);
    }
  }

  private String mapToString(Map<?, ?> m) {
    StringBuffer result= new StringBuffer();
    for (Object o : m.values()) {
      result.append(o.toString()).append(" ");
    }

    return result.toString();
  }

  private void log(int level, String s) {
    Utils.log("TestRunner", level, s);
  }

  public static int getVerbose() {
    return m_verbose;
  }

  public void setVerbose(int n) {
    m_verbose = n;
  }

  private void log(String s) {
    Utils.log("TestRunner", 2, s);
  }

  /////
  // Listeners
  //
  public void addListener(Object listener) {
    if(listener instanceof ITestListener) {
      addTestListener((ITestListener) listener);
    }
    if(listener instanceof IConfigurationListener) {
      addConfigurationListener((IConfigurationListener) listener);
    }
  }

  public void addTestListener(ITestListener il) {
    m_testListeners.add(il);
  }

  private void addConfigurationListener(IConfigurationListener icl) {
    m_configurationListeners.add(icl);
  }
  //
  // Listeners
  /////

  private List<InvokedMethod> m_invokedMethods = Lists.newArrayList();

  private void dumpInvokedMethods() {
    System.out.println("\n*********** INVOKED METHODS\n");
    for (IInvokedMethod im : m_invokedMethods) {
      if (im.isTestMethod()) {
        System.out.print("\t\t");
      }
      else if (im.isConfigurationMethod()) {
        System.out.print("\t");
      }
      else {
        continue;
      }
      System.out.println("" + im);
    }
    System.out.println("\n***********\n");
  }

  public List<ITestNGMethod> getInvokedMethods() {
    List<ITestNGMethod> result= Lists.newArrayList();
    synchronized(m_invokedMethods) {
      for (IInvokedMethod im : m_invokedMethods) {
        ITestNGMethod tm= im.getTestMethod();
        tm.setDate(im.getDate());
        result.add(tm);
      }
    }

    return result;
  }

  private IResultMap m_passedConfigurations= new ResultMap();
  private IResultMap m_skippedConfigurations= new ResultMap();
  private IResultMap m_failedConfigurations= new ResultMap();

  private class ConfigurationListener implements IConfigurationListener {
    @Override
    public void beforeConfiguration(ITestResult tr) {
    }

    @Override
    public void onConfigurationFailure(ITestResult itr) {
      m_failedConfigurations.addResult(itr, itr.getMethod());
    }

    @Override
    public void onConfigurationSkip(ITestResult itr) {
      m_skippedConfigurations.addResult(itr, itr.getMethod());
    }

    @Override
    public void onConfigurationSuccess(ITestResult itr) {
      m_passedConfigurations.addResult(itr, itr.getMethod());
    }
  }

  public void setMethodInterceptor(IMethodInterceptor methodInterceptor) {
    m_methodInterceptor = methodInterceptor;
  }

  @Override
  public XmlTest getCurrentXmlTest() {
    return m_xmlTest;
  }

  private IAttributes m_attributes = new Attributes();

  @Override
  public Object getAttribute(String name) {
    return m_attributes.getAttribute(name);
  }

  @Override
  public void setAttribute(String name, Object value) {
    m_attributes.setAttribute(name, value);
  }

  @Override
  public Set<String> getAttributeNames() {
    return m_attributes.getAttributeNames();
  }

  @Override
  public Object removeAttribute(String name) {
    return m_attributes.removeAttribute(name);
  }

  private ListMultiMap<Class<? extends Module>, Module> m_guiceModules = Maps.newListMultiMap();

  @Override
  public List<Module> getGuiceModules(Class<? extends Module> cls) {
    List<Module> result = m_guiceModules.get(cls);
    return result;
  }

  @Override
  public void addGuiceModule(Class<? extends Module> cls, Module module) {
    m_guiceModules.put(cls, module);
  }

  private Map<List<Module>, Injector> m_injectors = Maps.newHashMap();

  @Override
  public Injector getInjector(List<Module> moduleInstances) {
    return m_injectors .get(moduleInstances);
  }

  @Override
  public void addInjector(List<Module> moduleInstances, Injector injector) {
    m_injectors.put(moduleInstances, injector);
  }

} // TestRunner
