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.core.BasicClass;
    18  import org.as2lib.util.ObjectUtil;
    19  import org.as2lib.env.except.IllegalArgumentException;
    20  import org.as2lib.env.reflect.ReflectUtil;
    21  import org.as2lib.data.holder.Queue;
    22  import org.as2lib.data.holder.Iterator;
    23  
    24  /**
    25   * {@code TypedQueue} is a wrapper for {@link Queue} instances that ensures that
    26   * only values of a specific type can be added to the wrapped queue.
    27   * 
    28   * <p>This class simply delegates all method invocations to the wrapped queue. If
    29   * the specific method is responsible for adding values it first checks if the values
    30   * to add are of the expected type. If they are the method invocation is forwarded,
    31   * otherwise an {@link IllegalArgumentException} is thrown.
    32   *
    33   * @author Simon Wacker
    34   */
    35  class org.as2lib.data.holder.queue.TypedQueue extends BasicClass implements Queue {
    36  	
    37  	/** The wrapped queue. */
    38  	private var queue:Queue;
    39  	
    40  	/** The type of the values that can be added. */
    41  	private var type:Function;
    42  	
    43  	/**
    44  	 * Constructs a new {@code TypedQueue} instance.
    45  	 *
    46  	 * <p>If the passed-in {@code queue} does already contain values, these values do
    47  	 * not get type-checked.
    48  	 * 
    49  	 * @param type the type of the values that are allowed to be added
    50  	 * @param queue the queue to wrap
    51  	 * @throws IllegalArgumentException if the passed-in {@code type} is {@code null}
    52  	 * or {@code undefined}
    53  	 * @throws IllegalArgumentException if {@code queue} is {@code null} or
    54  	 * {@code undefined}
    55  	 */
    56  	public function TypedQueue(type:Function, queue:Queue) {
    57  		if (!type) throw new IllegalArgumentException("Argument 'type' [" + type + "] must not be 'null' nor 'undefined'.", this, arguments);
    58  		if (!queue) throw new IllegalArgumentException("Argument 'queue' [" + queue + "] must not be 'null' nor 'undefined'.", this, arguments);
    59  		this.type = type;
    60  		this.queue = queue;
    61  	}
    62  	
    63  	/**
    64  	 * Returns the type that all values in the wrapped queue have.
    65  	 *
    66  	 * <p>This is the type passed-in on construction.
    67  	 *
    68  	 * @return the type the all values of the wrapped queue have
    69  	 */
    70  	public function getType(Void):Function {
    71  		return type;
    72  	}
    73  	
    74  	/**
    75  	 * Adds the passed-in {@code value} to this queue.
    76  	 *
    77  	 * <p>The value is only enqueued if it is of the expected type.
    78  	 *
    79  	 * @param value the value to add
    80  	 * @throws IllegalArgumentException if the type of the passed-in {@code value} is
    81  	 * invalid
    82  	 */
    83  	public function enqueue(value):Void {
    84  		validate(value);
    85  		queue.enqueue(value);
    86  	}
    87  	
    88  	/**
    89  	 * Removes the firstly inserted value.
    90  	 *
    91  	 * @return the firstly inserted value
    92  	 * @throws org.as2lib.data.holder.EmptyDataHolderException if this queue is empty
    93  	 */
    94  	public function dequeue(Void) {
    95  		return queue.dequeue();
    96  	}
    97  	
    98  	/**
    99  	 * Returns the firstly inserted value.
   100  	 *
   101  	 * @return the firstly inserted value
   102  	 * @throws org.as2lib.data.holder.EmptyDataHolderException if this queue is empty
   103  	 */
   104  	public function peek(Void) {
   105  		return queue.peek();
   106  	}
   107  	/**
   108  	 * Returns an iterator that can be used to iterate over the values of this queue.
   109  	 * 
   110  	 * @return an iterator to iterate over this queue's values
   111  	 * @see #toArray
   112  	 */
   113  	public function iterator(Void):Iterator {
   114  		return queue.iterator();
   115  	}
   116  	
   117  	/**
   118  	 * Returns whether this queue contains any values.
   119  	 *
   120  	 * @return {@code true} if this queue contains no values else {@code false}
   121  	 */
   122  	public function isEmpty(Void):Boolean {
   123  		return queue.isEmpty();
   124  	}
   125  	
   126  	/**
   127  	 * Returns the number of enqueued elements.
   128  	 *
   129  	 * @return the number of enqueued elements
   130  	 * @see #enqueue
   131  	 */
   132  	public function size(Void):Number {
   133  		return queue.size();
   134  	}
   135  	
   136  	/**
   137  	 * Returns an array representation of this queue.
   138  	 *
   139  	 * <p>The elements are copied onto the array in a 'first-in, first-out' order,
   140  	 * similar to the order of the elements returned by a succession of calls to the
   141  	 * {@link #dequeue} method.
   142  	 * 
   143  	 * @return the array representation of this queue
   144  	 */
   145  	public function toArray(Void):Array {
   146  		return queue.toArray();
   147  	}
   148  	
   149  	/**
   150  	 * Returns the string representation of the wrapped queue.
   151  	 *
   152  	 * @return the string representation of the wrapped queue
   153  	 */
   154  	public function toString():String {
   155  		return queue.toString();
   156  	}
   157  	
   158  	/**
   159  	 * Validates the passed-in {@code value} based on its type.
   160  	 *
   161  	 * @param value the value whose type shall be validated
   162  	 * @throws IllegalArgumentException if the type of the {@code value} is invalid
   163  	 */
   164  	private function validate(value):Void {
   165  		if (!ObjectUtil.typesMatch(value, type)) {
   166  			throw new IllegalArgumentException("Type mismatch between value [" + value + "] and type [" + ReflectUtil.getTypeNameForType(type) + "].", this, arguments);
   167  		}
   168  	}
   169  	
   170  }