package org.kitteh.irc.event;

import org.kitteh.irc.util.Pair;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Manages them events.
 */
public final class EventManager {
    private final Map<Class<?>, Set<Pair<Object, Method>>> registeredEvents = new ConcurrentHashMap<>();

    public void registerEvents(Object object) {
        try {
            Method[] methods = object.getClass().getDeclaredMethods();
            for (Method method : methods) {
                if (Modifier.isStatic(method.getModifiers())) {
                    continue;
                }
                EventHandler handler = method.getAnnotation(EventHandler.class);
                if (handler == null) {
                    continue;
                }
                Class<?>[] types = method.getParameterTypes();
                if (types.length != 1) {
                    System.out.println("Event handlers must only have one parameter. Invalid method " + method.getName());
                    continue;
                }
                method.setAccessible(true);
                this.getSet(types[0]).add(new Pair<>(object, method));
            }
        } catch (Exception e) {
            System.out.println("Exception registering " + object.getClass().getSimpleName() + ":");
            e.printStackTrace();
        }
    }

    public void callEvent(Object event) {
        Set<Pair<Object, Method>> set = this.registeredEvents.get(event.getClass());
        if (set != null) {
            for (Pair<Object, Method> pair : set) {
                try {
                    pair.getB().invoke(pair.getA(), event);
                } catch (Throwable thrown) {
                    System.out.println("Exception calling event " + event.getClass().getSimpleName() + " in " + pair.getA().getClass().getSimpleName());
                }
            }
        }
    }

    private synchronized Set<Pair<Object, Method>> getSet(Class<?> type) {
        Set<Pair<Object, Method>> set = this.registeredEvents.get(type);
        if (set != null) {
            set = Collections.newSetFromMap(new ConcurrentHashMap<Pair<Object, Method>, Boolean>());
            this.registeredEvents.put(type, set);
        }
        return set;
    }
}
@@ -420,16 +420,413 @@
 p%3C%3E();%0A%0A
+    /**%0A     * Registers any non-static methods annotated with%0A     * %7B@link org.kitteh.irc.event.EventHandler%7D, provided they have a single%0A     * parameter. This parameter is the event.%0A     * %3Cp/%3E%0A     * The class listened to must be the same class called in%0A     * %7B@link #callEvent(Object)%7D, not a super or subclass.%0A     *%0A     * @param listener listener in which to register events%0A     */%0A
     publ
@@ -850,23 +850,32 @@
 vent
-s(Object object
+Listener(Object listener
 ) %7B%0A
@@ -919,22 +919,24 @@
 thods = 
-object
+listener
 .getClas
@@ -1069,98 +1069,11 @@
 s())
-) %7B%0A                    continue;%0A                %7D%0A                EventHandler handler =
+ %7C%7C
  met
@@ -1113,37 +1113,8 @@
 ass)
-;%0A                if (handler
  == 
@@ -1389,24 +1389,77 @@
 od.getName()
+ + %22 in class %22 + listener.getClass().getSimpleName()
 );%0A         
@@ -1594,22 +1594,24 @@
  Pair%3C%3E(
-object
+listener
 , method
@@ -1722,14 +1722,16 @@
 %22 + 
-object
+listener
 .get
@@ -1808,24 +1808,104 @@
    %7D%0A    %7D%0A%0A
+    /**%0A     * Calls an event.%0A     *%0A     * @param event event to call%0A     */%0A
     public v

Document event manager