package net.ranides.assira.collection.query.support;

import lombok.experimental.UtilityClass;
import net.ranides.assira.collection.lists.ListUtils;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.collection.sets.OpenSet;
import net.ranides.assira.functional.Consumers;
import net.ranides.assira.functional.Predicates;
import net.ranides.assira.generic.Ref;

import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.function.Predicate;

/**
 * This is internal utility class not supposed to use by clients.
 * It has default implementations of query operations using only List contract.
 *
 * It is almost complete facade: most of the time it delegates work to BaseListParallel or BaseListSequential.
 */
@UtilityClass
@SuppressWarnings("MissingJavadoc")
public class BaseList {

    public static <T, A> A[] array(CQuery<T> that, IntFunction<A[]> generator) {
        List<T> out = that.list();
        return out.toArray(generator.apply(out.size()));
    }

    public static <T> Set<T> set(CQuery<T> that) {
        return new OpenSet<>(that.list());
    }

    public static <T> Ref<T> at(CQuery<T> that, int index) {
        return ListUtils.at(that.list(), index).withMessage(that.message());
    }

    public static <T> Ref<T> first(CQuery<T> that) {
        return ListUtils.first(that.list()).withMessage(that.message());
    }

    public static <T> Ref<T> last(CQuery<T> that) {
        return ListUtils.last(that.list()).withMessage(that.message());
    }

    public static <T> void forEach(CQuery<T> that, Consumer<? super T> consumer) {
        if(that.features().isParallel()) {
            BaseListParalell.forEach(that.list(), consumer);
        } else {
            BaseListSequential.forEach(that.list(), consumer);
        }
    }

    public static <T> void forEach(CQuery<T> that, Consumers.EachConsumer<? super T> consumer) {
        if(that.features().isParallel()) {
            BaseListParalell.forEach(that.list(), consumer);
        } else {
            BaseListSequential.forEach(that.list(), consumer);
        }
    }

    public static <T> boolean whileEach(CQuery<T> that, Predicate<? super T> consumer) {
        if(that.features().isParallel()) {
            return BaseListParalell.whileEach(that.list(), consumer);
        } else {
            return BaseListSequential.whileEach(that.list(), consumer);
        }
    }

    public static <T> boolean whileEach(CQuery<T> that, Predicates.EachPredicate<? super T> consumer) {
        if(that.features().isParallel()) {
            return BaseListParalell.whileEach(that.list(), consumer);
        } else {
            return BaseListSequential.whileEach(that.list(), consumer);
        }
    }
}
