package co.unruly.control.Result;

import co.unruly.control.ThrowingLambdas.ThrowingFunction;

import java.util.function.Function;

import static co.unruly.control.Result.Match.ifType;
import static co.unruly.control.Result.Result.failure;
import static co.unruly.control.Result.Result.success;
import static co.unruly.control.Result.Results.flatMap;
import static co.unruly.control.Result.Results.mapFailure;
import static java.util.function.Function.identity;

public class Try {

    public static <I, O, X extends Exception> Attempt<I, O, Exception, Exception> tryTo(ThrowingFunction<I, O, X> f) {
        return flatMap(tryToCall(f, identity()));
    }

    public static <I, O, F, X extends Exception> Attempt<I, O, F, F> tryTo(ThrowingFunction<I, O, X> f, Function<Exception, F> exceptionHandler) {
        return flatMap(tryToCall(f, exceptionHandler));
    }

    public static <I, O, R extends Exception, X extends R> Attempt<I, O, R, R> tryTo(ThrowingFunction<I, O, X> f, Class<R> checkedType) {
        return flatMap(tryChecked(f, checkedType));
    }

    public static <I, O, F, R extends Exception, X extends R> Attempt<I, O, F, F> tryTo(ThrowingFunction<I, O, X> f, Class<R> checkedType, Function<R, F> exceptionHandler) {
        return flatMap(tryChecked(f, checkedType).then(mapFailure(exceptionHandler)));
    }

    private static <I, O, R extends Exception, X extends R> Attempt<I, O, Exception, R> tryChecked(ThrowingFunction<I, O, X> f, Class<R> checkedType) {
        final Function<Exception, R> castToCheckedType = Match.<Exception, R>match(
            ifType(checkedType, ex -> ex)
        ).otherwise(ex -> { throw (RuntimeException)ex;});

        return tryTo(f, identity()).then(mapFailure(castToCheckedType));
    }

    private static <I, O, F, X extends Exception> Function<I, Result<O, F>> tryToCall(ThrowingFunction<I, O, X> f, Function<Exception, F> exceptionHandler) {
        return s -> {
            try {
                return success(f.apply(s));
            } catch (Exception ex) {
                return failure(exceptionHandler.apply(ex));
            }
        };
    }
}

@@ -28,16 +28,58 @@
 esult;%0A%0A
+import co.unruly.control.ThrowingLambdas;%0A
 import c
@@ -1779,32 +1779,655 @@
 dType));%0A    %7D%0A%0A
+    public static %3CI, S, F, X extends Exception%3E Attempt%3CI, S, F, F%3E flatTry(ThrowingLambdas.ThrowingFunction%3CI, Result%3CS, F%3E, X%3E f, Function%3CException, F%3E emap) %7B%0A        return flatMap(tryToFlat(f, emap));%0A    %7D%0A%0A    private static %3CI, S, F, X extends Exception%3E java.util.function.Function%3CI, Result%3CS, F%3E%3E tryToFlat(ThrowingLambdas.ThrowingFunction%3CI, Result%3CS, F%3E, X%3E f, Function%3CException, F%3E exceptionHandler) %7B%0A        return s -%3E %7B%0A            try %7B%0A                return f.apply(s);%0A            %7D catch (Exception ex) %7B%0A                return failure(exceptionHandler.apply(ex));%0A            %7D%0A        %7D;%0A    %7D%0A%0A
     private stat
@@ -2780,10 +2780,11 @@
 ;%0A    %7D%0A
+%0A
 %7D%0A

Add flatTry