/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.query;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Stream;
import net.ranides.assira.collection.HashFunction;
import net.ranides.assira.functional.EachFunction;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 * @param <T>
 */
@SuppressWarnings("PMD.TooManyDifferentMethods")
public interface CQuery<T> extends Iterable<T> {
    
    Stream<T> stream();

    <A,R> R collect(Collector<? super T,A,R> collector);
    
    Object[] array();
    
    <A> A[] array(IntFunction<A[]> generator);
    
    List<T> list();
    
    Set<T> set();
    
    <K> Map<K,T> group(Function<? super T, ? extends K> key);
    
    <K,V> Map<K,V> group(Function<? super T, ? extends K> key, Function<? super T, ? extends V> value);
    
    int size();
    
    boolean isEmpty();
    
    CQuery<T> limit(Predicate<? super T> p);
    
    CQuery<T> limit(int n);
    
    CQuery<T> skip(int n);
    
    CQuery<T> slice(int begin, int end);

    CQuery<T> filter(Predicate<? super T> p);
    
    <R> CQuery<R> map(Function<? super T,? extends R> f);
    
    <R> CQuery<R> map(EachFunction<? super T,? extends R> f);
    
    <R> CQuery<R> unfold(Function<? super T, CQuery<R>> f);
    
    <R> CQuery<R> split(Function<? super T, R[]> f);
    
    T fold(T identity, BinaryOperator<T> accumulator);
    
    T fold(BinaryOperator<T> accumulator);
    
    T min(Comparator<? super T> cmp);
    
    T max(Comparator<? super T> cmp);

    Optional<T> first();

    Optional<T> last();
    
    CQuery<T> distinct();
    
    CQuery<T> distinct(HashFunction<T> eq);
    
    CQuery<T> distinct(Comparator<? super T> cmp);
    
    CQuery<T> sort();
    
    CQuery<T> sort(Comparator<? super T> cmp);
    
    void each(Consumer<? super T> consumer);
    
    void into(Collection<? super T> collection);
    
    boolean matchAny(Predicate<? super T> predicate);
    
    boolean matchAll(Predicate<? super T> predicate);
    
    boolean matchNone(Predicate<? super T> predicate);
    
}
