/*
 * Copyright (c) 2004-2017, by Alex Leigh.
 * All rights reserved.
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
 * The copyright notice above does not evidence any
 * actual or intended publication of such source code.
 */

package lc.mecha.lang;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

/**
 * Simple implementation of an event router.
 *
 * @author Alex Leigh
 */
public class EventRouter<K> {
    private static final Logger logger = LoggerFactory.getLogger(EventRouter.class);
    private final HashMap<K, Set<EventHandler>> handlers = new HashMap<>();

    /**
     * Add the given handler to the given key. The handler will begin receiving events for which it is
     * registered.
     *
     * @param key
     * @param handler
     */
    public void addHandler(final K key, final EventHandler handler) {
        Set<EventHandler> keyHandlers = handlers.get(key);
        if (keyHandlers == null) {
            keyHandlers = new HashSet<>();
            handlers.put(key, keyHandlers);
        }
        keyHandlers.add(handler);
    }

    /**
     * Remove the given handler from the given key. The handler will stop receiving events for which
     * it is registered.
     *
     * @param key
     * @param handler
     * @return
     */
    public boolean removeHandler(final K key, final EventHandler handler) {
        final Set<EventHandler> keyHandlers = handlers.get(key);
        return keyHandlers != null && keyHandlers.remove(handler);
    }

    public void send(final K key, final Event evt) {
        logger.debug("Sending event: {} {}", key, evt);
        // FIXME: The performance of this is terrible, but we do it to prevent concurrent modification exceptions

        // Send to the handlers which have criteria
        Set<EventHandler> h = handlers.get(key);
        if (h != null) {
            final Set<EventHandler> keyHandlers = new HashSet(handlers.get(key));
            if (keyHandlers == null) return;
            for (final EventHandler handler : keyHandlers) {
                handler.handleEvent(evt);
            }
        }

        // Send to the null handlers
        h = handlers.get(null);
        if (h != null) {
            final Set<EventHandler> keyHandlers = new HashSet(handlers.get(null));
            if (keyHandlers == null) return;

            for (final EventHandler handler : handlers.get(null)) {
                handler.handleEvent(evt);
            }
        }
    }
}
