package com.github.jeysal.java.util.function;

import lombok.experimental.UtilityClass;

import java.util.Arrays;
import java.util.Optional;
import java.util.function.Supplier;

/**
 * @author Tim Seckinger
 * @since 12.03.2016
 */
@UtilityClass
public class SupplierUtils {

    /**
     * Returns a {@link Supplier} that supplies the first present {@link Optional} supplied by given suppliers in order,
     * or an empty {@link Optional} if none of the suppliers return a present {@link Optional}.
     *
     * @param suppliers The suppliers to call in order
     * @param <T>       The type of the {@link Optional}
     * @return The {@link Supplier} that supplies the first present {@link Optional}
     */
    @SafeVarargs
    public static <T> Supplier<Optional<T>> firstPresent(Supplier<Optional<T>>... suppliers) {
        return () -> Arrays.stream(suppliers)
                .map(Supplier::get)
                .filter(Optional::isPresent)
                .findFirst().orElse(Optional.empty());
    }

    /**
     * Returns a {@link Supplier} that supplies the content of the first present {@link Optional} supplied by given
     * suppliers in order, or the object supplied by given fallback supplier if none of the suppliers return a present
     * {@link Optional}.
     *
     * @param fallback  The fallback supplier
     * @param suppliers The suppliers to call in order
     * @param <T>       The type of the {@link Optional} content or fallback object
     * @return The {@link Supplier} that supplies the first present {@link Optional}
     */
    @SafeVarargs
    public static <T> Supplier<T> firstPresent(Supplier<T> fallback, Supplier<Optional<T>>... suppliers) {
        return () -> Arrays.stream(suppliers)
                .map(Supplier::get)
                .filter(Optional::isPresent)
                .findFirst().orElseGet(() ->
                        Optional.of(fallback.get())
                ).get();
    }

    /**
     * Returns a {@link Supplier} that delegates calls to given throwingSupplier and returns an {@link Optional} of the
     * result or an empty {@link Optional} if given throwingSupplier returned null or threw an {@link Exception}.
     *
     * @param throwingSupplier The {@link Supplier} to delegate to
     * @param <R>              The return type of the {@link Supplier}
     * @return The {@link Supplier} that delegates calls to throwingSupplier
     */
    public static <R> Supplier<Optional<R>> trying(ThrowingSupplier<R, ?> throwingSupplier) {
        return () -> {
            try {
                return Optional.ofNullable(throwingSupplier.get());
            } catch (Exception e) {
                return Optional.empty();
            }
        };
    }
}

@@ -134,16 +134,52 @@
 tional;%0A
+import java.util.function.Function;%0A
 import j
@@ -2759,10 +2759,556 @@
 ;%0A    %7D%0A
+%0A    public static %3CR%3E Supplier%3CR%3E rethrowing(ThrowingSupplier%3CR, ?%3E throwingSupplier) %7B%0A        return rethrowing(throwingSupplier, RuntimeException::new);%0A    %7D%0A%0A    public static %3CR%3E Supplier%3CR%3E rethrowing(%0A            ThrowingSupplier%3CR, ?%3E throwingSupplier,%0A            Function%3CException, ? extends RuntimeException%3E exceptionMapper) %7B%0A        return () -%3E %7B%0A            try %7B%0A                return throwingSupplier.get();%0A            %7D catch (Exception e) %7B%0A                throw exceptionMapper.apply(e);%0A            %7D%0A        %7D;%0A    %7D%0A%0A
 %7D%0A

add SupplierUtils.rethrowing