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

import java.lang.annotation.*;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.util.ServiceLoader;


/**
 * Annotations with semantic information.
 * Some of them are used at runtime in reflective classes and/or for code generation.
 * Others are used only as hints for programmers and tools.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
@SuppressWarnings("PMD.PackageClass")
public final class Meta {

    private Meta() { }

    /**
     * This field is assigned only once, at initialization, but outside constructor.
     * For example, inside method {@code onInit}, {@code onCreate} or similar.
     * Especially useful in Java EE beans, where init method is preferred.
     */
    @Retention(RUNTIME)
    @Target({FIELD})
    @Documented
    public @interface Final {
        /**
         * Symbolic name of initialization method (create, init, show, etc etc)
         * It is used only as a hint for programmer.
         * @return default = ""
         */
        String value() default "";

    }
    
    /**
     * The class is immutable. I'ts guaranteed that every method supposed to 
     * change object will throw exception. Ideally, object does not have any
     * method of that kind in public interface.
     * <p>
     * Immutable object most often has all fields final, and use only references
     * to immutable objects. By default, immutable object are thread-safe. 
     * If not, you should change "threadsafe" parameter. 
     * </p>
     * <p> Annotation is especially helpfull if you need to create some subclass 
     * of java collection or implement interface. There is no "ImmutableList" or
     * something like that. Annotation is clean method of expressing your intentions
     * about object's behaviour.
     * </p>
     */
    @Retention(RUNTIME)
    @Target({TYPE})
    @Documented
    public @interface Immutable {

        /**
         * Mark this class as immutable, but not thread-safe
         * @return bool
         */
        boolean threadsafe() default true;

    }

    /**
     * If method or class should be used very carefully, it should be annotated by {@code Unsafe}.
     * For example:
     * <ul>
     *      <li>method uses unchecked casts inside</li>
     *      <li>method has undefined behaviour under special conditions</li>
     *      <li>exposes internal array</li>
     *      <li>can cause race conditions</li>
     *      <li>returns null instead of throwing exception or optional</li>
     * </ul>
     */
    @Retention(RUNTIME)
    @Target({TYPE, METHOD, CONSTRUCTOR})
    @Documented
    public @interface Unsafe {
    }

    /**
     * Annotated class implements interface designed for {@link ServiceLoader}.
     * Library will generate entry inside META-INF directory at compile time.
     */
    @Retention(SOURCE)
    @Documented
    @Target(TYPE)
    public @interface JavaService {
        /**
         * If class implements more than one interface, you have to use this parameter to tell
         * which interface is designed for {@link ServiceLoader} and should be included inside generated manifest.
         * @return class
         */
        Class<?> value() default void.class;
    }

    /**
     * This method can throw exception at runtime due to JDK or OS incompatibility
     */
    @Retention(RUNTIME)
    @Target({TYPE, METHOD, CONSTRUCTOR})
    @Documented
    public @interface UnstableAPI {
    }

    /**
     * This method is designed for JDK8, new java versions can throw exception at runtime
     * because of more strict security model
     */
    @Retention(RUNTIME)
    @Target({TYPE, METHOD, CONSTRUCTOR})
    @Documented
    public @interface ForJDK8 {
    }

    /**
     * Annotation used by {@link net.ranides.assira.reflection.AdapterFactory}
     * AdapterFactory tries cast any object into type marked by this annotation.
     *
     * Please note, that if you write "adaptable interface" and you use "adaptable types" in their
     * method declarations, then every adaptable type will be unwrapped at call time, and passed into
     * original class in raw form. The same applies to return values: if original object returns something, but
     * you declared "adaptable type" as return value, generated proxy will try to convert raw result to adaptable.
     */
    @Retention(RUNTIME)
    @Target({TYPE})
    @Documented
    public @interface Adapter {

        /**
         * Unused parameter, reserved for the future
         * @return value
         */
        String value() default "";

    }

    /**
     * Annotated method is invoked at runtime by {@link net.ranides.assira.generic.DynamicInvoker}.
     */
    @Target(METHOD)
    @Retention(RUNTIME)
    @Documented
    public @interface DynamicDispatch {
    }

    /**
     * Annotated type or method can be drastically changed or removed at all in future versions
     */
    @Target({METHOD, TYPE})
    @Retention(SOURCE)
    public @interface Experimental {
    }

    /**
     * Annotation used by classes or methods to mark code as thread-safe.
     * It is used for documentation purposes or static analysis.
     */
    @Target({METHOD, TYPE})
    @Retention(SOURCE)
    @Documented
    public @interface ThreadSafe {

    }

    /**
     * Element is called reflectively by external system at runtime.
     * Static analysis should not warn about unused method.
     */
    @Retention(RUNTIME)
    @Target({METHOD, FIELD})
    @Documented
    public @interface Dynamic {
        /**
         * List of runtime systems using annotated method or field.
         * @return strings
         */
        String[] system() default {""};
    }

    /**
     * Annotation used to mark method as an alias.
     * It is for documentation purposes, mostly.
     */
    @Target({METHOD})
    @Retention(SOURCE)
    @Documented
    public @interface Alias {

        /**
         * Name of aliased method
         * @return value
         */
        String value() default "";

    }


}
