/*
 * Copyright 2016 Google Inc.
 *
 * 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.gwt.emultest.java8.util.stream;

import static java.util.stream.Collectors.averagingDouble;
import static java.util.stream.Collectors.averagingInt;
import static java.util.stream.Collectors.averagingLong;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.minBy;
import static java.util.stream.Collectors.partitioningBy;
import static java.util.stream.Collectors.summarizingDouble;
import static java.util.stream.Collectors.summarizingInt;
import static java.util.stream.Collectors.summarizingLong;
import static java.util.stream.Collectors.summingDouble;
import static java.util.stream.Collectors.summingInt;
import static java.util.stream.Collectors.summingLong;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

import com.google.gwt.emultest.java.util.EmulTestBase;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IntSummaryStatistics;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.LongSummaryStatistics;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * Tests {@link java.util.stream.Collectors}.
 * <p />
 * Methods that are presently only tested indirectly:
 * <ul>
 *   <li>reducing: counting, minBy/maxBy use this</li>
 *   <li>toCollection tested by toList (toSet now uses its own impl)</li>
 * </ul>
 */
public class CollectorsTest extends EmulTestBase {

  public void testAveragingDouble() {
    Collector<Double, ?, Double> c = averagingDouble(Double::doubleValue);
    applyItems((4.0 + 8.0) / 2.0, c, 4.0, 8.0);

    assertZeroItemsCollectedAs(0D, c);
    assertSingleItemCollectedAs(5D, c, 5D);
  }

  public void testAveragingInt() {
    Collector<Integer, ?, Double> c = averagingInt(Integer::intValue);
    applyItems((4.0 + 8.0) / 2.0, c, 4, 8);

    assertZeroItemsCollectedAs(0D, c);
    assertSingleItemCollectedAs(5D, c, 5);
  }

  public void testAveragingLong() {
    Collector<Long, ?, Double> c = averagingLong(Long::longValue);
    applyItems((4.0 + 8.0) / 2.0, c, 4L, 8L);

    assertZeroItemsCollectedAs(0D, c);
    assertSingleItemCollectedAs(5D, c, 5L);
  }

  public void testCollectingAndThen() {
    Collector<Object, ?, List<Object>> listIdentityCollector =
        collectingAndThen(toList(), Function.identity());
    // same test as toList():
    // same items (allow dups)
    applyItems(
        Arrays.asList("a", "a"),
        listIdentityCollector,
        "a", "a"
    );

    // ordered
    applyItems(
        Arrays.asList("a", "b"),
        listIdentityCollector,
        "a", "b"
    );
    assertZeroItemsCollectedAs(Collections.emptyList(), listIdentityCollector);
    assertSingleItemCollectedAs(Collections.singletonList("a"), listIdentityCollector, "a");

    Collector<Object, ?, Integer> uglyCount = collectingAndThen(toList(), List::size);
    // (nearly) same test as counting():
    applyItems(2, uglyCount, "1", new Object());

    assertZeroItemsCollectedAs(0, uglyCount);
    assertSingleItemCollectedAs(1, uglyCount, new Object());
  }

  public void testCounting() {
    Collector<Object, ?, Long> c = counting();
    applyItems(2L, c, "1", new Object());

    assertZeroItemsCollectedAs(0L, c);
    assertSingleItemCollectedAs(1L, c, new Object());
  }

  public void testGroupingBy() {
    Collector<String, ?, Map<String, List<String>>> c1 = groupingBy(Function.identity());

    Map<String, List<String>> mapOfLists = new HashMap<>();
    mapOfLists.put("a", Arrays.asList("a", "a"));
    applyItems(mapOfLists, c1, "a", "a");
    mapOfLists.clear();
    mapOfLists.put("a", Collections.singletonList("a"));
    mapOfLists.put("b", Collections.singletonList("b"));
    applyItems(mapOfLists, c1, "a", "b");

    assertZeroItemsCollectedAs(Collections.emptyMap(), c1);
    assertSingleItemCollectedAs(
        Collections.singletonMap("a", Collections.singletonList("a")), c1, "a");

    Collector<String, ?, LinkedHashMap<String, Set<String>>> c2 =
        groupingBy(Function.identity(), LinkedHashMap::new, toSet());

    LinkedHashMap<String, Set<String>> linkedMapOfSets = new LinkedHashMap<>();
    linkedMapOfSets.put("a", Collections.singleton("a"));
    applyItems(linkedMapOfSets, c2, "a", "a");
    linkedMapOfSets.clear();
    linkedMapOfSets.put("a", Collections.singleton("a"));
    linkedMapOfSets.put("b", Collections.singleton("b"));
    applyItems(linkedMapOfSets, c2, "a", "b");

    // check to make sure we actually get the linked results, and that they are ordered how we want
    // them
    LinkedHashMap<String, Set<String>> out = applyItemsWithoutSplitting(c2, "a", "b");
    assertEquals(Arrays.asList("a", "b"), new ArrayList<>(out.keySet()));
    out = applyItemsWithoutSplitting(c2, "b", "a");
    assertEquals(Arrays.asList("b", "a"), new ArrayList<>(out.keySet()));

    assertZeroItemsCollectedAs(new LinkedHashMap<>(), c2);
    linkedMapOfSets.clear();
    linkedMapOfSets.put("a", Collections.singleton("a"));
    assertSingleItemCollectedAs(linkedMapOfSets, c2, "a");
  }

  public void testJoining() {
    Collector<CharSequence, ?, String> c = joining();
    applyItems("ab", c, "a", "b");
    applyItems("a,", c, "a", ",");
    applyItems("", c, "", "");
    assertZeroItemsCollectedAs("", c);
    assertSingleItemCollectedAs("a", c, "a");
    assertSingleItemCollectedAs("", c, "");

    c = joining(",");
    applyItems("a,b", c, "a", "b");
    applyItems("a,,", c, "a", ",");
    applyItems(",", c, "", "");
    assertZeroItemsCollectedAs("", c);
    assertSingleItemCollectedAs("a", c, "a");
    assertSingleItemCollectedAs("", c, "");

    c = joining("-", "{", "}");
    applyItems("{a-b}", c, "a", "b");
    assertZeroItemsCollectedAs("{}", c);
    assertSingleItemCollectedAs("{a}", c, "a");
    assertSingleItemCollectedAs("{}", c, "");
  }

  public void testMapping() {
    Collector<String, ?, List<String>> identityMapping = mapping(Function.identity(), toList());
    // same test as toList():
    // same items (allow dups)
    applyItems(
        Arrays.asList("a", "a"),
        identityMapping,
        "a", "a"
    );

    // ordered
    applyItems(
        Arrays.asList("a", "b"),
        identityMapping,
        "a", "b"
    );
    assertZeroItemsCollectedAs(Collections.emptyList(), identityMapping);
    assertSingleItemCollectedAs(Collections.singletonList("a"), identityMapping, "a");

    Collector<Integer, ?, List<String>> numberMapping = mapping(s -> "#" + s, toList());
    // poke the same tests as list, make sure the mapper is run
    applyItems(
        Arrays.asList("#1", "#2"),
        numberMapping,
        1, 2
    );

    // ordered
    applyItems(
        Arrays.asList("#1", "#2"),
        numberMapping,
        1, 2
    );
    assertZeroItemsCollectedAs(Collections.emptyList(), numberMapping);
    assertSingleItemCollectedAs(Collections.singletonList("#10"), numberMapping, 10);
  }

  public void testMaxBy() {
    Collector<String, ?, Optional<String>> c = maxBy(Comparator.naturalOrder());
    applyItems(Optional.of("z"), c, "a", "z");
    applyItems(Optional.of("z"), c, "z", "a");

    assertZeroItemsCollectedAs(Optional.empty(), c);
    assertSingleItemCollectedAs(Optional.of("foo"), c, "foo");
  }

  public void testMinBy() {
    Collector<String, ?, Optional<String>> c = minBy(Comparator.naturalOrder());
    applyItems(Optional.of("a"), c, "a", "z");
    applyItems(Optional.of("a"), c, "z", "a");

    assertZeroItemsCollectedAs(Optional.empty(), c);
    assertSingleItemCollectedAs(Optional.of("foo"), c, "foo");
  }

  public void testPartitioningBy() {
    Collector<Boolean, ?, Map<Boolean, List<Boolean>>> c1 = partitioningBy(Boolean::valueOf);

    Map<Boolean, List<Boolean>> mapOfLists = new HashMap<>();
    mapOfLists.put(true, Collections.singletonList(true));
    mapOfLists.put(false, Collections.singletonList(false));
    applyItems(mapOfLists, c1, true, false);

    mapOfLists.clear();
    mapOfLists.put(false, Collections.emptyList());
    mapOfLists.put(true, Arrays.asList(true, true));
    applyItems(mapOfLists, c1, true, true);

    mapOfLists.clear();
    mapOfLists.put(false, Arrays.asList(false, false));
    mapOfLists.put(true, Collections.emptyList());
    applyItems(mapOfLists, c1, false, false);

    mapOfLists.clear();
    mapOfLists.put(false, Collections.emptyList());
    mapOfLists.put(true, Collections.emptyList());
    assertZeroItemsCollectedAs(mapOfLists, c1);

    mapOfLists.clear();
    mapOfLists.put(false, Collections.emptyList());
    mapOfLists.put(true, Collections.singletonList(true));
    assertSingleItemCollectedAs(mapOfLists, c1, true);

    mapOfLists.clear();
    mapOfLists.put(false, Collections.singletonList(false));
    mapOfLists.put(true, Collections.emptyList());
    assertSingleItemCollectedAs(mapOfLists, c1, false);

    Collector<Boolean, ?, Map<Boolean, Set<Boolean>>> c2 =
        partitioningBy(Boolean::valueOf, toSet());

    Map<Boolean, Set<Boolean>> mapOfSets = new HashMap<>();
    mapOfSets.put(true, Collections.singleton(true));
    mapOfSets.put(false, Collections.singleton(false));
    applyItems(mapOfSets, c2, true, false);

    mapOfSets.clear();
    mapOfSets.put(false, Collections.emptySet());
    mapOfSets.put(true, Collections.singleton(true));
    applyItems(mapOfSets, c2, true, true);

    mapOfSets.clear();
    mapOfSets.put(false, Collections.singleton(false));
    mapOfSets.put(true, Collections.emptySet());
    applyItems(mapOfSets, c2, false, false);
  }

  public void testSummarizingDouble() {
    Collector<Double, ?, DoubleSummaryStatistics> c = summarizingDouble(Double::doubleValue);
    DoubleSummaryStatistics stats = new DoubleSummaryStatistics();
    stats.accept(5.1);
    stats.accept(7);
    BiPredicate<DoubleSummaryStatistics, DoubleSummaryStatistics> equals = (s1, s2) ->
        s1.getSum() == s2.getSum()
            && s1.getAverage() == s2.getAverage()
            && s1.getCount() == s2.getCount()
            && s1.getMin() == s2.getMin()
            && s1.getMax() == s2.getMax();
    applyItems(stats, c, 5.1, 7.0, equals);
    applyItems(stats, c, 7.0, 5.1, equals);//probably unnecessary to run these backward

    assertZeroItemsCollectedAs(new DoubleSummaryStatistics(), c, equals);
    stats = new DoubleSummaryStatistics();
    stats.accept(7.3);
    assertSingleItemCollectedAs(stats, c, 7.3, equals);
  }

  public void testSummarizingInt() {
    Collector<Integer, ?, IntSummaryStatistics> c = summarizingInt(Integer::intValue);
    IntSummaryStatistics stats = new IntSummaryStatistics();
    stats.accept(2);
    stats.accept(10);
    BiPredicate<IntSummaryStatistics, IntSummaryStatistics> equals = (s1, s2) ->
        s1.getSum() == s2.getSum()
            && s1.getAverage() == s2.getAverage()
            && s1.getCount() == s2.getCount()
            && s1.getMin() == s2.getMin()
            && s1.getMax() == s2.getMax();
    applyItems(stats, c, 2, 10, equals);
    applyItems(stats, c, 10, 2, equals);

    assertZeroItemsCollectedAs(new IntSummaryStatistics(), c, equals);
    stats = new IntSummaryStatistics();
    stats.accept(7);
    assertSingleItemCollectedAs(stats, c, 7, equals);
  }

  public void testSummarizingLong() {
    Collector<Long, ?, LongSummaryStatistics> c = summarizingLong(Long::longValue);
    LongSummaryStatistics stats = new LongSummaryStatistics();
    stats.accept(2);
    stats.accept(10);
    BiPredicate<LongSummaryStatistics, LongSummaryStatistics> equals = (s1, s2) ->
        s1.getSum() == s2.getSum()
            && s1.getAverage() == s2.getAverage()
            && s1.getCount() == s2.getCount()
            && s1.getMin() == s2.getMin()
            && s1.getMax() == s2.getMax();
    applyItems(stats, c, 2L, 10L, equals);
    applyItems(stats, c, 10L, 2L, equals);

    assertZeroItemsCollectedAs(new LongSummaryStatistics(), c, equals);
    stats = new LongSummaryStatistics();
    stats.accept(7L);
    assertSingleItemCollectedAs(stats, c, 7L, equals);
  }

  public void testSummingDouble() {
    Collector<Double, ?, Double> c = summingDouble(Double::doubleValue);
    applyItems(4.1 + 8.2, c, 4.1, 8.2);

    assertZeroItemsCollectedAs(0d, c);
    assertSingleItemCollectedAs(7.3, c, 7.3);
  }

  public void testSummingInt() {
    Collector<Integer, ?, Integer> c = summingInt(Integer::intValue);
    applyItems(4 + 8, c, 4, 8);

    assertZeroItemsCollectedAs(0, c);
    assertSingleItemCollectedAs(7, c, 7);
  }

  public void testSummingLong() {
    Collector<Long, ?, Long> c = summingLong(Long::longValue);
    applyItems(4L + 8L, c, 4L, 8L);

    assertZeroItemsCollectedAs(0L, c);
    assertSingleItemCollectedAs(5L, c, 5L);
  }

  public void testList() {
    Collector<String, ?, List<String>> c = toList();

    // same items (allow dups)
    applyItems(
        Arrays.asList("a", "a"),
        c,
        "a", "a"
    );

    // ordered
    applyItems(
        Arrays.asList("a", "b"),
        c,
        "a", "b"
    );
    assertZeroItemsCollectedAs(Collections.emptyList(), c);
    assertSingleItemCollectedAs(Collections.singletonList("a"), c, "a");
  }

  public void testMap() {
    Collector<String, ?, Map<String, String>> c = toMap(Function.identity(), Function.identity());

    // two distinct items
    Map<String, String> map = new HashMap<>();
    map.put("a", "a");
    map.put("b", "b");
    applyItems(map, c, "a", "b");

    // inline applyItems and test each to confirm failure for duplicates
    try {
      applyItemsWithoutSplitting(c, "a", "a");
      fail("expected IllegalStateException");
    } catch (IllegalStateException expected) {
    }
    try {
      applyItemsWithSplitting(c, "a", "a");
      fail("expected IllegalStateException");
    } catch (IllegalStateException expected) {
    }

    assertZeroItemsCollectedAs(Collections.emptyMap(), c);
    assertSingleItemCollectedAs(Collections.singletonMap("a", "a"), c, "a");

    List<String> seen = new ArrayList<>();
    c = toMap(Function.identity(), Function.identity(), (s, s2) -> {
      seen.add("first: " + s);
      seen.add("second: " + s2);
      return s + "," + s2;
    });
    map = new HashMap<>();
    map.put("a", "a,a");
    applyItems(map, c, "a", "a");
    assertEquals(Arrays.asList("first: a", "second: a", "first: a", "second: a"), seen);
  }

  public void testSet() {
    Collector<String, ?, Set<String>> c = toSet();

    // same items (no dups)
    applyItems(
        Collections.singleton("a"),
        c,
        "a", "a"
    );

    // different items
    applyItems(
        new HashSet<>(Arrays.asList("a", "b")),
        c,
        "a", "b"
    );

    assertZeroItemsCollectedAs(Collections.emptySet(), c);
    assertSingleItemCollectedAs(Collections.singleton("a"), c, "a");
  }

  /**
   * This method attempts to apply a collector to items as a stream might do, so that we can simply
   * verify the output. Taken from the Collector class's javadoc.
   */
  private static <T, A, R> void applyItems(
      R expected, Collector<T, A, R> collector, T t1, T t2, BiPredicate<R, R> equals) {
    assertTrue(
        "failed without splitting",
        equals.test(expected, applyItemsWithoutSplitting(collector, t1, t2)));
    assertTrue(
        "failed with splitting", equals.test(expected, applyItemsWithSplitting(collector, t1, t2)));
  }

  /**
   * This method attempts to apply a collector to items as a stream might do, so that we
   * can simply verify the output. Taken from the Collector class's javadoc.
   */
  private static <T, A, R> void applyItems(R expected, Collector<T, A, R> collector, T t1, T t2) {
    applyItems(expected, collector, t1, t2, Object::equals);
  }

  /**
   * Helper for applyItems.
   */
  private static <T, A, R> R applyItemsWithoutSplitting(Collector<T, A, R> collector, T t1, T t2) {
    Supplier<A> supplier = collector.supplier();
    BiConsumer<A, T> accumulator = collector.accumulator();
    // unused in this impl
    BinaryOperator<A> combiner = collector.combiner();
    Function<A, R> finisher = collector.finisher();

    A a1 = supplier.get();

    accumulator.accept(a1, t1);
    accumulator.accept(a1, t2);

    // result without splitting
    R r1 = finisher.apply(a1);
    return r1;
  }

  /**
   * Helper for applyItems.
   */
  private static <T, A, R> R applyItemsWithSplitting(Collector<T, A, R> collector, T t1, T t2) {
    Supplier<A> supplier = collector.supplier();
    BiConsumer<A, T> accumulator = collector.accumulator();
    // actually used in this impl
    BinaryOperator<A> combiner = collector.combiner();
    Function<A, R> finisher = collector.finisher();

    A a2 = supplier.get();
    accumulator.accept(a2, t1);
    A a3 = supplier.get();
    accumulator.accept(a3, t2);

    // result with splitting
    R r2 = finisher.apply(combiner.apply(a2, a3));
    return r2;
  }

  private static <T, A, R> void assertZeroItemsCollectedAs(
      R expected, Collector<T, A, R> collector) {
    assertZeroItemsCollectedAs(expected, collector, Object::equals);
  }

  private static <T, A, R> void assertZeroItemsCollectedAs(
      R expected, Collector<T, A, R> collector, BiPredicate<R, R> equals) {
    Supplier<A> supplier = collector.supplier();
    // unused in this impl
    BiConsumer<A, T> accumulator = collector.accumulator();
    // shouldn't really be used, just handy to poke the internals quick
    BinaryOperator<A> combiner = collector.combiner();
    Function<A, R> finisher = collector.finisher();

    R actual = finisher.apply(supplier.get());
    assertTrue(equals, expected, actual);
    // doesn't actually ever happen, just internal checks
    actual = finisher.apply(combiner.apply(supplier.get(), supplier.get()));
    assertTrue(equals, expected, actual);
  }

  private static <T, A, R> void assertSingleItemCollectedAs(
      R expected, Collector<T, A, R> collector, T item) {
    assertSingleItemCollectedAs(expected, collector, item, Object::equals);
  }

  private static <T, A, R> void assertSingleItemCollectedAs(
      R expected, Collector<T, A, R> collector, T item, BiPredicate<R, R> equals) {
    Supplier<A> supplier = collector.supplier();
    BiConsumer<A, T> accumulator = collector.accumulator();
    // shouldn't really be used, just handy to poke the internals quick
    BinaryOperator<A> combiner = collector.combiner();
    Function<A, R> finisher = collector.finisher();

    A a1 = supplier.get();

    accumulator.accept(a1, item);

    R actual = finisher.apply(a1);
    // normal test
    assertTrue(equals, expected, actual);
    // these shouldn't really be used, just handy to poke the internals quick
    actual = finisher.apply(combiner.apply(a1, supplier.get()));
    assertTrue(equals, expected, actual);
    actual = finisher.apply(combiner.apply(supplier.get(), a1));
    assertTrue(equals, expected, actual);
  }

  private static <T, U> void assertTrue(BiPredicate<T, U> predicate, T expected, U actual) {
    assertTrue("expected= " + expected + ", actual=" + actual, predicate.test(expected, actual));
  }

}
