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 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(String event, 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);
    }
    
    /**
     * 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(String event, ISFSEventListener listener)
    {
        if(listeners.containsKey(event))
        {
            return listeners.get(event).remove(listener);
        }
        else
        {
            return false;
        }
    }
    
    /*
     * Dispaches a new event.
     * 
     * @param eventObject the object that represent the event.
     */
    public void dispatchEvent(SFSEvent eventObject)
    {
        String eventName = eventObject.getName();
        if(listeners.containsKey(eventName))
        {
            for(ISFSEventListener listener : listeners.get(eventName))
            {
                listener.handleEvent(eventObject);
            }
        }
    }
}