/*
 * @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.lang.reflect.Field;
import java.util.function.Predicate;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.reflection.impl.AArguments;
import net.ranides.assira.reflection.impl.AFields;
import net.ranides.assira.reflection.impl.FElements;

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

    /**
     * Factory: returns collection with each field converted to IField
     *
     * @param fields fields
     * @return IFields
     */
    static IFields typeinfo(Field... fields) {
        return FElements.newFields(fields);
    }

    /**
     * Factory: returns empty collection
     *
     * @return fields
     */
    static IFields empty() {
        return AFields.$empty();
    }

    /**
     * Returns (this) filtered collection, with fields matching predicate
     *
     * @param predicate predicate
     * @return IFields
     */
    IFields require(Predicate<? super IField> predicate);

    /**
     * Returns (this) filtered collection, with fields annotated by provided annotation
     *
     * @param annotations annotations
     * @return IFields
     */
    IFields require(IAnnotations annotations);

    /**
     * Returns (this) filtered collection, with fields annotated by provided annotations
     *
     * @param annotation annotation
     * @return IFields
     */
    IFields require(Class<? extends Annotation> annotation);

    /**
     * Returns (this) filtered collection, with fields of specified type
     *
     * @param type type
     * @return IFields
     */
    IFields require(IClass<?> type);

    /**
     * Returns (this) filtered collection, with fields with provided attribute
     *
     * @param attribute attribute
     * @return IFields
     */
    IFields require(IAttribute attribute);

    /**
     * Returns (this) filtered collection, with fields with provided attributes
     *
     * @param attributes attributes
     * @return IFields
     */
    IFields require(IAttributes attributes);

    /**
     * Returns (this) filtered collection, with fields with specified name.
     *
     * Please note: it is possible to have more than one field with the same name
     * if we search for inherited non-public ones.
     *
     * @param name name
     * @return IFields
     */
    IFields require(String name);

    /**
     * Returns (this) filtered collection, without fields matching predicate
     *
     * @param predicate predicate
     * @return IFields
     */
    IFields discard(Predicate<? super IField> predicate);

    /**
     * Returns (this) filtered collection, without fields annotated by provided annotation
     *
     * @param annotations annotations
     * @return IFields
     */
    IFields discard(IAnnotations annotations);

    /**
     * Returns (this) filtered collection, without fields annotated by provided annotations
     *
     * @param annotation annotation
     * @return IFields
     */
    IFields discard(Class<? extends Annotation> annotation);

    /**
     * Returns (this) filtered collection, without fields of specified type
     *
     * @param type type
     * @return IFields
     */
    IFields discard(IClass<?> type);

    /**
     * Returns (this) filtered collection, without fields with provided attribute
     *
     * @param attribute attribute
     * @return IFields
     */
    IFields discard(IAttribute attribute);

    /**
     * Returns (this) filtered collection, without fields with provided attributes
     *
     * @param attributes attributes
     * @return IFields
     */
    IFields discard(IAttributes attributes);

    /**
     * Returns (this) filtered collection, without fields with specified name.
     *
     * @param name name
     * @return IFields
     */
    IFields discard(String name);

    /**
     * Returns mapped collection with type of each field.
     *
     * @return IClasses
     */
    IClasses type();

    /**
     * Returns mapped collection with parent class of each field.
     *
     * @return IClasses
     */
    @Override
    IClasses parent();

    /**
     * Returns stream with each field mapped to reflective Field
     *
     * @return CQuery
     */
    CQuery<Field> reflective();

    /**
     * Returns mapped collection with each field converted to writable field
     *
     * @return IFields
     */
    IFields rewritable();

    /**
     * Returns mapped collection with each field converted to accessible field
     *
     * @return IFields
     */
    IFields accessible();

}
