/**
   * {@inheritDoc}
   *
   * @see com.blockhaus2000.ipm.technical.event.EventManager#register(java.lang.Class,
   *     java.lang.Object)
   */
  @Override
  public synchronized <T> void register(final Class<T> clazz, final T obj) {
    assert clazz != null : "Clazz cannot be null!";
    assert obj == null || obj.getClass().equals(clazz) : "Obj has to be an instance of clazz!";

    SimpleEventManager.LOGGER.debug("Registering listeners of class " + clazz);

    for (final Method method : clazz.getDeclaredMethods()) {
      this.register(new SimpleEventHandler(obj, method));
    }

    SimpleEventManager.LOGGER.debug("Registration finished");
  }
  /**
   * {@inheritDoc}
   *
   * @see
   *     com.blockhaus2000.ipm.technical.event.EventManager#fire(com.blockhaus2000.ipm.technical.event.AbstractEvent)
   */
  @Override
  public void fire(final AbstractEvent event) {
    assert event != null : "Event cannot be null!";

    SimpleEventManager.LOGGER.debug("Firing event " + event);

    if (event instanceof AbstractAsynchEvent) {
      this.internalFire(event);
    } else {
      synchronized (this) {
        this.internalFire(event);
      }
    }

    SimpleEventManager.LOGGER.debug("Firing finished");
  }
  /**
   * Fires the given event.
   *
   * @param event The event to fire.
   */
  private void internalFire(final AbstractEvent event) {
    assert event != null : "Event cannot be null!";

    final EventContext<AbstractEvent> context = new EventContext<AbstractEvent>(event);
    for (final EventHandler handler : event.getHandlers()) {
      if (!handler.isEnabled()) {
        // If the event handler is disabled, skip the execution.
        continue;
      }

      try {
        handler.getListenerMethod().invoke(handler.getListenerObject(), context);
      } catch (final IllegalArgumentException ex) {
        SimpleEventManager.LOGGER.error(
            "It seems that the event listener method \""
                + handler.getListenerMethod().getName()
                + "\" in class \""
                + handler.getListenerMethod().getDeclaringClass().getName()
                + "\" defines wrong arguments. The one and only argument should be a \""
                + EventContext.class.getName()
                + "\"!",
            ex);
      } catch (final IllegalAccessException ex) {
        SimpleEventManager.LOGGER.error(
            "An error occurred whilst firing event \""
                + event
                + "\" for method \""
                + handler.getListenerMethod().getName()
                + "\" in class \""
                + handler.getListenerMethod().getDeclaringClass().getName()
                + "\"!",
            ex);
      } catch (final InvocationTargetException ex) {
        SimpleEventManager.LOGGER.error(
            "An error occurred whilst firing event \""
                + event
                + "\" for method \""
                + handler.getListenerMethod().getName()
                + "\" in class \""
                + handler.getListenerMethod().getDeclaringClass().getName()
                + "\"!",
            ex);
      }
    }
  }
  /**
   * Registers the given event handler.
   *
   * @param handler The {@link EventHandler} to register.
   */
  protected synchronized void register(final EventHandler handler) {
    assert handler != null : "Handler cannot be null!";

    SimpleEventManager.LOGGER.debug("Registering event handler " + handler);

    final Object obj = handler.getListenerObject();
    final Method method = handler.getListenerMethod();
    final Class<?> clazz = method.getDeclaringClass();

    if (!method.isAnnotationPresent(EventListener.class)) {
      SimpleEventManager.LOGGER.debug("Skipping event handler " + handler);

      return;
    }

    SimpleEventManager.LOGGER.debug("Processing event handler " + handler);

    assert obj != null || Modifier.isStatic(method.getModifiers())
        : "Method \""
            + method.getName()
            + "\" in class \""
            + clazz.getName()
            + "\" cannot be non-static if obj is null!";
    assert method.getParameterTypes().length == 1
            && method.getParameterTypes()[0].equals(EventContext.class)
        : "The "
            + "arguments of the method \""
            + method.getName()
            + "\" in class \""
            + clazz.getName()
            + "\" are wrong! The first (and only) argument should have the type \""
            + EventContext.class.getName()
            + "\"!";

    final Class<? extends AbstractEvent> eventClass =
        method.getAnnotation(EventListener.class).value();

    final HandlerList handlers;
    try {
      final Field handlersField = eventClass.getDeclaredField("HANDLERS");

      final boolean handlersFieldAccessible = handlersField.isAccessible();
      handlersField.setAccessible(true);

      handlers = (HandlerList) handlersField.get(obj);

      handlersField.setAccessible(handlersFieldAccessible);
    } catch (final IllegalArgumentException cause) {
      throw new EventException(
          "An error occurred whilest retriving handler list from class \""
              + clazz.getName()
              + "\"!",
          cause);
    } catch (final SecurityException cause) {
      throw new EventException(
          "An error occurred whilest retriving handler list from class \""
              + clazz.getName()
              + "\"!",
          cause);
    } catch (final IllegalAccessException cause) {
      throw new EventException(
          "An error occurred whilest retriving handler list from class \""
              + clazz.getName()
              + "\"!",
          cause);
    } catch (final NoSuchFieldException cause) {
      throw new EventException(
          "An error occurred whilest retriving handler list from class \""
              + clazz.getName()
              + "\"!",
          cause);
    }

    handlers.add(new SimpleEventHandler(obj, method));

    SimpleEventManager.LOGGER.debug("Registration of event handler finished");
  }