/*
 * 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 com.google.gwt.emultest.java.util.EmulTestBase;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.Iterator;
import java.util.List;
import java.util.OptionalDouble;
import java.util.Spliterator;
import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
import java.util.stream.DoubleStream;
import java.util.stream.Stream;

/**
 * Tests {@link DoubleStream}.
 */
public class DoubleStreamTest extends EmulTestBase {

  public void testEmptyStream() {
    DoubleStream empty = DoubleStream.empty();
    assertEquals(0, empty.count());
    try {
      empty.count();
      fail("second terminal operation should have thrown IllegalStateEx");
    } catch (IllegalStateException expected) {
      // expected
    }

    assertEquals(0, DoubleStream.empty().limit(2).toArray().length);
    assertEquals(0L, DoubleStream.empty().count());
    assertEquals(0L, DoubleStream.empty().limit(2).count());

    assertFalse(DoubleStream.empty().findFirst().isPresent());
    assertFalse(DoubleStream.empty().findAny().isPresent());
    assertFalse(DoubleStream.empty().max().isPresent());
    assertFalse(DoubleStream.empty().min().isPresent());
    assertTrue(DoubleStream.empty().noneMatch(item -> true));
    assertTrue(DoubleStream.empty().allMatch(item -> true));
    assertFalse(DoubleStream.empty().anyMatch(item -> true));
    assertEquals(new double[0], DoubleStream.empty().toArray());
  }

  public void testStreamOfOne() {
    Supplier<DoubleStream> one = () -> DoubleStream.of(1);
    assertEquals(new double[] {1d}, one.get().toArray());
    assertEquals(1L, one.get().count());
    assertEquals(1d, one.get().findFirst().getAsDouble(), 0d);
    assertEquals(1d, one.get().findAny().getAsDouble(), 0d);
  }

  public void testBuilder() {
    DoubleStream s = DoubleStream.builder().add(1d).add(3d).add(2d).build();

    assertEquals(new double[] {1d, 3d, 2d}, s.toArray());

    DoubleStream.Builder builder = DoubleStream.builder();
    DoubleStream built = builder.build();
    assertEquals(0, built.count());
    try {
      builder.build();
      fail("build() after build() should fail");
    } catch (IllegalStateException expected) {
      // expected
    }
    try {
      builder.add(10d);
      fail("add() after build() should fail");
    } catch (IllegalStateException expected) {
      // expected
    }
  }

  public void testConcat() {
    Supplier<DoubleStream> adbc =
        () -> {
          return DoubleStream.concat(DoubleStream.of(1, 4), DoubleStream.of(2, 3));
        };

    assertEquals(new double[] {1d, 4d, 2d, 3d}, adbc.get().toArray());
    assertEquals(new double[] {1d, 2d, 3d, 4d}, adbc.get().sorted().toArray());

    List<String> closed = new ArrayList<>();
    DoubleStream first = DoubleStream.of(1d).onClose(() -> closed.add("first"));
    DoubleStream second = DoubleStream.of(2d).onClose(() -> closed.add("second"));

    DoubleStream concat = DoubleStream.concat(first, second);

    // read everything, make sure we saw it all and didn't close automatically
    double collectedAll = concat.sum();
    assertEquals(3d, collectedAll);
    assertEquals(0, closed.size());

    concat.close();
    assertEquals(Arrays.asList("first", "second"), closed);
  }

  public void testIterate() {
    assertEquals(
        new double[] {10d, 11d, 12d, 13d, 14d},
        DoubleStream.iterate(0d, l -> l + 1d).skip(10).limit(5).toArray());
  }

  public void testGenerate() {
    // infinite, but if you limit it is already too short to skip much
    assertEquals(new double[0], DoubleStream.generate(makeGenerator()).limit(4).skip(5).toArray());

    assertEquals(
        new double[] {10d, 11d, 12d, 13d, 14d},
        DoubleStream.generate(makeGenerator()).skip(10).limit(5).toArray());
  }

  private DoubleSupplier makeGenerator() {
    return new DoubleSupplier() {
      double next = 0d;

      @Override
      public double getAsDouble() {
        return next++;
      }
    };
  }

  public void testToArray() {
    assertEquals(new double[0], DoubleStream.of().toArray());
    assertEquals(new double[] {1d}, DoubleStream.of(1d).toArray());
    assertEquals(new double[] {3d, 2d, 0d}, DoubleStream.of(3d, 2d, 0d).toArray());
  }

  public void testReduce() {
    double reduced = DoubleStream.of(1d, 2d, 4d).reduce(0, Double::sum);
    assertEquals(7d, reduced, 0d);

    reduced = DoubleStream.of().reduce(0, Double::sum);
    assertEquals(0d, reduced, 0d);

    OptionalDouble maybe = DoubleStream.of(1d, 4d, 8d).reduce(Double::sum);
    assertTrue(maybe.isPresent());
    assertEquals(13, maybe.getAsDouble(), 0d);
    maybe = DoubleStream.of().reduce(Double::sum);
    assertFalse(maybe.isPresent());
  }

  public void testFilter() {
    // unconsumed stream never runs filter
    boolean[] data = {false};
    DoubleStream.of(1d, 2d, 3d).filter(i -> data[0] |= true);
    assertFalse(data[0]);

    // one result
    assertEquals(
        new double[] {1d}, DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> a == 1).toArray());
    // zero results
    assertEquals(new double[0], DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> false).toArray());
    // two results
    assertEquals(
        new double[] {2d, 4d},
        DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> a % 2 == 0).toArray());
    // all
    assertEquals(
        new double[] {1d, 2d, 3d, 4d, 3d},
        DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> true).toArray());
  }

  public void testMap() {
    // unconsumed stream never runs map
    int[] data = {0};
    DoubleStream.of(1d, 2d, 3d).map(i -> data[0]++);
    assertEquals(0, data[0]);

    assertEquals(new double[] {2d, 4d, 6d}, DoubleStream.of(1d, 2d, 3d).map(i -> i * 2).toArray());
  }

  public void testPeek() {
    // unconsumed stream never peeks
    boolean[] data = {false};
    DoubleStream.of(1d, 2d, 3d).peek(i -> data[0] |= true);
    assertFalse(data[0]);

    // make sure we saw it all in order
    double[] items = new double[] {1d, 2d, 3d};
    List<Double> peeked = new ArrayList<>();
    DoubleStream.of(items)
        .peek(peeked::add)
        .forEach(
            item -> {
              // do nothing, just run
            });
    assertEquals(items.length, peeked.size());
    for (int i = 0; i < items.length; i++) {
      assertEquals(items[i], peeked.get(i), 0d);
    }
  }

  // same impl, no parallel in browser
  public void testFindFirstOrAny() {
    OptionalDouble any = DoubleStream.of(1d, 2d).findAny();
    assertTrue(any.isPresent());
    assertEquals(1d, any.getAsDouble(), 0d);
  }

  public void testAnyMatch() {
    // all
    assertTrue(DoubleStream.of(1d, 2d).anyMatch(s -> true));

    // some
    assertTrue(DoubleStream.of(1d, 2d).anyMatch(s -> s == 1d));

    // none
    assertFalse(DoubleStream.of(1d, 2d).anyMatch(s -> false));
  }

  public void testAllMatch() {
    // all
    assertTrue(DoubleStream.of(1d, 2d).allMatch(s -> true));

    // some
    assertFalse(DoubleStream.of(1d, 2d).allMatch(s -> s == 1d));

    // none
    assertFalse(DoubleStream.of(1d, 2d).allMatch(s -> false));
  }

  public void testNoneMatch() {
    // all
    assertFalse(DoubleStream.of(1d, 2d).noneMatch(s -> true));

    // some
    assertFalse(DoubleStream.of(1d, 2d).noneMatch(s -> s == 1d));

    // none
    assertTrue(DoubleStream.of(1d, 2d).noneMatch(s -> false));
  }

  public void testFlatMap() {
    assertEquals(0L, DoubleStream.empty().flatMap(value -> DoubleStream.of(1d)).count());
    assertEquals(0L, DoubleStream.of(1d).flatMap(value -> DoubleStream.empty()).count());
    assertEquals(0L, DoubleStream.of(1d).flatMap(value -> DoubleStream.of()).count());
    assertEquals(0L, DoubleStream.of().flatMap(value -> DoubleStream.of(1d)).count());
    assertEquals(1L, DoubleStream.of(1d).flatMap(value -> DoubleStream.of(1d)).count());

    DoubleStream values = DoubleStream.of(1d, 2d, 3d);

    assertEquals(
        new double[] {1d, 2d, 2d, 4d, 3d, 6d},
        values.flatMap(i -> DoubleStream.of(i, i * 2d)).toArray());
  }

  public void testMapToOthers() {
    Supplier<DoubleStream> s = () -> DoubleStream.of(1d, 2d, 10d);

    assertEquals(
        new String[] {"1", "2", "10"},
        s.get().mapToObj(DoubleStreamTest::toIntegralString).toArray(String[]::new));

    assertEquals(new long[] {1L, 2L, 10L}, s.get().mapToLong(i -> (long) i).toArray());

    assertEquals(new int[] {1, 2, 10}, s.get().mapToInt(i -> (int) i).toArray());
  }

  public void testDistinct() {
    double[] distinct = DoubleStream.of(1d, 2d, 3d, 2d).distinct().toArray();
    assertEquals(3, distinct.length);
    assertEquals(1d + 2d + 3d, distinct[0] + distinct[1] + distinct[2], 0d);
  }

  public void testSorted() {
    double[] sorted = DoubleStream.of(3d, 1d, 2d).sorted().toArray();
    assertEquals(new double[] {1d, 2d, 3d}, sorted);
  }

  public void testMinMax() {
    Supplier<DoubleStream> stream = () -> DoubleStream.of(2d, 3d, 4d, 1d);

    assertEquals(1d, stream.get().min().orElse(0), 0d);
    assertEquals(4d, stream.get().max().orElse(0), 0d);

    assertFalse(stream.get().filter(a -> false).max().isPresent());
    assertFalse(stream.get().filter(a -> false).min().isPresent());
  }

  public void testCountLimitSkip() {
    Supplier<DoubleStream> stream = () -> DoubleStream.of(1d, 2d, 3d, 4d);

    assertEquals(4L, stream.get().count());

    assertEquals(4L, stream.get().limit(4).count());
    assertEquals(4L, stream.get().limit(5).count());
    assertEquals(3L, stream.get().limit(3).count());

    assertEquals(3L, stream.get().skip(1).limit(3).count());

    assertEquals(2L, stream.get().limit(3).skip(1).count());

    assertEquals(1L, stream.get().skip(3).count());

    assertEquals(new double[] {3d, 4d}, stream.get().skip(2).limit(3).toArray());
    assertEquals(new double[] {3d}, stream.get().skip(2).limit(1).toArray());

    assertEquals(new double[] {4d}, stream.get().skip(3).toArray());
    assertEquals(new double[] {}, stream.get().skip(5).toArray());

    assertEquals(new double[] {1d, 2d}, stream.get().limit(2).toArray());

    assertEquals(new double[] {2d}, stream.get().limit(2).skip(1).toArray());
  }

  public void testBoxed() {
    Supplier<DoubleStream> stream = () -> DoubleStream.of(1d, 2d);
    Stream<Double> expected = stream.get().mapToObj(Double::valueOf);
    assertEquals(expected.toArray(), stream.get().boxed().toArray());
  }

  public void testSummaryStats() {
    Supplier<DoubleStream> stream = () -> DoubleStream.of(1d, 2d, 3d);
    DoubleSummaryStatistics summaryStats = stream.get().summaryStatistics();
    assertEquals(3L, summaryStats.getCount());
    assertEquals(1d, summaryStats.getMin(), 0d);
    assertEquals(2d, summaryStats.getAverage(), 0d);
    assertEquals(3d, summaryStats.getMax(), 0d);
    assertEquals(6d, summaryStats.getSum(), 0d);

    summaryStats.accept(6L);
    assertEquals(4L, summaryStats.getCount());
    assertEquals(1d, summaryStats.getMin(), 0d);
    assertEquals(3d, summaryStats.getAverage(), 0d);
    assertEquals(6d, summaryStats.getMax(), 0d);
    assertEquals(12d, summaryStats.getSum(), 0d);

    DoubleSummaryStatistics combinedSumStats = stream.get().summaryStatistics();
    combinedSumStats.combine(DoubleStream.of(4d, 5d, 6d, 0d).summaryStatistics());
    assertEquals(7L, combinedSumStats.getCount());
    assertEquals(0d, combinedSumStats.getMin(), 0d);
    assertEquals(3d, combinedSumStats.getAverage(), 0d);
    assertEquals(6d, combinedSumStats.getMax(), 0d);
    assertEquals(21d, combinedSumStats.getSum(), 0d);
  }

  public void testAverage() {
    assertFalse(DoubleStream.empty().average().isPresent());
    assertEquals(2.0d, DoubleStream.of(1d, 2d, 3d).average().getAsDouble(), 0d);
    assertEquals(0d, DoubleStream.of(1d, 2d, -3d).average().getAsDouble(), 0d);
    assertEquals(-2.0d, DoubleStream.of(-1d, -2d, -3d).average().getAsDouble(), 0d);
  }

  public void testSum() {
    assertEquals(6d, DoubleStream.of(1d, 2d, 3d).sum(), 0d);
    assertEquals(0d, DoubleStream.of(1d, 2d, -3d).sum(), 0d);
    assertEquals(-6d, DoubleStream.of(-1d, -2d, -3d).sum(), 0d);
  }

  public void testCollect() {
    // noinspection StringConcatenationInsideStringBufferAppend
    String val =
        DoubleStream.of(1d, 2d, 3d, 4d, 5d)
            .collect(
                StringBuilder::new,
                (stringBuilder, d) -> stringBuilder.append(toIntegralString(d)),
                StringBuilder::append)
            .toString();

    assertEquals("12345", val);
  }

  public void testForEach() {
    List<Double> vals = new ArrayList<>();
    DoubleStream.of(1d, 2d, 3d, 4d, 5d).forEach(vals::add);
    assertEquals(5, vals.size());
    assertEquals(new Double[] {1d, 2d, 3d, 4d, 5d}, vals.toArray(new Double[vals.size()]));
  }

  public void testIterator() {
    List<Double> vals = new ArrayList<>();
    Iterator<Double> iterator = DoubleStream.of(1d, 2d, 3d, 4d, 5d).iterator();
    while (iterator.hasNext()) {
      vals.add(iterator.next());
    }
    assertEquals(5, vals.size());
    assertEquals(new Double[] {1d, 2d, 3d, 4d, 5d}, vals.toArray(new Double[vals.size()]));
  }

  public void testSpliterator() {
    Spliterator<Double> spliterator = DoubleStream.of(1d, 2d, 3d, 4d, 5d).spliterator();
    assertEquals(5, spliterator.estimateSize());
    assertEquals(5, spliterator.getExactSizeIfKnown());

    List<Double> vals = new ArrayList<>();
    while (spliterator.tryAdvance(vals::add)) {
      // work is all done in the condition
    }

    assertEquals(5, vals.size());
    assertEquals(new Double[] {1d, 2d, 3d, 4d, 5d}, vals.toArray(new Double[vals.size()]));
  }

  // See https://github.com/gwtproject/gwt/issues/8615
  private static String toIntegralString(double value) {
    return "" + (int) value;
  }
}
