001package net.minecraftforge.event;
002
003import static java.lang.annotation.ElementType.TYPE;
004import static java.lang.annotation.RetentionPolicy.RUNTIME;
005
006import java.lang.annotation.Retention;
007import java.lang.annotation.Target;
008import java.util.Map;
009import java.util.concurrent.ConcurrentHashMap;
010
011
012/**
013 * Base Event class that all other events are derived from
014 */
015public class Event
016{
017    @Retention(value = RUNTIME)
018    @Target(value = TYPE)
019    public @interface HasResult{}
020
021    public enum Result
022    {
023        DENY,
024        DEFAULT,
025        ALLOW
026    }
027
028    private boolean isCanceled = false;
029    private final boolean isCancelable;
030    private Result result = Result.DEFAULT;
031    private final boolean hasResult;
032    private static ListenerList listeners = new ListenerList();
033
034    private static final Map<Class, Map<Class, Boolean>> annotationMap = new ConcurrentHashMap<Class, Map<Class, Boolean>>();
035    
036    public Event()
037    {
038        setup();
039        isCancelable = hasAnnotation(Cancelable.class);
040        hasResult = hasAnnotation(HasResult.class);
041    }
042
043    private boolean hasAnnotation(Class annotation)
044    {
045        Class me = this.getClass();
046        Map<Class, Boolean> list = annotationMap.get(me);
047        if (list == null)
048        {
049            list = new ConcurrentHashMap<Class, Boolean>();
050            annotationMap.put(me, list);
051        }
052
053        Boolean cached = list.get(annotation);
054        if (cached != null)
055        {
056            return cached;
057        }
058
059        Class cls = me;
060        while (cls != Event.class)
061        {
062            if (cls.isAnnotationPresent(annotation))
063            {
064                list.put(annotation, true);
065                return true;
066            }
067            cls = cls.getSuperclass();
068        }
069
070        list.put(annotation, false);
071        return false;
072    }
073
074    /**
075     * Determine if this function is cancelable at all. 
076     * @return If access to setCanceled should be allowed
077     */
078    public boolean isCancelable()
079    {
080        return isCancelable;
081    }
082
083    /**
084     * Determine if this event is canceled and should stop executing.
085     * @return The current canceled state
086     */
087    public boolean isCanceled()
088    {
089        return isCanceled;
090    }
091
092    /**
093     * Sets the state of this event, not all events are cancelable, and any attempt to
094     * cancel a event that can't be will result in a IllegalArgumentException.
095     * 
096     * The functionality of setting the canceled state is defined on a per-event bases.
097     * 
098     * @param cancel The new canceled value
099     */
100    public void setCanceled(boolean cancel)
101    {
102        if (!isCancelable())
103        {
104            throw new IllegalArgumentException("Attempted to cancel a uncancelable event");
105        }
106        isCanceled = cancel;
107    }
108
109    /**
110     * Determines if this event expects a significant result value.
111     */
112    public boolean hasResult()
113    {
114        return hasResult;
115    }
116
117    /**
118     * Returns the value set as the result of this event
119     */
120    public Result getResult()
121    {
122        return result;
123    }
124
125    /**
126     * Sets the result value for this event, not all events can have a result set, and any attempt to
127     * set a result for a event that isn't expecting it will result in a IllegalArgumentException.
128     * 
129     * The functionality of setting the result is defined on a per-event bases.
130     * 
131     * @param value The new result
132     */
133    public void setResult(Result value)
134    {
135        result = value;
136    }
137    /**
138     * Called by the base constructor, this is used by ASM generated 
139     * event classes to setup various functionality such as the listener's list.
140     */
141    protected void setup()
142    {
143    }
144    
145    /**
146     * Returns a ListenerList object that contains all listeners
147     * that are registered to this event.
148     * 
149     * @return Listener List
150     */
151    public ListenerList getListenerList()
152    {
153        return listeners;
154    }
155}