/*
 *  @author Ranides Atterwim <ranides@gmail.com>
 *  @copyright Ranides Atterwim
 *  @license WTFPL
 *  @url http://ranides.net/projects/assira
 */

package net.ranides.assira.annotations;

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


/**
 * Adnotacje dodające do kodu informacje o znaczeniu semantycznym.
 * Z niektórych adnotacji bliblioteka może intensywnie korzystać w runtime,
 * inne są tylko podpowiedziami dla programistów i/lub narzędzi sprawdzających
 * kod.
 *
 * @author ranides
 */
@SuppressWarnings("PMD.PackageClass")
public final class Meta {

    private Meta() { }

    /**
     * W jaki sposób kod jest generowany.
     */
    public enum GenerationStrategy {
        /** Automatycznie, wstawiany przed wywołaniem metody */
        BEFORE,

        /** Automatycznie, wstawiany po wywołaniu metody */
        AFTER,

        /** Automatycznie, zastępuje istniejącą implementację metody */
        REPLACE,

        /** Programista użył w kodzie metody jawnie generatora */
        MANUAL
    }

    /**
     * W jaki sposób wywołanie metody ma być synchronizowane z systemem
     */
    public enum SyncStrategy {

        /** Brak synchronizacji */
        NONE,

        /** Wywołanie w "event dispatching thread" biblioteki AWT */
        AWT,

        /** Wywołanie w "event dispatching thread" biblioteki AWT i oczekiwanie na zakończenie */
        AWT_WAIT
    }

    /**
     * Element zamrożony, gwarantowany brak zmian w API.
     */
    @Retention(RUNTIME)
    @Target({TYPE, ANNOTATION_TYPE, METHOD, CONSTRUCTOR, FIELD})
    @Documented
    public @interface Frozen {
        /**
         * Numer wersji podczas której zamrożono wskazane API (major).
         * @return default = 1
         */
        int version() default 1;

        /**
         * Numer wersji podczas której zamrożono wskazane API (minor).
         * @return default = 0
         */
        int minor() default 0;

        /**
         * Numer rewizji podczas której zamrożono wskazane API (np svn).
         * @return default = 0
         */
        int revision() default 0;
    }

    /**
     * Dostępne z poziomu języka skryptowego.
     */
    @Retention(RUNTIME)
    @Target({TYPE, METHOD, FIELD})
    @Documented
    public @interface Scriptable {
        /**
         * Języki, do których możliwe jest wiązanie
         * @return default = { "ECMA-262", "JavaScript 1.6" }
         */
        String[] lang() default {"ECMA-262", "JavaScript 1.6"};
    }


    /**
     * Pole lub właściwość odziedziczona prototypowo
     */
    @Retention(RUNTIME)
    @Target({METHOD, FIELD})
    @Documented
    public @interface Inherited {
    }


    /**
     * Implementacja metody wiązana dynamicznie.
     */
    @Retention(RUNTIME)
    @Target({METHOD})
    @Documented
    public @interface Dynamic {
        /**
         * Symboliczna nazwa systemu, do którego prowadzi wiązanie. Dopuszczalny
         * rozszerzony format w postaci system/protokół. Na przykład:
         * "postgreSQL/jpa", "postgreSQL/odbc", "timeserver/ntp" ...
         * @return default = ""
         */
        String invoker() default "";
    }

    /**
     * Implementacja metody zawiera kod wygenerowany dynamicznie
     */
    @Retention(RUNTIME)
    @Target({CONSTRUCTOR,METHOD})
    @Documented
    public static @interface Generated {

        /**
         * Symboliczna nazwa użytego generatora
         * @return default = ""
         */
        String generator() default "";

        /**
         * W jaki sposób  kod jest integrowany z istniejącą implementacją metody
         * @return default = {@code GenerationStrategy.MANUAL}
         */
        GenerationStrategy strategy() default GenerationStrategy.MANUAL;
    }


    /**
     * Pole ma nadawaną wartość tylko raz, ale poza konstruktorem. Na przykład
     * procedurze {@code onInit}, {@code onCreate} lub podobnej.
     */
    @Retention(RUNTIME)
    @Target({FIELD})
    @Documented
    public @interface Final {
        /**
         * Symboliczna nazwa metody, w której następuje inicjalizacja (create, init, show, etc etc)
         * @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 {

        boolean threadsafe() default true;

    }


    /**
     * Metoda obsługi zdarzenia. Przeznaczona tylko jako wywołanie zwrotne, a nie
     * bezpośrednie.
     */
    @Retention(RUNTIME)
    @Target(METHOD)
    @Documented
    public @interface EventHandler {
        /**
         * Symboliczna nazwa zdarzenia, do którego obsługi metoda jest przeznaczona
         * @return default = ""
         */
        String value() default "";

        /**
         * Czy obsługa ma być uruchomiona w wątku AWT
         * @return default = {@link SyncStrategy#NONE}
         */
        SyncStrategy sync() default SyncStrategy.NONE;

    }

    /**
     * Metoda obsługi wyjątku. Przeznaczona tylko jako wywołanie zwrotne, a nie
     * bezpośrednie.
     */
    @Retention(RUNTIME)
    @Target(METHOD)
    @Documented
    public @interface ErrorHandler {
    }

    /**
     * <p>
     * Jeśli funkcja z dowolnego powodu wymaga szczególnej ostrożności,
     * to powinna tym być oznaczona. Przykłady zachowań:</p>
     * <ul>
     *      <li>funkcja wykonuje rzutowania "unchecked"</li>
     *      <li>"undefined behaviour" w niektórych warunkach</li>
     *      <li>"expose internal array"</li>
     *      <li>może powodować rece condition</li>
     *      <li>zwraca null zamiast uczciwie rzucać wyjątek</li>
     * </ul>
     */
    @Retention(RUNTIME)
    @Target({TYPE, METHOD, CONSTRUCTOR})
    @Documented
    public @interface Unsafe {
    }

    /**
     * Adnotowana klasa jest implementacją interfejsu obsługiwanego za pomocą
     * {@link ServiceLoader}. Powinien zostać wygenerowany odpowiedni wpis do
     * manifestu pliku JAR.
     */
    @Retention(SOURCE)
    @Documented
    @Target(TYPE)
    public @interface JavaService {
        /**
         * Jeśli klasa implementuje więcej niż jeden interfejs, to należy wskazać
         * interfejs, która powinien zostać wyeksportowany w manifeście.
         * @return
         */
        Class value() default void.class;
    }

}
