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

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.BaseIterable;

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

/**
 * Stream implementation which uses iterator generator as source of data.
 *
 * Obviously, it supports fast iterator, it provided generator create iterator fast.
 *
 * @param <T>
 */
public abstract class CQIterator<T> extends CQueryAbstract<T> {

    /**
     * Creates new stream which does not support fast operations at all, because
     * it assummes generator call has very high cost.
     *
     * @param source source
     * @param <T> T
     * @return stream
     */
    public static <T> CQuery<T> from(Supplier<Iterator<T>> source) {
        return from(false, source);
    }

    /**
     * Creates new stream which reports fast iterator, if generator is fast.
     *
     * @param fast fast
     * @param source source
     * @param <T> T
     * @return query
     */
    public static <T> CQuery<T> from(boolean fast, Supplier<Iterator<T>> source) {
        return new CQIterator<T>() {
            @Override
            public Iterator<T> iterator() {
                return source.get();
            }

            @Override
            public boolean hasFastIterator() {
                return fast;
            }
        };
    }

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

    @Override
    public CQuery<T> message(Supplier<? extends RuntimeException> message) {
        return from(() -> IteratorUtils.withCause(iterator(), message));
    }

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

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

    @Override
    public CQuery<T> parallel() {
        return this;
    }

    @Override
    public CQuery<T> sequential() {
        return this;
    }

    @Override
    public Stream<T> stream() {
        return BaseIterable.stream(this);
    }

    @Override
    public int size() {
        return BaseIterable.size(this);
    }
}


