// Copyright 2015 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.lib.pkgcache;

import static com.google.common.truth.Truth.assertThat;

import com.google.common.base.Predicates;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.ResolvedTargets;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.events.DelegatingEventHandler;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.junit.Before;

/**
 * Abstract framework for target pattern evaluation tests. The {@link TargetPatternEvaluatorTest}
 * contains much of the functionality that might be needed for future tests, and its methods should
 * be extracted here if they are needed by other classes.
 */
public abstract class AbstractTargetPatternEvaluatorTest extends PackageLoadingTestCase {
  protected TargetPatternPreloader parser;
  protected RecordingParsingListener parsingListener;

  protected static ResolvedTargets<Target> parseTargetPatternList(
      TargetPatternPreloader parser,
      ExtendedEventHandler eventHandler,
      List<String> targetPatterns,
      boolean keepGoing)
      throws TargetParsingException, InterruptedException {
    return parseTargetPatternList(
        PathFragment.EMPTY_FRAGMENT, parser, eventHandler, targetPatterns, keepGoing);
  }

  protected static ResolvedTargets<Target> parseTargetPatternList(
      PathFragment relativeWorkingDirectory,
      TargetPatternPreloader parser,
      ExtendedEventHandler eventHandler,
      List<String> targetPatterns,
      boolean keepGoing)
      throws TargetParsingException, InterruptedException {
    List<String> positivePatterns =
        targetPatterns.stream()
            .map((s) -> s.startsWith("-") ? s.substring(1) : s)
            .collect(Collectors.toList());
    Map<String, Collection<Target>> resolvedTargetsMap =
        parser.preloadTargetPatterns(
            eventHandler,
            TargetPattern.mainRepoParser(relativeWorkingDirectory),
            positivePatterns,
            keepGoing);
    ResolvedTargets.Builder<Target> result = ResolvedTargets.builder();
    for (String pattern : targetPatterns) {
      if (pattern.startsWith("-")) {
        String positivePattern = pattern.substring(1);
        Collection<Target> resolvedTargets = resolvedTargetsMap.get(positivePattern);
        result.filter(Predicates.not(Predicates.in(resolvedTargets)));
      } else {
        Collection<Target> resolvedTargets = resolvedTargetsMap.get(pattern);
        result.addAll(resolvedTargets);
      }
    }
    return result.build();
  }

  /**
   * Method converts collection of targets to the new, mutable, lexicographically-ordered set of
   * corresponding labels.
   */
  protected static Set<Label> targetsToLabels(Iterable<Target> targets) {
    Set<Label> labels = new TreeSet<>();
    for (Target target : targets) {
      labels.add(target.getLabel());
    }
    return labels;
  }

  @Before
  public final void initializeParser() throws Exception {
    setUpSkyframe(ConstantRuleVisibility.PRIVATE);
    parser = skyframeExecutor.newTargetPatternPreloader();
    parsingListener = new RecordingParsingListener(reporter);
  }

  protected static Set<Label> labels(String... labelStrings) throws LabelSyntaxException {
    Set<Label> labels = new HashSet<>();
    for (String labelString : labelStrings) {
      labels.add(Label.parseCanonical(labelString));
    }
    return labels;
  }

  protected Pair<Set<Label>, Boolean> parseListKeepGoing(String... patterns)
      throws TargetParsingException, InterruptedException {
    ResolvedTargets<Target> result =
        parseTargetPatternList(parser, parsingListener, Arrays.asList(patterns), true);
    return Pair.of(targetsToLabels(result.getTargets()), result.hasError());
  }

  /** Event handler that records all parsing errors. */
  protected static final class RecordingParsingListener extends DelegatingEventHandler {
    protected final List<Pair<String, String>> events = new ArrayList<>();

    private RecordingParsingListener(ExtendedEventHandler delegate) {
      super(delegate);
    }

    @Override
    public void post(Postable post) {
      super.post(post);
      if (post instanceof ParsingFailedEvent) {
        ParsingFailedEvent e = (ParsingFailedEvent) post;
        events.add(Pair.of(e.getPattern(), e.getMessage()));
      }
    }

    protected void assertEmpty() {
      assertThat(events).isEmpty();
    }
  }
}
