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

import lombok.experimental.UtilityClass;

import net.ranides.assira.functional.Consumers;
import net.ranides.assira.functional.Predicates;

import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * This is internal utility class not supposed to use by clients.
 * It has default implementations of sequential query operations using only List contract.
 *
 * Those methods should not be called directly, but by "BaseList" facade.
 */
@UtilityClass
@SuppressWarnings("MissingJavadoc")
public class BaseListSequential {

    public static <T> void forEach(List<T> list, Consumer<? super T> consumer) {
        list.forEach(consumer);
    }

    public static <T> void forEach(List<T> list, Consumers.EachConsumer<? super T> consumer) {
        forEach(list, 0, list.size(), consumer);
    }

    public static <T> void forEach(List<T> list, int begin, int end, Consumers.EachConsumer<? super T> consumer) {
        if(list instanceof RandomAccess) {
            for (int index = begin; index < end; index++) {
                consumer.accept(index, list.get(index));
            }
        } else {
            Iterator<T> itr = list.listIterator(begin);
            for (int index = begin; index < end; index++) {
                consumer.accept(index, itr.next());
            }
        }
    }

    public static <T> boolean whileEach(List<T> list, Predicate<? super T> consumer) {
        for (T a : list) {
            if (!consumer.test(a)) {
                return false;
            }
        }
        return true;
    }

    public static <T> boolean whileEach(List<T> list, Predicates.EachPredicate<? super T> consumer) {
        if(list instanceof RandomAccess) {
            for(int index = 0, n = list.size(); index<n; index++) {
                if( !consumer.test(index, list.get(index))) {
                    return false;
                }
            }
            return true;
        } else {
            Iterator<T> itr = list.iterator();
            for(int index = 0, n = list.size(); index<n; index++) {
                if( !consumer.test(index, itr.next())) {
                    return false;
                }
            }
            return true;
        }
    }

    public static <T> void whileEach(List<T> list, int begin, int end, BaseState.Terminator terminator, Predicates.EachPredicate<? super T> consumer) {
        if(list instanceof RandomAccess) {
            for (int index = begin; index < end; index++) {
                if (terminator.stopped()) {
                    break;
                }
                boolean test = consumer.test(index, list.get(index));
                if (!test) {
                    terminator.stop();
                    break;
                }
            }
        } else {
            ListIterator<T> itr = list.listIterator(begin);
            for (int index = begin; index < end; index++) {
                if (terminator.stopped()) {
                    break;
                }
                boolean test = consumer.test(index, itr.next());
                if (!test) {
                    terminator.stop();
                    break;
                }
            }
        }
    }

    public static <T> boolean whileEach(List<T> list, int begin, int end, Predicates.EachPredicate<? super T> consumer) {
        if(list instanceof RandomAccess) {
            for (int index = begin; index < end; index++) {
                if (!consumer.test(index, list.get(index))) {
                    return false;
                }
            }
            return true;
        } else {
            ListIterator<T> itr = list.listIterator(begin);
            for (int index = begin; index < end; index++) {
                if (!consumer.test(index, itr.next())) {
                    return false;
                }
            }
            return true;
        }
    }
}
