package throwing.stream;

import java.util.Optional;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.Collector;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

import throwing.ThrowingComparator;
import throwing.bridge.ThrowingBridge;
import throwing.function.ThrowingBiConsumer;
import throwing.function.ThrowingBiFunction;
import throwing.function.ThrowingBinaryOperator;
import throwing.function.ThrowingConsumer;
import throwing.function.ThrowingFunction;
import throwing.function.ThrowingPredicate;
import throwing.function.ThrowingSupplier;
import throwing.function.ThrowingToDoubleFunction;
import throwing.function.ThrowingToIntFunction;
import throwing.function.ThrowingToLongFunction;

/**
 * A mirror of {@link Stream}. A {@link Stream} allows for functions to be
 * lazily applied to it. A {@link ThrowingStream} allows for these functions to
 * also throw checked exceptions. Since a terminal operation on a {@link Stream}
 * (with the exception of {@code iterator} and {@code spliterator}, which are
 * lazy terminal operations) applied all of the functions, and since one of
 * those functions may throw an exception, each terminal operation in a
 * {@code ThrowingStream} declares a thrown exception.
 * 
 * @author jeffrey
 *
 * @param <T>
 *            The type of the stream elements
 * @param <X>
 *            The type of the exception that might be thrown
 */
public interface ThrowingStream<T, X extends Throwable> extends ThrowingBaseStream<T, X, ThrowingStream<T, X>> {
    public ThrowingStream<T, X> filter(ThrowingPredicate<? super T, ? extends X> predicate);

    public <R> ThrowingStream<R, X> map(ThrowingFunction<? super T, ? extends R, ? extends X> mapper);

    public ThrowingIntStream<X> mapToInt(ThrowingToIntFunction<? super T, ? extends X> mapper);

    public ThrowingLongStream<X> mapToLong(ThrowingToLongFunction<? super T, ? extends X> mapper);

    public ThrowingDoubleStream<X> mapToDouble(ThrowingToDoubleFunction<? super T, ? extends X> mapper);

    public <R> ThrowingStream<R, X> flatMap(
            ThrowingFunction<? super T, ? extends ThrowingStream<? extends R, ? extends X>, ? extends X> mapper);

    public ThrowingIntStream<X> flatMapToInt(
            ThrowingFunction<? super T, ? extends ThrowingIntStream<? extends X>, ? extends X> mapper);

    public ThrowingLongStream<X> flatMapToLong(
            ThrowingFunction<? super T, ? extends ThrowingLongStream<? extends X>, ? extends X> mapper);

    public ThrowingDoubleStream<X> flatMapToDouble(
            ThrowingFunction<? super T, ? extends ThrowingDoubleStream<? extends X>, ? extends X> mapper);

    public ThrowingStream<T, X> distinct();

    public ThrowingStream<T, X> sorted();

    public ThrowingStream<T, X> sorted(ThrowingComparator<? super T, ? extends X> comparator);

    public ThrowingStream<T, X> peek(ThrowingConsumer<? super T, ? extends X> action);

    public ThrowingStream<T, X> limit(long maxSize);

    public ThrowingStream<T, X> skip(long n);

    public void forEach(ThrowingConsumer<? super T, ? extends X> action) throws X;

    public void forEachOrdered(ThrowingConsumer<? super T, ? extends X> action) throws X;

    public Object[] toArray() throws X;

    public <A> A[] toArray(IntFunction<A[]> generator) throws X;

    public T reduce(T identity, ThrowingBinaryOperator<T, ? extends X> accumulator) throws X;

    public Optional<T> reduce(ThrowingBinaryOperator<T, ? extends X> accumulator) throws X;

    public <U> U reduce(U identity, ThrowingBiFunction<U, ? super T, U, ? extends X> accumulator,
            ThrowingBinaryOperator<U, ? extends X> combiner) throws X;

    public <R> R collect(ThrowingSupplier<R, ? extends X> supplier,
            ThrowingBiConsumer<R, ? super T, ? extends X> accumulator, ThrowingBiConsumer<R, R, ? extends X> combiner)
        throws X;

    public <R, A> R collect(ThrowingCollector<? super T, A, R, ? extends X> collector) throws X;

    default public <R, A> R collect(Collector<? super T, A, R> collector) throws X {
        return collect(ThrowingBridge.of(collector));
    }

    public Optional<T> min(ThrowingComparator<? super T, ? extends X> comparator) throws X;

    public Optional<T> max(ThrowingComparator<? super T, ? extends X> comparator) throws X;

    public long count() throws X;

    public boolean anyMatch(ThrowingPredicate<? super T, ? extends X> predicate) throws X;

    public boolean allMatch(ThrowingPredicate<? super T, ? extends X> predicate) throws X;

    public boolean noneMatch(ThrowingPredicate<? super T, ? extends X> predicate) throws X;

    public Optional<T> findFirst() throws X;

    public Optional<T> findAny() throws X;

    /**
     * Returns a stream which will only throw Y and will rethrow any X as Y as
     * specified by the mapper.
     * 
     * This is an intermediate operation.
     * 
     * @param y
     *            The new exception class
     * @param mapper
     *            A way to convert X exceptions to Ys
     * @return the new stream
     */
    public <Y extends Throwable> ThrowingStream<T, Y> rethrow(Class<Y> y, Function<? super X, ? extends Y> mapper);

    public static <T, X extends Throwable> ThrowingStream<T, X> of(Stream<T> stream, Class<X> x) {
        return ThrowingBridge.of(stream, x);
    }

    public static <X extends Throwable> ThrowingIntStream<X> of(IntStream stream, Class<X> x) {
        return ThrowingBridge.of(stream, x);
    }

    public static <X extends Throwable> ThrowingLongStream<X> of(LongStream stream, Class<X> x) {
        return ThrowingBridge.of(stream, x);
    }

    public static <X extends Throwable> ThrowingDoubleStream<X> of(DoubleStream stream, Class<X> x) {
        return ThrowingBridge.of(stream, x);
    }
}

@@ -847,17 +847,16 @@
 * A 
-mirror of
+standard
  %7B@l
@@ -870,155 +870,141 @@
 eam%7D
-. A %7B@link Stream%7D allows for functions to be%0A * lazily applied to it. A %7B@link ThrowingStream%7D allows for these functions to%0A * also throw
+ does not allow you to throw any checked exceptions.%0A * This class is a mirror of %7B@code Stream%7D except this class allows for
  checked
  exc
@@ -991,32 +991,35 @@
 lows for checked
+%0A *
  exceptions. Sin
@@ -1019,335 +1019,257 @@
 ns. 
-Since a terminal operation on a %7B@link Stream%7D%0A * (with the exception of %7B@code iterator%7D and %7B@code spliterator%7D, which are%0A * lazy terminal operations) applied all of the functions, and since one of%0A * those functions may throw an exception, each terminal operation in a%0A * %7B@code ThrowingStream%7D declares a thrown exception.
+Each method in the exception-free API has its mirror here using%0A * interfaces which support exceptions. There are also helper methods such as%0A * %7B@link #rethrow(Class, Function)%7D.%0A * %0A * %3Cbr%3E%3Cbr%3E%0A * %0A * Each terminal operation may throw an %7B@code X%7D
 %0A * 

improve documentation