// 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.query2.engine;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.MutableMap;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryTaskCallable;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryTaskFuture;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.ThreadSafeMutableSet;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;

/** Several query utilities to make easier to work with query callbacks and uniquifiers. */
public final class QueryUtil {

  private QueryUtil() { }

  /** A {@link Callback} that can aggregate all the partial results into one set. */
  public interface AggregateAllCallback<T, S extends Set<T>> extends Callback<T> {
    /** Returns a {@link Set} of all the results. */
    S getResult();
  }

  /** A {@link OutputFormatterCallback} that is also a {@link AggregateAllCallback}. */
  public abstract static class AggregateAllOutputFormatterCallback<T, S extends Set<T>>
      extends ThreadSafeOutputFormatterCallback<T> implements AggregateAllCallback<T, S>  {
  }

  private static class AggregateAllOutputFormatterCallbackImpl<T>
      extends AggregateAllOutputFormatterCallback<T, ThreadSafeMutableSet<T>> {
    private final ThreadSafeMutableSet<T> result;

    private AggregateAllOutputFormatterCallbackImpl(QueryEnvironment<T> env) {
      this.result = env.createThreadSafeMutableSet();
    }

    @Override
    public final void processOutput(Iterable<T> partialResult) {
      Iterables.addAll(result, partialResult);
    }

    @Override
    public ThreadSafeMutableSet<T> getResult() {
      return result;
    }
  }

  private static class OrderedAggregateAllOutputFormatterCallbackImpl<T>
      extends AggregateAllOutputFormatterCallback<T, Set<T>> {
    private final Set<T> resultSet;
    private final List<T> resultList;

    private OrderedAggregateAllOutputFormatterCallbackImpl(QueryEnvironment<T> env) {
      this.resultSet = env.createThreadSafeMutableSet();
      this.resultList = new ArrayList<>();
    }

    @Override
    public final synchronized void processOutput(Iterable<T> partialResult) {
      for (T element : partialResult) {
        if (resultSet.add(element)) {
          resultList.add(element);
        }
      }
    }

    @Override
    public synchronized Set<T> getResult() {
      // A CompactHashSet's iteration order is the same as its insertion order.
      CompactHashSet<T> result = CompactHashSet.createWithExpectedSize(resultList.size());
      result.addAll(resultList);
      return result;
    }
  }

  /**
   * Returns a fresh {@link AggregateAllOutputFormatterCallback} instance whose
   * {@link AggregateAllCallback#getResult} returns all the elements of the result in the order they
   * were processed.
   */
  public static <T> AggregateAllOutputFormatterCallback<T, Set<T>>
      newOrderedAggregateAllOutputFormatterCallback(QueryEnvironment<T> env) {
    return new OrderedAggregateAllOutputFormatterCallbackImpl<>(env);
  }

  /**
   * Returns a fresh {@link AggregateAllCallback} instance that aggregates all of the values into an
   * {@link ThreadSafeMutableSet}.
   */
  public static <T> AggregateAllCallback<T, ThreadSafeMutableSet<T>> newAggregateAllCallback(
      QueryEnvironment<T> env) {
    return new AggregateAllOutputFormatterCallbackImpl<>(env);
  }

  /**
   * Returns a {@link QueryTaskFuture} representing the evaluation of {@code expr} as a mutable,
   * thread safe {@link Set} comprised of all the results.
   *
   * <p>Should only be used by QueryExpressions when it is the only way of achieving correctness.
   */
  public static <T> QueryTaskFuture<ThreadSafeMutableSet<T>> evalAll(
      QueryEnvironment<T> env, VariableContext<T> context, QueryExpression expr) {
    final AggregateAllCallback<T, ThreadSafeMutableSet<T>> callback = newAggregateAllCallback(env);
    return env.whenSucceedsCall(
        env.eval(expr, context, callback),
        new QueryTaskCallable<ThreadSafeMutableSet<T>>() {
          @Override
          public ThreadSafeMutableSet<T> call() {
            return callback.getResult();
          }
        });
  }

  /**
   * A mutable thread safe {@link Set} that uses a {@link KeyExtractor} for determining equality of
   * its elements. This is useful e.g. when {@code T} isn't guaranteed to have a useful
   * {@link Object#equals} and {@link Object#hashCode} but {@code K} is.
   */
  public static class ThreadSafeMutableKeyExtractorBackedSetImpl<T, K>
      extends AbstractSet<T> implements ThreadSafeMutableSet<T> {
    private final KeyExtractor<T, K> extractor;
    private final Class<T> elementClass;
    private final ConcurrentMap<K, T> map;

    public ThreadSafeMutableKeyExtractorBackedSetImpl(
        KeyExtractor<T, K> extractor, Class<T> elementClass) {
      this(extractor, elementClass, /*concurrencyLevel=*/ 1);
    }

    public ThreadSafeMutableKeyExtractorBackedSetImpl(
        KeyExtractor<T, K> extractor,
        Class<T> elementClass,
        int concurrencyLevel) {
      this.extractor = extractor;
      this.elementClass = elementClass;
      this.map =
          new ConcurrentHashMap<>(/*initialCapacity=*/ concurrencyLevel, /*loadFactor=*/ 0.75f);
    }

    @Override
    public Iterator<T> iterator() {
      return map.values().iterator();
    }

    @Override
    public int size() {
      return map.size();
    }

    @Override
    public boolean add(T element) {
      return map.putIfAbsent(extractor.extractKey(element), element) == null;
    }

    @Override
    public boolean contains(Object obj) {
      if (!elementClass.isInstance(obj)) {
        return false;
      }
      T element = elementClass.cast(obj);
      return map.containsKey(extractor.extractKey(element));
    }

    @Override
    public boolean remove(Object obj) {
      if (!elementClass.isInstance(obj)) {
        return false;
      }
      T element = elementClass.cast(obj);
      return map.remove(extractor.extractKey(element)) != null;
    }
  }

  /**
   * A {@link MutableMap} implementation that uses a {@link KeyExtractor} for determining equality
   * of its keys.
   */
  public static class MutableKeyExtractorBackedMapImpl<T, K, V> implements MutableMap<T, V> {
    private final KeyExtractor<T, K> extractor;
    private final HashMap<K, V> map;

    public MutableKeyExtractorBackedMapImpl(KeyExtractor<T, K> extractor) {
      this.extractor = extractor;
      this.map = new HashMap<>();
    }

    @Override
    @Nullable
    public V get(T key) {
      return map.get(extractor.extractKey(key));
    }

    @Override
    public V put(T key, V value) {
      return map.put(extractor.extractKey(key), value);
    }
  }

  /** A trivial {@link Uniquifier} implementation. */
  public static class UniquifierImpl<T, K> implements Uniquifier<T> {
    private final KeyExtractor<T, K> extractor;
    private final Set<K> alreadySeen;

    public UniquifierImpl(KeyExtractor<T, K> extractor) {
      this(extractor, /*concurrencyLevel=*/ 1);
    }

    public UniquifierImpl(KeyExtractor<T, K> extractor, int concurrencyLevel) {
      this.extractor = extractor;
      this.alreadySeen =
          Collections.newSetFromMap(
              new ConcurrentHashMap<>(
                  /*initialCapacity=*/ concurrencyLevel, /*loadFactor=*/ 0.75f));
    }

    @Override
    public boolean uniquePure(T element) {
      return !alreadySeen.contains(extractor.extractKey(element));
    }

    @Override
    public boolean unique(T element) {
      return alreadySeen.add(extractor.extractKey(element));
    }

    @Override
    public ImmutableList<T> unique(Iterable<T> newElements) {
      ImmutableList.Builder<T> result = ImmutableList.builder();
      for (T element : newElements) {
        if (unique(element)) {
          result.add(element);
        }
      }
      return result.build();
    }
  }

  /** A trivial {@link MinDepthUniquifier} implementation. */
  public static class MinDepthUniquifierImpl<T, K> implements MinDepthUniquifier<T> {
    private final KeyExtractor<T, K> extractor;
    private final ConcurrentMap<K, AtomicInteger> alreadySeenAtDepth;

    public MinDepthUniquifierImpl(KeyExtractor<T, K> extractor, int concurrencyLevel) {
      this.extractor = extractor;
      this.alreadySeenAtDepth =
          new ConcurrentHashMap<>(/*initialCapacity=*/ concurrencyLevel, /*loadFactor=*/ 0.75f);
    }

    @Override
    public final ImmutableList<T> uniqueAtDepthLessThanOrEqualTo(
        Iterable<T> newElements, int depth) {
      ImmutableList.Builder<T> resultBuilder = ImmutableList.builder();
      for (T newElement : newElements) {
        if (uniqueAtDepthLessThanOrEqualTo(newElement, depth)) {
          resultBuilder.add(newElement);
        }
      }
      return resultBuilder.build();
    }

    @Override
    public boolean uniqueAtDepthLessThanOrEqualTo(T newElement, int depth) {
      AtomicInteger newDepth = new AtomicInteger(depth);
      AtomicInteger previousDepth =
          alreadySeenAtDepth.putIfAbsent(extractor.extractKey(newElement), newDepth);
      if (previousDepth == null) {
        return true;
      }
      if (depth < previousDepth.get()) {
        synchronized (previousDepth) {
          if (depth < previousDepth.get()) {
            // We've seen the element before, but never at a depth this shallow.
            previousDepth.set(depth);
            return true;
          }
        }
      }
      return false;
    }

    @Override
    public boolean uniqueAtDepthLessThanOrEqualToPure(T newElement, int depth) {
      AtomicInteger previousDepth = alreadySeenAtDepth.get(extractor.extractKey(newElement));
      return previousDepth != null
          ? depth < previousDepth.get()
          : true;
    }
  }
}
