/*
 * Copyright 2000-2013 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;

import org.jetbrains.annotations.NotNull;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.*;
import java.util.regex.Pattern;

/**
 * Encapsulates logic of filtering test classes (classes that contain test-cases).
 * <p/>
 * We want to have such facility in order to be able to execute different sets of tests like <code>'fast tests'</code>,
 * <code>'problem tests'</code> etc.
 * <p/>
 * I.e. assumed usage scenario is to create object of this class with necessary filtering criteria and use it's
 * {@link #matches(String)} method for determining if particular test should be executed.
 * <p/>
 * The filtering is performed by fully-qualified test class name. There are two ways to define the criteria at the moment:
 * <ul>
 *   <li>
 *     Define target class name filters (at regexp format) explicitly using
 *     {@link PatternListTestClassFilter#PatternListTestClassFilter(List) PatternListTestClassFilter};
 *   </li>
 *   <li>
 *     Read class name filters (at regexp format) from the given stream - see {@link #createOn(java.io.Reader, java.util.List)};
 *   </li>
 * </ul>
 */
public class GroupBasedTestClassFilter extends TestClassesFilter {
  /**
   * Holds reserved test group name that serves as a negation of matching result.
   *
   * @see #matches(String)
   */
  public static final String ALL_EXCLUDE_DEFINED = "ALL_EXCLUDE_DEFINED";

  private final Map<String, List<Pattern>> myPatterns = new HashMap<String, List<Pattern>>();
  private final List<Pattern> myAllPatterns = new ArrayList<Pattern>();
  private final List<Pattern> myTestGroupPatterns;
  private boolean myContainsAllExcludeDefinedGroup;

  public GroupBasedTestClassFilter(Map<String, List<String>> filters, List<String> testGroupNames) {
    //empty group means all patterns from each defined group should be excluded
    myContainsAllExcludeDefinedGroup = containsAllExcludeDefinedGroup(testGroupNames);

    for (String groupName : filters.keySet()) {
      List<String> filterList = filters.get(groupName);
      addPatterns(groupName, filterList);
    }

    myTestGroupPatterns = collectPatternsFor(testGroupNames);
  }

  private void addPatterns(String groupName, List<String> filterList) {
    List<Pattern> patterns = compilePatterns(filterList);
    myPatterns.put(groupName, patterns);
    myAllPatterns.addAll(patterns);
  }

  /**
   * Creates <code>TestClassesFilter</code> object assuming that the given stream contains grouped test class filters
   * at the following format:
   * <p/>
   * <ul>
   *   <li>
   *      every line that starts with <code>'['</code> symbol and ends with <code>']'</code> symbol defines start
   *      of the new test group. That means that all test class filters that follows this line belongs to the same
   *      test group which name is defined by the text contained between <code>'['</code> and <code>']'</code>
   *   </li>
   *   <li>every line that is not a test-group definition is considered to be a test class filter at regexp format;</li>
   * </ul>
   * <p/>
   * <b>Example</b>
   * Consider that given stream points to the following data:
   * <pre>
   *    [CVS]
   *    com.intellij.cvsSupport2.*
   *    [STRESS_TESTS]
   *    com.intellij.application.InspectionPerformanceTest
   *    com.intellij.application.TraverseUITest
   * </pre>
   * <p/>
   * It defines two test groups:
   * <ul>
   *   <li><b>CVS</b> group with the single test class name pattern <code>'com.intellij.cvsSupport2.*'</code>;</li>
   *   <li>
   *     <b>STRESS_TESTS</b> group with the following test class name patterns:
   *     <ul>
   *       <li>com.intellij.application.InspectionPerformanceTest</li>
   *       <li>com.intellij.application.TraverseUITest</li>
   *     </ul>
   *   </li>
   * </ul>
   * <p/>
   * This method doesn't suppose itself to be owner of the given stream reader, i.e. it assumes that the stream should be
   * closed on caller side.
   *
   *
   * @param reader   reader that points to the target test groups config
   * @param testGroupNames
   * @return newly created {@link GroupBasedTestClassFilter} object with the data contained at the given reader
   * @see #matches(String)
   */
  @NotNull
  public static TestClassesFilter createOn(@NotNull Reader reader, @NotNull List<String> testGroupNames) throws IOException {
    return new GroupBasedTestClassFilter(readGroups(reader), testGroupNames);
  }

  public static Map<String, List<String>> readGroups(Reader reader) throws IOException {
    Map<String, List<String>> groupNameToPatternsMap = new HashMap<String, List<String>>();
    String currentGroupName = "";

    @SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"}) BufferedReader bufferedReader = new BufferedReader(reader);
    String line;
    while ((line = bufferedReader.readLine()) != null) {
      if (line.startsWith("#")) continue;
      if (line.startsWith("[") && line.endsWith("]")) {
        currentGroupName = line.substring(1, line.length() - 1);
      }
      else {
        if (!groupNameToPatternsMap.containsKey(currentGroupName)) {
          groupNameToPatternsMap.put(currentGroupName, new ArrayList<String>());
        }
        groupNameToPatternsMap.get(currentGroupName).add(line);
      }
    }
    return groupNameToPatternsMap;
  }

  /**
   * Allows to check if given class name belongs to the test group with the given name based on filtering rules encapsulated
   * at the current {@link GroupBasedTestClassFilter} object. I.e. this method returns <code>true</code> if given test class name
   * is matched with any test class name filter configured for the test group with the given name.
   * <p/>
   * <b>Note:</b> there is a special case processing when given group name is {@link #ALL_EXCLUDE_DEFINED}. This method
   * returns <code>true</code> only if all registered patterns (for all test groups) don't match given test class name.
   *
   * @param className   target test class name to check
   * @return            <code>true</code> if given test group name is defined (not <code>null</code>) and test class with given
   *                    name belongs to the test group with given name;
   *                    <code>true</code> if given group if undefined or equal to {@link #ALL_EXCLUDE_DEFINED} and given test
   *                    class name is not matched by all registered patterns;
   *                    <code>false</code> otherwise
   */
  @Override
  public boolean matches(String className) {
    if (matchesAnyPattern(myTestGroupPatterns, className)) {
      return true;
    }
    if (myContainsAllExcludeDefinedGroup && !matchesAnyPattern(myAllPatterns, className)) {
      return true;
    }
    return false;
  }

  private static boolean containsAllExcludeDefinedGroup(List<String> groupNames) {
    return groupNames.isEmpty() || groupNames.contains(ALL_EXCLUDE_DEFINED);
  }

  private List<Pattern> collectPatternsFor(List<String> groupNames) {
    List<Pattern> patterns = new ArrayList<Pattern>();
    for (String groupName : groupNames) {
      if (myPatterns.containsKey(groupName)) {
        patterns.addAll(myPatterns.get(groupName));
      }
    }
    return patterns;
  }
}
