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

import net.ranides.assira.collection.iterators.IteratorUtils;
import net.ranides.assira.collection.iterators.SpliteratorUtils;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.collection.query.base.CQAbstractFilter;

import java.util.Iterator;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 * Adapter query: it filters provided stream using predicate.
 * Stops instantly when predicate returns "false"
 * Use by {@link CQuery#limit(Predicate)} operation.
 *
 * Supports fast iterator and stream if source supports it.
 * Does not support other fast operations.
 *
 * It supports stateless predicates only
 *
 * @param <T> T
 */
public class CQLimit<T> extends CQAbstractFilter<T, T> {

    private final Predicate<? super T> p;

    /**
     * Creates new filtered query.
     * It assumes that predicate is stateless, and is reused by all terminal operations.
     *
     * @param source source
     * @param p predicate
     */
    public CQLimit(CQuery<T> source, Predicate<? super T> p) {
        super(source);
        this.p = p;
    }

    @Override
    public CQuery<T> parallel() {
        return isParallel() ? this : new CQLimit<>(source.parallel(), p);
    }

    @Override
    public CQuery<T> sequential() {
        return isParallel() ? new CQLimit<>(source.sequential(), p) : this;
    }

    @Override
    public boolean hasFastEach() {
        return source.features().hasFastEach();
    }

    @Override
    public Stream<T> stream() {
        return SpliteratorUtils.limit(source.stream(), p);
    }

    @Override
    public Iterator<T> iterator() {
        return IteratorUtils.limit(source.iterator(), p);
    }

    @Override
    public boolean whileEach(Predicate<? super T> consumer) {
        return source.whileEach(v -> p.test(v) && consumer.test(v));
    }

}
