package net.ranides.assira.functional;

import lombok.experimental.UtilityClass;

import net.ranides.assira.functional.Predicates.EachPredicate;
import net.ranides.assira.functional.Predicates.Predicate0;
import net.ranides.assira.functional.Predicates.Predicate1;
import net.ranides.assira.functional.Predicates.Predicate2;
import net.ranides.assira.functional.Predicates.Predicate3;
import net.ranides.assira.functional.Predicates.Predicate4;

import java.util.function.BiPredicate;
import java.util.function.BooleanSupplier;
import java.util.function.Predicate;

/**
 * Static functional methods for Predicate interface
 */
@UtilityClass
public class PredicateUtils {

    /**
     * Sneaky raw cast.
     * It allows to avoid warnings in contexts where we know correctness of the code.
     *
     * @param predicate predicate
     * @return functional
     */
    public static Predicate0 raw(BooleanSupplier predicate) {
        return predicate::getAsBoolean;
    }

    /**
     * Sneaky raw cast.
     * It allows to avoid warnings in contexts where we know correctness of the code.
     *
     * @param predicate predicate
     * @param <R> R
     * @return functional
     */
    @SuppressWarnings("unchecked")
    public static <R> Predicate1<R> raw(Predicate<?> predicate) {
        Predicate<R> ready = Predicate.class.cast(predicate);
        return ready::test;
    }

    /**
     * Sneaky raw cast.
     * It allows to avoid warnings in contexts where we know correctness of the code.
     *
     * @param predicate predicate
     * @param <T> T
     * @param <U> U
     * @return functional
     */
    @SuppressWarnings("unchecked")
    public static <T, U> Predicate2<T, U> raw(BiPredicate<?, ?> predicate) {
        BiPredicate<T, U> ready = BiPredicate.class.cast(predicate);
        return ready::test;
    }

    /**
     * Sneaky raw cast.
     * It allows to avoid warnings in contexts where we know correctness of the code.
     *
     * @param predicate predicate
     * @param <A> A
     * @param <B> B
     * @param <C> C
     * @return functional
     */
    @SuppressWarnings("unchecked")
    public static <A, B, C> Predicate3<A, B, C> raw(Predicate3<?, ?, ?> predicate) {
        return Predicate3.class.cast(predicate);
    }

    /**
     * Sneaky raw cast.
     * It allows to avoid warnings in contexts where we know correctness of the code.
     *
     * @param function function
     * @param <A> A
     * @param <B> B
     * @param <C> C
     * @param <D> D
     * @return functional
     */
    @SuppressWarnings("unchecked")
    public static <A, B, C, D> Predicate4<A, B, C, D> raw(Predicate4<?, ?, ?, ?> function) {
        return Predicate4.class.cast(function);
    }

}
