1  /*
     2   * Copyright the original author or authors.
     3   * 
     4   * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   * 
     8   *      http://www.mozilla.org/MPL/MPL-1.1.html
     9   * 
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  import org.as2lib.env.except.AbstractOperationException;
    18  import org.as2lib.env.event.TypeSafeEventListenerSource;
    19  
    20  /**
    21   * {@code AbstractEventDistributorControl} offers default implementations of
    22   * methods needed when implementing the {@link EventDistributorControl} interface
    23   * or any sub-interface.
    24   * 
    25   * @author Simon Wacker
    26   */
    27  class org.as2lib.env.event.distributor.AbstractEventDistributorControl extends TypeSafeEventListenerSource {
    28  	
    29  	/** The distributor to distribute events. */
    30  	private var d;
    31  	
    32  	/**
    33  	 * Constructs a new {@code AbstractEventDistributorControl} instance.
    34  	 *
    35  	 * <p>{@code checkListenerType} is by default set to {@code true}.
    36  	 *
    37  	 * @param listenerType the expected type of listeners
    38  	 * @param checkListenerType determines whether to check that passed-in listeners
    39  	 * are of the expected type
    40  	 * @throws IllegalArgumentException if the passed-in {@code listenerType} is
    41  	 * {@code null} or {@code undefined}
    42  	 */
    43  	public function AbstractEventDistributorControl(listenerType:Function, checkListenerType:Boolean) {
    44  		super (listenerType, checkListenerType);
    45  	}
    46  	
    47  	/**
    48  	 * Returns the type of listeners this distributor expects. This is also the type of
    49  	 * the distributor returned by the {@link #getDistributor} method.
    50  	 * 
    51  	 * @return the type of the distributor and listeners
    52  	 */
    53  	public function getType(Void):Function {
    54  		return t;
    55  	}
    56  	
    57  	/**
    58  	 * Returns the distributor to distribute the event to all added listeners.
    59  	 *
    60  	 * <p>The returned distributor can be casted to the type specified on construction.
    61  	 * You can then invoke the event method on it to distribute it to all added
    62  	 * listeners. This event distribution approach has the advantage of proper
    63  	 * compile-time type-checking.
    64  	 *
    65  	 * <p>The returned distributor throws an {@link EventExecutionException} on
    66  	 * distribution if an event method of a listener threw an exception.
    67  	 * 
    68  	 * <p>This method does always return the same distributor.
    69  	 * 
    70  	 * @return the distributor to distribute the event
    71  	 */
    72  	public function getDistributor(Void) {
    73  		if (!this.d) this.d = createDistributor();
    74  		return this.d;
    75  	}
    76  	
    77  	/**
    78  	 * Creates a new distributor based on the listener type specified on construction.
    79  	 *
    80  	 * <p>The catching of methods called on the returned distributor takes place using
    81  	 * {@code __resolve}. This method then invokes the {@link #distribute} method with
    82  	 * the name of the called method and the arguments used for the method call.
    83  	 * 
    84  	 * @return the new distributor
    85  	 */
    86  	private function createDistributor(Void) {
    87  		var result = new Object();
    88  		var t:Function = getListenerType();
    89  		result.__proto__ = t.prototype;
    90  		result.__constructor__ = t;
    91  		var e:AbstractEventDistributorControl = this;
    92  		//var d:Function = e["distribute"];
    93  		result.__resolve = function(n:String):Function {
    94  			return (function():Void {
    95  				//d.apply(e, n, arguments); causes 255 recursion error
    96  				// e.distribute is not MTASC compatible because "distribute" is private
    97  				e["distribute"](n, arguments);
    98  			});
    99  		};
   100  		var p:Object = t.prototype;
   101  		while (p != Object.prototype) {
   102  			for (var i:String in p) {
   103  				result[i] = function():Void {
   104  					// e.distribute is not MTASC compatible because "distribute" is private
   105  					e["distribute"](arguments.callee.n, arguments);
   106  				};
   107  				result[i].n = i;
   108  			}
   109  			p = p.__proto__;
   110  		}
   111  		return result;
   112  	}
   113  	
   114  	/**
   115  	 * Executes the event with the given {@code eventName} on all added listeners, using
   116  	 * the arguments after {@code eventName} as parameters.
   117  	 * 
   118  	 * @param eventName the name of the event method to execute on the added listeners
   119  	 * @param args any number of arguments that are used as parameters on execution of
   120  	 * the event on the listeners
   121  	 * @throws EventExecutionException if an event method on a listener threw an
   122  	 * exception
   123  	 */
   124  	private function distribute(eventName:String, args:Array):Void {
   125  		throw new AbstractOperationException("This method is marked as abstract and must be overwritten.", this, arguments);
   126  	}
   127  	
   128  }