/*
 * @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.annotations.Meta;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.generic.Ref;

import java.lang.annotation.Annotation;

/**
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface IElement {

    /**
     * Returns type context assigned with this element.
     *
     * Every reflective element has defined context (possibly default one) used for
     * type resolution. Type contexts try to bypass type-erasure and deduce generic parameters.
     *
     * @return IContext
     */
    IContext context();

    /**
     * Returns collection with exactly one element, this one
     *
     * @return IElements
     */
    IElements<? extends IElement> collect();

    /**
     * Loosely speaking: returns java identifier of element.
     *
     * This method has different semanthics for different subinterfaces:
     *  - IClass returns fully qualified name
     *  - IField returns just field name
     *  - IExecutable returns just method name
     *  - IArgument returns argument name, but it is not guaranteed to work
     *  - IVariable returns variable identifier
     *
     * @return String
     */
    String name();

    /**
     * Returns attributes of element.
     *
     * @return IAttributes
     */
    IAttributes attributes();

    /**
     * Returns true if element has provided attribute.
     *
     * @param attr attr
     * @return boolean
     */
    boolean attribute(IAttribute attr);

    /**
     * Returns all annotations assocciated with this element.
     * (in java every element can be annotated, even method return types)
     *
     * @return IAnnotations
     */
    IAnnotations annotations();

    /**
     * Returns first annotation of provided type assocciated with this element.
     * (in java every element can be annotated, even method return types)
     *
     * Returns empty optional, if annotation was not found.
     *
     * @param type type
     * @param <A> A
     * @return optional
     */
    <A extends Annotation> Ref<A> annotation(Class<A> type);

    /**
     * Returns annotations of provided type assocciated with this element.
     * (in java every element can be annotated, even method return types)
     *
     * @param type type
     * @param <A> A
     * @return CQuery
     */
    <A extends Annotation> CQuery<A> annotations(Class<A> type);

    /**
     * Loosely speaking: returns parent element
     *
     * This method has different semanthics for different subinterfaces:
     *  - IClass returns base class (not outer class)
     *  - IField returns declaring class
     *  - IExecutable returns declaring class
     *  - IArgument returns declaring method
     *  - IVariable returns declaring method
     *
     * @return IElement
     */
    IElement parent();

    /**
     * Alias for {@code attribute(IAttribute.PUBLIC)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(PUBLIC)")
    boolean isPublic();

    /**
     * Alias for {@code attribute(IAttribute.PACKAGE)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(PACKAGE)")
    boolean isPackage();

    /**
     * Alias for {@code attribute(IAttribute.PRIVATE)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(PRIVATE)")
    boolean isPrivate();

    /**
     * Alias for {@code attribute(IAttribute.PROTECTED)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(PROTECTED)")
    boolean isProtected();

    /**
     * Alias for {@code attribute(IAttribute.DECLARED)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(DECLARED)")
    boolean isDeclared();

    /**
     * Alias for {@code attribute(IAttribute.PARAMETERIZED)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(PARAMETERIZED)")
    boolean isParamaterized();

    /**
     * Alias for {@code attribute(IAttribute.FINAL)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(FINAL)")
    boolean isFinal();

    /**
     * Alias for {@code attribute(IAttribute.STATIC)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(STATIC)")
    boolean isStatic();

    /**
     * Alias for {@code attribute(IAttribute.SYNTHETIC)}.
     *
     * @return boolean
     */
    @Meta.Alias("attribute(SYNTHETIC)")
    boolean isSynthetic();

}
