package de.fe1k.game9.events;

import java.util.*;

public class EventManager {

	private class EventListenerMap extends HashMap<Class<? extends Event>, Set<EventListener<? extends Event>>> {}

	private EventListenerMap listeners;
	private EventListenerMap listenersOnce;

	public EventManager() {
		listeners = new EventListenerMap();
		listenersOnce = new EventListenerMap();
	}

	public <T extends Event> boolean register(Class<T> eventClass, EventListener<? super T> listener) {
		if (!listeners.containsKey(eventClass)) {
			listeners.put(eventClass, new HashSet<>());
		}
		return listeners.get(eventClass).add(listener);
	}

	public <T extends Event> boolean registerOnce(Class<T> eventClass, EventListener<? super T> listener) {
		if (!listenersOnce.containsKey(eventClass)) {
			listenersOnce.put(eventClass, new HashSet<>());
		}
		return listenersOnce.get(eventClass).add(listener);
	}

	public <T extends Event> boolean unregister(Class<T> eventClass, EventListener<? super T> listener) {
		return listeners.containsKey(eventClass) && listeners.get(eventClass).remove(listener);
	}

	@SuppressWarnings("unchecked")
	public <T extends Event> void trigger(T event) {
		Set<EventListener<T>> toCall = new HashSet<>();

		for (EventListenerMap listenerMap : new EventListenerMap[] {listeners, listenersOnce}) {
			Iterator<Map.Entry<Class<? extends Event>, Set<EventListener<? extends Event>>>> iter = listenerMap.entrySet().iterator();
			while(iter.hasNext()) {
				Map.Entry<Class<? extends Event>, Set<EventListener<? extends Event>>> entry = iter.next();
				if (!entry.getKey().isInstance(event)) {
					continue;
				}
				for (EventListener<? extends Event> eventListener : entry.getValue()) {
					toCall.add((EventListener<T>) eventListener);
				}
				if (listenerMap == listenersOnce) {
					iter.remove();
				}
			}
		}
		for (EventListener<T> listener : toCall) {
			listener.onEvent(event);
		}
	}

}

@@ -266,16 +266,100 @@
 sOnce;%0A%0A
+%09private Queue%3CEvent%3E     eventQueue;%0A%09private boolean          isAlreadyInvoking;%0A%0A
 %09public 
@@ -455,16 +455,51 @@
 rMap();%0A
+%09%09eventQueue = new LinkedList%3C%3E();%0A
 %09%7D%0A%0A%09pub
@@ -1239,32 +1239,301 @@
 ecked%22)%0A%09public 
+void trigger(Event event) %7B%0A%09%09eventQueue.add(event);%0A%09%09if (isAlreadyInvoking) %7B%0A%09%09%09return;%0A%09%09%7D%0A%09%09isAlreadyInvoking = true;%0A%09%09while (!eventQueue.isEmpty()) %7B%0A%09%09%09triggerOne(eventQueue.poll());%0A%09%09%7D%0A%09%09isAlreadyInvoking = false;%0A%09%7D%0A%0A%09@SuppressWarnings(%22unchecked%22)%0A%09private 
 %3CT extends Event
@@ -1546,16 +1546,19 @@
  trigger
+One
 (T event

add queue to EventManager for correct order of events