package de.renew.net.event;


/**
 * A {@code TransitionEventListenerSet} manages a collection
 * of transition event listeners and is able to distribute events
 * to all of its listeners.
 * <p>
 * Synchronization is done on this object.
 * <p>
 * When an event is delivered synchronously, it is ensured that
 * the event set is locked, but that changes to the set of listeners
 * do not affect the current notifications.
 *
 * @author <a href="mailto:kummer@informatik.uni-hamburg.de">Olaf Kummer</a>
 */
public class TransitionEventListenerSet extends ListenerSet implements TransitionEventProducer {
    /**
     * Constructs a new TransitionEventListenerSet.
     */
    public TransitionEventListenerSet() {}

    @Override
    public synchronized void addTransitionEventListener(TransitionEventListener listener) {
        include(listener);
    }

    @Override
    public synchronized void removeTransitionEventListener(TransitionEventListener listener) {
        exclude(listener);
    }

    /**
     * Informs all TransitionEventListeners that an instance
     * has just started firing.
     * <p>
     * This method is called by all instances of this transition
     * if they have to send such an event.
     *
     * @param firingEvent the {@link FiringEvent} to distribute
     * <p>
     * {@link de.renew.net.TransitionInstance}
     **/
    public synchronized void firingStarted(final FiringEvent firingEvent) {
        dispatch(listener -> ((TransitionEventListener) listener).firingStarted(firingEvent));
    }

    /**
     * Informs all TransitionEventListeners that an instance
     * has just completed firing.
     * <p>
     * This method is called by all instances of this transition
     * if they have to send such an event.
     *
     * @param firingEvent the {@link FiringEvent} to distribute
     * <p>
     * {@link de.renew.net.TransitionInstance}
     **/
    public synchronized void firingComplete(final FiringEvent firingEvent) {
        dispatch(listener -> ((TransitionEventListener) listener).firingComplete(firingEvent));
    }
}