/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.reflection;

import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.generic.Ref;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collector;

/**
 * Fluent interface for collection of IElement objects.
 *
 * Please note, that IElements is unordered collection.
 *
 * It works in similar way to {@link CQuery}: it defers computation of content as long as possible.
 *
 * @param <T> IElement
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface IElements<T> extends Iterable<T> {

    /**
     * Returns number of elements.
     *
     * Invocation of this method can trigger computation of whole content of collection.
     *
     * @return int
     */
    int count();

    /**
     * Returns true if collection is empty.
     *
     * Invocation of this method can trigger computation of whole content of collection.
     *
     * @return boolean
     */
    boolean isEmpty();

    /**
     * Converts this collection into CQuery.
     * Each element is converted using provided mapper.
     *
     * @param mapper mapper
     * @param <R> R
     * @return CQuery
     */
    <R> CQuery<R> stream(Function<? super T, R> mapper);

    /**
     * Converts this collection into CQuery.
     *
     * @return CQuery
     */
    CQuery<T> stream();

    /**
     * Iterates over all elements inside collection.
     *
     * @param consumer consumer
     */
    void each(Consumer<? super T> consumer);

    /**
     * Converts this collection into List.
     * Each element is converted using provided mapper.
     *
     * @param mapper mapper
     * @param <R> R
     * @return List
     */
    <R> List<R> list(Function<? super T, R> mapper);

    /**
     * Converts this collection into List.
     *
     * @return List
     */
    List<T> list();

    /**
     * Converts this collection into Collection.
     *
     * @param collector collector
     * @param <R> R
     * @param <A> A
     * @return Collection
     */
    <R, A> R collect(Collector<? super T, A, R> collector);

    /**
     * Returns first element from collection.
     *
     * @return optional
     */
    Ref<T> first();

    /**
     * Returns element only if collection contains exactly one element.
     * If collection contains more elements or none, it returns empty.
     *
     * @return optional
     */
    Ref<T> single();

    /**
     * Returns element at specified index
     *
     * @param index index
     * @return optional
     */
    Ref<T> at(int index);

    /**
     * Returns list with names of each element
     *
     * @return List
     */
    List<String> names();

    /**
     * Returns list with parents of each element
     *
     * @return IElements
     */
    IElements<? extends IElement> parent();

    /**
     * Changes hint flags used by this collection.
     *
     * Hints are used when we compute content of collection.
     *
     * For example, you can enable searching for inherited members, or ignore all
     * non-public ones by specify corresponding "require" and "discard" clauses.
     *
     * @param attr attr
     * @return this
     */
    IElements<T> hint(IHints attr);
    
}
