// Copyright 2014 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.collect;

import com.google.common.base.Preconditions;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;
import com.google.common.primitives.Ints;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;

/**
 * A immutable multimap implementation for multimaps with comparable keys. It uses a sorted array
 * and binary search to return the correct values. It's only purpose is to save memory - it consumes
 * only about half the memory of the equivalent ImmutableListMultimap. Only a few methods are
 * efficiently implemented: {@link #isEmpty} is O(1), {@link #get} and {@link #containsKey} are
 * O(log(n)), and {@link #asMap} and {@link #values} refer to the parent instance. All other methods
 * can take O(n) or even make a copy of the contents.
 *
 * <p>This implementation supports neither {@code null} keys nor {@code null} values.
 */
public final class ImmutableSortedKeyListMultimap<K extends Comparable<K>, V>
    implements ListMultimap<K, V> {

  @SuppressWarnings({"rawtypes", "unchecked"})
  private static final ImmutableSortedKeyListMultimap EMPTY_MULTIMAP =
      new ImmutableSortedKeyListMultimap(new Comparable<?>[0], new List<?>[0]);

  /** Returns the empty multimap. */
  @SuppressWarnings("unchecked")
  public static <K extends Comparable<K>, V> ImmutableSortedKeyListMultimap<K, V> of() {
    // Safe because the multimap will never hold any elements.
    return EMPTY_MULTIMAP;
  }

  @SuppressWarnings("unchecked")
  public static <K extends Comparable<K>, V> ImmutableSortedKeyListMultimap<K, V> copyOf(
      Multimap<K, V> data) {
    if (data.isEmpty()) {
      return EMPTY_MULTIMAP;
    }
    if (data instanceof ImmutableSortedKeyListMultimap) {
      return (ImmutableSortedKeyListMultimap<K, V>) data;
    }
    Set<K> keySet = data.keySet();
    int size = keySet.size();
    K[] sortedKeys = (K[]) new Comparable<?>[size];
    int index = 0;
    for (K key : keySet) {
      sortedKeys[index++] = Preconditions.checkNotNull(key);
    }
    Arrays.sort(sortedKeys);
    List<V>[] values = (List<V>[]) new List<?>[size];
    for (int i = 0; i < size; i++) {
      values[i] = ImmutableList.copyOf(data.get(sortedKeys[i]));
    }
    return new ImmutableSortedKeyListMultimap<>(sortedKeys, values);
  }

  public static <K extends Comparable<K>, V> Builder<K, V> builder() {
    return new Builder<>();
  }

  /**
   * A builder class for ImmutableSortedKeyListMultimap<K, V> instances.
   */
  public static final class Builder<K extends Comparable<K>, V> {
    private final Multimap<K, V> builderMultimap = ArrayListMultimap.create();

    Builder() {
      // Not public so you must call builder() instead.
    }

    public ImmutableSortedKeyListMultimap<K, V> build() {
      return ImmutableSortedKeyListMultimap.copyOf(builderMultimap);
    }

    public Builder<K, V> put(K key, V value) {
      builderMultimap.put(Preconditions.checkNotNull(key), Preconditions.checkNotNull(value));
      return this;
    }

    public Builder<K, V> putAll(K key, Collection<? extends V> values) {
      Collection<V> valueList = builderMultimap.get(Preconditions.checkNotNull(key));
      for (V value : values) {
        valueList.add(Preconditions.checkNotNull(value));
      }
      return this;
    }

    @SuppressWarnings("unchecked")
    public Builder<K, V> putAll(K key, V... values) {
      return putAll(Preconditions.checkNotNull(key), Arrays.asList(values));
    }

    public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) {
      multimap.asMap().forEach((key, collectionValue) -> putAll(key, collectionValue));
      return this;
    }
  }

  /**
   * An implementation for the Multimap.asMap method. Note that AbstractMap already provides
   * implementations for all methods except {@link #entrySet}, but we override a few here because we
   * can do it much faster than the existing entrySet-based implementations. Also note that it
   * inherits the type parameters K and V from the parent class.
   */
  private class AsMap extends AbstractMap<K, Collection<V>> {

    AsMap() {
    }

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

    @Override
    public boolean containsKey(Object key) {
      return ImmutableSortedKeyListMultimap.this.containsKey(key);
    }

    @Override
    public Collection<V> get(Object key) {
      int index = Arrays.binarySearch(sortedKeys, key);
      // Note the different semantic between Map and Multimap.
      return index >= 0 ? values[index] : null;
    }

    @Override
    public Collection<V> remove(Object key) {
      throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
      throw new UnsupportedOperationException();
    }

    @Override
    public Set<Map.Entry<K, Collection<V>>> entrySet() {
      ImmutableSet.Builder<Map.Entry<K, Collection<V>>> builder = ImmutableSet.builder();
      for (int i = 0; i < sortedKeys.length; i++) {
        builder.add(new SimpleImmutableEntry<>(sortedKeys[i], values[i]));
      }
      return builder.build();
    }
  }

  private class ValuesCollection extends AbstractCollection<V> {

    ValuesCollection() {
    }

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

    @Override
    public boolean isEmpty() {
      return sortedKeys.length == 0;
    }

    @Override
    public boolean contains(Object o) {
      return ImmutableSortedKeyListMultimap.this.containsValue(o);
    }

    @Override
    public Iterator<V> iterator() {
      if (isEmpty()) {
        return Collections.emptyIterator();
      }
      return new AbstractIterator<V>() {
        private int currentList = 0;
        private int currentIndex = 0;

        @Override
        protected V computeNext() {
          if (currentList >= values.length) {
            return endOfData();
          }
          V result = values[currentList].get(currentIndex);
          // Find the next list/index pair.
          currentIndex++;
          if (currentIndex >= values[currentList].size()) {
            currentIndex = 0;
            currentList++;
          }
          return result;
        }
      };
    }

    @Override
    public boolean remove(Object o) {
      throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeAll(Collection<?> c) {
      throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection<?> c) {
      throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
      throw new UnsupportedOperationException();
    }
  }

  private final K[] sortedKeys;
  private final List<V>[] values;

  private ImmutableSortedKeyListMultimap(K[] sortedKeys, List<V>[] values) {
    this.sortedKeys = sortedKeys;
    this.values = values;
  }

  @Override
  public int size() {
    return Ints.saturatedCast(Arrays.stream(values).mapToLong(List::size).sum());
  }

  @Override
  public boolean isEmpty() {
    return sortedKeys.length == 0;
  }

  @Override
  public boolean containsKey(Object key) {
    int index = Arrays.binarySearch(sortedKeys, key);
    return index >= 0;
  }

  @Override
  public boolean containsValue(Object value) {
    return Arrays.stream(values).anyMatch(list -> list.contains(value));
  }

  @Override
  public boolean containsEntry(Object key, Object value) {
    int index = Arrays.binarySearch(sortedKeys, key);
    return index >= 0 && values[index].contains(value);
  }

  @Override
  public boolean put(K key, V value) {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean remove(Object key, Object value) {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean putAll(K key, Iterable<? extends V> values) {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
    throw new UnsupportedOperationException();
  }

  @Override
  public List<V> replaceValues(K key, Iterable<? extends V> values) {
    throw new UnsupportedOperationException();
  }

  @Override
  public List<V> removeAll(Object key) {
    throw new UnsupportedOperationException();
  }

  @Override
  public void clear() {
    throw new UnsupportedOperationException();
  }

  @Override
  public List<V> get(K key) {
    int index = Arrays.binarySearch(sortedKeys, key);
    return index >= 0 ? values[index] : ImmutableList.of();
  }

  @Override
  public Set<K> keySet() {
    return ImmutableSet.copyOf(sortedKeys);
  }

  @Override
  public Multiset<K> keys() {
    return ImmutableMultiset.copyOf(sortedKeys);
  }

  @Override
  public Collection<V> values() {
    return new ValuesCollection();
  }

  @Override
  public Collection<Map.Entry<K, V>> entries() {
    ImmutableList.Builder<Map.Entry<K, V>> builder = ImmutableList.builder();
    for (int i = 0; i < sortedKeys.length; i++) {
      for (V value : values[i]) {
        builder.add(new SimpleImmutableEntry<>(sortedKeys[i], value));
      }
    }
    return builder.build();
  }

  /**
   * {@inheritDoc}
   *
   * <p>Note that only {@code get} and {@code containsKey} are implemented efficiently on the
   * returned map.
   */
  @Override
  public Map<K, Collection<V>> asMap() {
    return new AsMap();
  }

  @Override
  public String toString() {
    return asMap().toString();
  }

  @Override
  public int hashCode() {
    return asMap().hashCode();
  }

  @Override
  public boolean equals(@Nullable Object object) {
    if (this == object) {
      return true;
    }
    if (object instanceof Multimap) {
      Multimap<?, ?> that = (Multimap<?, ?>) object;
      return asMap().equals(that.asMap());
    }
    return false;
  }
}
