package throwing.stream;

import java.util.Optional;
import java.util.function.IntFunction;
import java.util.stream.Collector;
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} normally allows for lazy
 * functions to be applied to is. A {@link ThrowingStream} allows for these
 * functions to throw checked exceptions. Any terminal operation has the
 * possibility of applying one of these lazy functions, so each stateful
 * intermediate operation and terminal operation 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;
}

@@ -744,17 +744,8 @@
 eam%7D
- normally
  all
@@ -755,16 +755,8 @@
  for
- lazy%0A *
  fun
@@ -767,16 +767,26 @@
 ns to be
+%0A * lazily
  applied
@@ -790,17 +790,17 @@
 ied to i
-s
+t
 . A %7B@li
@@ -851,16 +851,21 @@
 ions to 
+also 
 throw ch
@@ -882,19 +882,23 @@
 ptions. 
-Any
+Since a
  termina
@@ -913,137 +913,280 @@
 ion 
-has the%0A * possibility of applying one of these lazy functions, so each stateful%0A * intermediate operation and terminal operation
+on%0A * a %7B@link Stream%7D (with the exception of %7B@code iterator%7D and %7B@code spliterator%7D,%0A * which are lazy terminal operations) applied all of the functions, and since one%0A * of those functions may throw an exception, each terminal operation in a %0A * %7B@code ThrowingStream%7D
  dec

Update Javadoc