package il.co.codeguru.corewars8086.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * An event multicaster which broadcasts Events to a number of listeners.
 * @author BS
 */
public class EventMulticaster {
    
    private Class mListenerInterface;
    private EventListener mProxy;
    private Set<EventListener> mListeners = new HashSet<EventListener>();
    private Set<EventListener> mWaitingListeners = new HashSet<EventListener>();
    private boolean isCasting;

    /** Construct a new EventMulticaster for the given listener class.
     */
    public EventMulticaster(Class pListenerInterface) {
        if (! EventListener.class.isAssignableFrom(pListenerInterface) ) {
            throw new IllegalArgumentException("Listener interface must extend java.util.EventListener.");
        }
        mListenerInterface = pListenerInterface;
    }
    
    /** Add an event listener to the list.
     */
    public void add(EventListener pListener) {
    	if (isCasting) {
    		mWaitingListeners .add(pListener);
    	} else {
    		mListeners.add(pListener);
    	}
    }
    
    /** Remove an event listener from the list.
     */
    public void remove(EventListener pListener) {
        mListeners.remove(pListener);
    }

    /** Get the proxy for this event multicaster. This proxy can then be
     * used to broadcast events to all the registered event listeners.
     */
    public synchronized EventListener getProxy() {
        if ( mProxy == null ) {
            ClassLoader lCL = this.getClass().getClassLoader();
            Class[] lClasses = new Class[] {mListenerInterface};
            mProxy = (EventListener)Proxy.newProxyInstance(lCL,lClasses,new MulticasterInvocationHandler());
        }
        return mProxy;
    }
    
    /** Invokes the given method on each listener registered with the
     * multicaster.
     */
    private class MulticasterInvocationHandler implements InvocationHandler {
        public Object invoke(Object pProxy, Method pMethod, Object[] pArgs)
            throws Throwable {
            
            isCasting = true;
            Iterator lListeners = mListeners.iterator();
            while ( lListeners.hasNext() ) {
                pMethod.invoke(lListeners.next(),pArgs);
            }
            isCasting = false;
            if (mWaitingListeners.size() != 0) {
            	// listeners are waiting to be added, add them after multicasting
            	for (EventListener lis: mWaitingListeners) {
            		add(lis);
            	}
            	mWaitingListeners.clear();
            }
            return null;
        }
    } 
}
@@ -172,99 +172,9 @@
 til.
-EventListener;%0D%0Aimport java.util.HashSet;%0D%0Aimport java.util.Iterator;%0D%0Aimport java.util.Set
+*
 ;%0D%0A%0D
@@ -431,32 +431,38 @@
 eners = new 
+Linked
 HashSet%3C
 EventListene
@@ -449,32 +449,83 @@
 HashSet%3C
-EventListener%3E()
+%3E();%0D%0A%09private EventListener%5B%5D mListenersArr = new EventListener%5B0%5D
 ;%0D%0A    p
@@ -574,16 +574,22 @@
 s = new 
+Linked
 HashSet%3C
@@ -1256,24 +1256,101 @@
 );%0D%0A    %09%7D%0D%0A
+%09%09mListenersArr = mListeners.toArray(new EventListener%5BmListeners.size()%5D);%0D%0A
     %7D%0D%0A    %0D
@@ -1494,24 +1494,101 @@
 Listener);%0D%0A
+%09%09mListenersArr = mListeners.toArray(new EventListener%5BmListeners.size()%5D);%0D%0A
     %7D%0D%0A%0D%0A   
@@ -2451,38 +2451,29 @@
 e;%0D%0A
-            Iterator l
+%09%09%09for (Event
 Listener
 s = 
@@ -2468,19 +2468,16 @@
 Listener
-s =
  mListen
@@ -2482,85 +2482,33 @@
 ener
-s.iterator();%0D%0A            while ( lListeners.hasNext() ) %7B%0D%0A                
+ : mListenersArr) %7B%0D%0A%09%09%09%09
 pMet
@@ -2522,17 +2522,17 @@
 oke(
-l
+m
 Listener
 s.ne
@@ -2531,38 +2531,22 @@
 ener
-s.next(),pArgs);%0D%0A            
+, pArgs);%0D%0A%09%09%09
 %7D%0D%0A 
@@ -2592,16 +2592,17 @@
     if (
+!
 mWaiting
@@ -2615,19 +2615,17 @@
 ers.
-size() != 0
+isEmpty()
 ) %7B%0D

use array of listeners instead of HashMap iterator - improves performance considerably