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

import lombok.RequiredArgsConstructor;

import net.ranides.assira.collection.iterators.IteratorUtils;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.collection.query.CQueryAbstract;
import net.ranides.assira.collection.query.support.BaseEach;

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

/**
 * Abstract class for adapter stream which changes number of returned items.
 *
 * @param <S> S
 * @param <T> T
 */
public abstract class CQAbstractFilter<S,T> extends CQueryAbstract<T> {

    protected final CQuery<S> source;

    protected CQAbstractFilter(CQuery<S> source) {
        this.source = source;
    }

    @Override
    public Supplier<? extends RuntimeException> message() {
        return source.message();
    }

    @Override
    public CQuery<T> message(Supplier<? extends RuntimeException> message) {
        source.message(message);
        return this;
    }

    @Override
    public abstract Stream<T> stream();

    @Override
    public abstract Iterator<T> iterator();

    @Override
    public boolean hasFastEach() {
        return false;
    }

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

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

    @Override
    public boolean hasFastLength() {
        return false;
    }

    @Override
    public boolean hasFastList() {
        return false;
    }

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

    @Override
    public int size() {
        if(!hasFastStream()) {
            if(hasFastIterator()) {
                return IteratorUtils.size(iterator());
            }
            if(hasFastEach()) {
                return BaseEach.size(this);
            }
        }
        return (int)stream().count();
    }

}
