package it.gotoandplay.smartfoxclient;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * SFSEventDispatcher is used by the
 * {@link it.gotoandplay.smartfoxclient.SmartFoxClient} class to notify about
 * SmartFoxServer related events.
 * 
 * @see it.gotoandplay.smartfoxclient.SmartFoxClient
 * @see it.gotoandplay.smartfoxclient.SFSEvent
 * @see ISFSEventListener
 * 
 * @version 1.0.0
 * 
 * @author The gotoAndPlay() Team<br>
 *         <a
 *         href="http://www.smartfoxserver.com">http://www.smartfoxserver.com<
 *         /a><br>
 *         <a href="http://www.gotoandplay.it">http://www.gotoandplay.it</a><br>
 */
public class SFSEventDispatcher {
	private final ConcurrentHashMap <String, Set <ISFSEventListener>> listeners;

	/**
	 * The constructor.
	 */
	public SFSEventDispatcher () {
		listeners = new ConcurrentHashMap <String, Set <ISFSEventListener>> ();
	}

	/**
	 * Adds a new event listener. Multiple listeners can be registered for
	 * single event and single listener can be registered for multiple events.
	 * 
	 * <p>
	 * When event is dispached SFSEventDispatcher calls all listeners that are
	 * registered for the event but dosen't call them in any particular order.
	 * </p>
	 * 
	 * @param event the name of the event that listener listens for.
	 * @param listener the event listener.
	 * 
	 * @return {@code true} if the listener is registered, otherwise {@code
	 *         flase}. Listener may not be registered if its already registered
	 *         for the same event.
	 * 
	 * @throws java.lang.NullPointerException if listener == null
	 */
	public boolean addEventListener (final String event,
			final ISFSEventListener listener)
			throws NullPointerException {
		if (listener == null) {
			throw new NullPointerException (
					"Listener could not be null.");
		}

		listeners.putIfAbsent (event,
				new CopyOnWriteArraySet <ISFSEventListener> ());

		return listeners.get (event).add (listener);
	}

	/*
	 * Dispaches a new event.
	 * 
	 * @param eventObject the object that represent the event.
	 */
	public void dispatchEvent (final SFSEvent eventObject) {
		final String eventName = eventObject.getName ();
		if (listeners.containsKey (eventName)) {
			for (final ISFSEventListener listener : listeners
					.get (eventName)) {
				listener.handleEvent (eventObject);
			}
		}
	}

	/**
	 * Removes event listener.
	 * 
	 * @param event the name of the event listener was registered for.
	 * @param listener the listener that should be removed.
	 * 
	 * @return {@code true} if the listener is removed, otherwise {@code flase}.
	 *         Listener may not be removed if its haven't been registered for
	 *         this event or its already removed.
	 */
	public boolean removeEventListener (final String event,
			final ISFSEventListener listener) {
		if (listeners.containsKey (event)) {
			return listeners.get (event).remove (listener);
		}
		return false;
	}
}
