/*
 * Copyright 2017-2017 the original author or authors.
 *
 * 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.digitalascent.core.base;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public final class LambdaCheckedExceptionRethrowers {

    @FunctionalInterface
    public interface CheckedPredicate<T, E extends Exception> {
        boolean test(T t) throws E;
    }

    @FunctionalInterface
    public interface CheckedBiPredicate<T, U, E extends Exception> {
        boolean test(T t, U u) throws E;
    }

    @FunctionalInterface
    public interface CheckedConsumer<T, E extends Exception> {
        void accept(T t) throws E;
    }

    @FunctionalInterface
    public interface CheckedBiConsumer<T, U, E extends Exception> {
        void accept(T t, U u) throws E;
    }

    @FunctionalInterface
    public interface CheckedFunction<T, R, E extends Exception> {
        R apply(T t) throws E;
    }

    @FunctionalInterface
    public interface CheckedBiFunction<T, U, R, E extends Exception> {
        R apply(T t, U u) throws E;
    }

    @FunctionalInterface
    public interface CheckedSupplier<T, E extends Exception> {
        T get() throws E;
    }

    @FunctionalInterface
    public interface CheckedRunnable<E extends Exception> {
        void run() throws E;
    }

    public static <T, E extends Exception> Predicate<T> rethrowingPredicate(CheckedPredicate<T, E> predicate) {
        return t -> {
            try {
                return predicate.test(t);
            } catch (Exception exception) {
                throwAsUnchecked(exception);
                return false;
            }
        };
    }

    public static <T, U, E extends Exception> BiPredicate<T, U> rethrowingBiPredicate(CheckedBiPredicate<T, U, E> predicate) {
        return (t, u) -> {
            try {
                return predicate.test(t, u);
            } catch (Exception exception) {
                throwAsUnchecked(exception);
                return false;
            }
        };
    }

    public static <T, E extends Exception> Consumer<T> rethrowingConsumer(CheckedConsumer<T, E> consumer) {
        return t -> {
            try {
                consumer.accept(t);
            } catch (Exception exception) {
                throwAsUnchecked(exception);
            }
        };
    }

    public static <T, U, E extends Exception> BiConsumer<T, U> rethrowingBiConsumer(CheckedBiConsumer<T, U, E> biConsumer) {
        return (t, u) -> {
            try {
                biConsumer.accept(t, u);
            } catch (Exception exception) {
                throwAsUnchecked(exception);
            }
        };
    }

    public static <T, R, E extends Exception> Function<T, R> rethrowingFunction(CheckedFunction<T, R, E> function) {
        return t -> {
            try {
                return function.apply(t);
            } catch (Exception exception) {
                throwAsUnchecked(exception);
                return null;
            }
        };
    }

    public static <T, U, R, E extends Exception> BiFunction<T, U, R> rethrowingBiFunction(CheckedBiFunction<T, U, R, E> function) {
        return (t, u) -> {
            try {
                return function.apply(t, u);
            } catch (Exception exception) {
                throwAsUnchecked(exception);
                return null;
            }
        };
    }

    public static <T, E extends Exception> Supplier<T> rethrowingSupplier(CheckedSupplier<T, E> function) {
        return () -> {
            try {
                return function.get();
            } catch (Exception exception) {
                throwAsUnchecked(exception);
                return null;
            }
        };
    }

    @SuppressWarnings({"unchecked", "ConstantConditions"})
    private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E {
        throw (E) exception;
    }

    private LambdaCheckedExceptionRethrowers() {
        throw new AssertionError("Cannot instantiate " + getClass());
    }

}

@@ -1214,30 +1214,36 @@
 lean test(T 
-t, U u
+var1, U var2
 ) throws E;%0A
@@ -1355,25 +1355,28 @@
 id accept(T 
-t
+var1
 ) throws E;%0A
@@ -1497,22 +1497,28 @@
 ccept(T 
-t, U u
+var1, U var2
 ) throws
@@ -1637,17 +1637,20 @@
 apply(T 
-t
+var1
 ) throws
@@ -1778,14 +1778,20 @@
 y(T 
-t, U u
+var1, U var2
 ) th
@@ -2527,36 +2527,42 @@
         return (
-t, u
+var1, var2
 ) -%3E %7B%0A         
@@ -2608,20 +2608,26 @@
 te.test(
-t, u
+var1, var2
 );%0A     
@@ -2887,33 +2887,36 @@
 %0A        return 
-t
+var1
  -%3E %7B%0A          
@@ -2955,17 +2955,20 @@
 .accept(
-t
+var1
 );%0A     
@@ -3216,36 +3216,42 @@
         return (
-t, u
+var1, var2
 ) -%3E %7B%0A         
@@ -3293,20 +3293,26 @@
 .accept(
-t, u
+var1, var2
 );%0A     
@@ -3924,20 +3924,26 @@
 return (
-t, u
+var1, var2
 ) -%3E %7B%0A 
@@ -4001,12 +4001,18 @@
 ply(
-t, u
+var1, var2
 );%0A 

Align variable names with function types