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

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.function.Predicate;

import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.generic.Ref;
import net.ranides.assira.reflection.impl.AAnnotations;
import net.ranides.assira.reflection.impl.FElements;

/**
 * Fluent interface for collection of Annotation objects
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface IAnnotations extends IElements<Annotation> {

    /**
     * Factory: returns empty collection
     *
     * @return IAnnotations
     */
    static IAnnotations empty() {
        return AAnnotations.$empty();
    }

    /**
     * Factory: creates new collection with annotations of provided type
     * Every annotation inside collection has default parameter values.
     *
     * @param annotations types
     * @return IAnnotations
     */
    @SafeVarargs
    static IAnnotations of(Class<? extends Annotation>... annotations) {
        return FElements.newAnnotations(annotations);
    }

    /**
     * Factory: creates new collection with provided annotations inside.
     *
     * @param annotations annotations
     * @return IAnnotations
     */
    static IAnnotations of(Annotation... annotations) {
        return FElements.newAnnotations(annotations);
    }

    /**
     * Returns first annotation with specified type.
     * Returns none if not found.
     *
     * @param <A> A
     * @param type type
     * @return optional
     */
    <A extends Annotation> Ref<A> first(Class<A> type);

    /**
     * Returns stream which contains only annotations with specified type.
     *
     * @param type type
     * @param <A> A
     * @return CQuery
     */
    <A extends Annotation> CQuery<A> stream(Class<A> type);

    /**
     * Returns list which contains only annotations with specified type.
     *
     * @param type type
     * @param <A> A
     * @return List
     */
    <A extends Annotation> List<A> list(Class<A> type);

    /**
     * Returns new filtered collection, with elements matching predicate
     *
     * @param predicate predicate
     * @return IAnnotations
     */
    IAnnotations require(Predicate<? super Annotation> predicate);

    /**
     * Returns new filtered collection, with elements matching type
     *
     * @param type type
     * @return IAnnotations
     */
    IAnnotations require(Class<? extends Annotation> type);

    /**
     * Returns new filtered collection, without elements matching predicate
     *
     * @param predicate predicate
     * @return IAnnotations
     */
    IAnnotations discard(Predicate<? super Annotation> predicate);

    /**
     * Returns new filtered collection, without elements matching predicate
     *
     * @param type type
     * @return IAnnotations
     */
    IAnnotations discard(Class<? extends Annotation> type);
            
}
