001package net.minecraftforge.event;
002
003import java.lang.reflect.Constructor;
004import java.lang.reflect.Method;
005import java.util.ArrayList;
006import java.util.Set;
007import java.util.concurrent.ConcurrentHashMap;
008
009
010
011import com.google.common.reflect.TypeToken;
012
013public class EventBus
014{
015    private static int maxID = 0;
016    
017    private ConcurrentHashMap<Object, ArrayList<IEventListener>> listeners = new ConcurrentHashMap<Object, ArrayList<IEventListener>>();
018    private final int busID = maxID++;
019
020    public EventBus()
021    {
022        ListenerList.resize(busID + 1);
023    }
024    
025    public void register(Object target)
026    {
027        Set<? extends Class<?>> supers = TypeToken.of(target.getClass()).getTypes().rawTypes();
028        for (Method method : target.getClass().getMethods())
029        {
030            for (Class<?> cls : supers)
031            {
032                try
033                {
034                    Method real = cls.getDeclaredMethod(method.getName(), method.getParameterTypes());
035                    if (real.isAnnotationPresent(ForgeSubscribe.class))
036                    {
037                        Class<?>[] parameterTypes = method.getParameterTypes();
038                        if (parameterTypes.length != 1)
039                        {
040                            throw new IllegalArgumentException(
041                                "Method " + method + " has @ForgeSubscribe annotation, but requires " + parameterTypes.length +
042                                " arguments.  Event handler methods must require a single argument."
043                            );
044                        }
045                        
046                        Class<?> eventType = parameterTypes[0];
047                        
048                        if (!Event.class.isAssignableFrom(eventType))
049                        {
050                            throw new IllegalArgumentException("Method " + method + " has @ForgeSubscribe annotation, but takes a argument that is not a Event " + eventType); 
051                        }
052                                                
053                        register(eventType, target, method);
054                        break;
055                    }
056                }
057                catch (NoSuchMethodException e)
058                {
059                    ;
060                }
061            }
062        }
063    }
064
065    private void register(Class<?> eventType, Object target, Method method)
066    {
067        try
068        {
069            Constructor<?> ctr = eventType.getConstructor();
070            ctr.setAccessible(true);
071            Event event = (Event)ctr.newInstance();
072            ASMEventHandler listener = new ASMEventHandler(target, method);
073            event.getListenerList().register(busID, listener.getPriority(), listener);
074
075            ArrayList<IEventListener> others = listeners.get(target); 
076            if (others == null)
077            {
078                others = new ArrayList<IEventListener>();
079                listeners.put(target, others);
080            }
081            others.add(listener);
082        }
083        catch (Exception e)
084        {
085            e.printStackTrace();
086        }
087    }
088
089    public void unregister(Object object)
090    {
091        ArrayList<IEventListener> list = listeners.remove(object);
092        for (IEventListener listener : list)
093        {
094            ListenerList.unregiterAll(busID, listener);
095        }
096    }
097    
098    public boolean post(Event event)
099    {
100        IEventListener[] listeners = event.getListenerList().getListeners(busID);
101        for (IEventListener listener : listeners)
102        {
103            listener.invoke(event);
104        }
105        return (event.isCancelable() ? event.isCanceled() : false);
106    }
107}