package net.ranides.assira.functional;

import lombok.experimental.UtilityClass;

import java.io.Serializable;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * Consumer interfaces with arity other than 1
 *
 * Please note, that those interfaces extend Serializable.
 * You can use them if you want to store your lambda expressions in Serializable objects.
 */
@UtilityClass
public class Consumers {

    /**
     * Consumer interface with arity = 0.
     * It is equivalent to Runnabe, but uses Consumer naming convention.
     */
    public interface Consumer0 extends Runnable, Serializable {
        /**
         * Operation
         */
        void accept();

        @Override
        default void run() {
            accept();
        }
    }

    /**
     * Consumer interface with arity = 1.
     * It is equivalent to standard Consumer.
     *
     * @param <A> A
     */
    public interface Consumer1<A> extends Consumer<A>, Serializable {
        @Override
        void accept(A a);

    }

    /**
     * Consumer interface with arity = 2.
     * It is equivalent to BiConsumer.
     *
     * @param <A> A
     * @param <B> B
     */
    public interface Consumer2<A, B> extends BiConsumer<A, B>, Serializable {
        @Override
        void accept(A a, B b);
    }

    /**
     * Consumer interface with arity = 3.
     *
     * @param <A> A
     * @param <B> B
     * @param <C> C
     */
    public interface Consumer3<A, B, C> extends Serializable {
        /**
         * Operation
         *
         * @param a a
         * @param b b
         * @param c c
         */
        void accept(A a, B b, C c);
    }

    /**
     * Consumer interface with arity = 4.
     *
     * @param <A> A
     * @param <B> B
     * @param <C> C
     * @param <D> D
     */
    public interface Consumer4<A, B, C, D> extends Serializable {
        /**
         * Operation
         *
         * @param a a
         * @param b b
         * @param c c
         * @param d d
         */
        void accept(A a, B b, C c, D d);
    }

    /**
     * It is Consumer which takes value of element and index of element inside collection.
     * It is used by functional looping methods.
     *
     * @author Ranides Atterwim {@literal <ranides@gmail.com>}
     */
    public interface EachConsumer<U> extends Serializable {

        /**
         * Operation: takes value and it's position.
         *
         * @param index index
         * @param value value
         */
        void accept(int index, U value);

    }
}
