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.data.holder.Queue;
    19  import org.as2lib.data.holder.Iterator;
    20  import org.as2lib.data.holder.array.ArrayIterator;
    21  import org.as2lib.data.holder.EmptyDataHolderException;
    22  import org.as2lib.util.Stringifier;
    23  import org.as2lib.data.holder.queue.QueueStringifier;
    24  
    25  /**
    26   * {@code LinearQueue} stores values in a 'first-in, first-out' manner.
    27   * 
    28   * <p>This class is a linear implementation of the {@code Queue} interface. This
    29   * means that enqueued values are stored in a linear manner and that you can store
    30   * as many values as you please. There are also queues that store values in a cyclic
    31   * manner. These queues can normally only hold a prescribed number of values and
    32   * overwrite old values or throw an exception if you try to enqueue more values.
    33   *
    34   * <p>'first-in, first-out' means that the first value that has been enqueued/added
    35   * to the queue is the first that gets dequeued/removed.
    36   * 
    37   * <p>The usage of a queue is quite simple. You have one method to add/enqueue values
    38   * {@link #enqueue} and one method to remove/dequeue them {@link #dequeue}. You can
    39   * also peek at the beginning of the queue to see what value has been added/enqueued
    40   * at first without removing it {@link #peek}.
    41   *
    42   * <p>If you want to iterate over the values of the queue you can either use the
    43   * iterator returned by the {@link #iterator} method or the array that contains the
    44   * queue's values returned by the {@link #toArray} method.
    45   * 
    46   * <p>The two methods {@link #isEmpty} and {@link #size} let you find
    47   * out whether the queue contains values and how many values it contains.
    48   * 
    49   * <p>You can modify the string representation that is returned by the {@link #toString}
    50   * method with the static {@link #setStringifier} method.
    51   *
    52   * <p>Example:
    53   * <code>
    54   *   // construct the queue
    55   *   var queue:Queue = new LinearQueue();
    56   *   queue.enqueue("value1");
    57   *   queue.enqueue("value2");
    58   *   queue.enqueue("value3");
    59   *   // use the queue
    60   *   trace(queue.peek());
    61   *   while (!queue.isEmpty()) {
    62   *       trace(queue.pop());
    63   *   }
    64   * </code>
    65   *
    66   * <p>Output:
    67   * <pre>
    68   *   value1
    69   *   value1
    70   *   value2
    71   *   value3
    72   * </pre>
    73   * 
    74   * <p>You can alternatively pass-in the content of the queue on construction.
    75   * <code>
    76   *   var queue:Queue = new LinearQueue(["value1", "value2", "value3"]);
    77   *   // ..
    78   * </code>
    79   *
    80   * @author Simon Wacker
    81   */
    82  class org.as2lib.data.holder.queue.LinearQueue extends BasicClass implements Queue {
    83  	
    84  	/** Stringifies queues. */
    85  	private static var stringifier:Stringifier;
    86  	
    87  	/** Contains the inserted elements. */
    88  	private var data:Array;
    89  	
    90  	/**
    91  	 * Returns the stringifier that stringifies queues.
    92  	 *
    93  	 * <p>If no stringifier has been set manually via the static {@link #setStringifier}
    94  	 * method an instance of class {@link QueueStringifier} will be returned.
    95  	 * 
    96  	 * @return the stringifier that stringifies queues
    97  	 */
    98  	public static function getStringifier(Void):Stringifier {
    99  		if (!stringifier) stringifier = new QueueStringifier();
   100  		return stringifier;
   101  	}
   102  	
   103  	/**
   104  	 * Sets the new stringifier that stringifies queues.
   105  	 * 
   106  	 * <p>If the passed-in {@code queueStringifier} is {@code null} or {@code undefined},
   107  	 * the static {@link #getStringifier} method will return the default stringifier.
   108  	 *
   109  	 * @param queueStringifier the new queue stringifier
   110  	 */
   111  	public static function setStringifier(queueStringifier:Stringifier):Void {
   112  		stringifier = queueStringifier;
   113  	}
   114  	
   115  	/**
   116  	 * Constructs a new {@code LinearQueue} instance.
   117  	 *
   118  	 * <p>The queue steps through the passed-in {@code source} beginning at position 0
   119  	 * and enqueues all contained elements.
   120  	 * 
   121  	 * <p>Example:
   122  	 * <code>
   123  	 *   var queue:LinearQueue = new LinearQueue([1, 2, 3]);
   124   	 *   while (!queue.isEmpty()) {
   125  	 * 	     trace(queue.dequeue());
   126  	 *   }
   127  	 * </code>
   128  	 *
   129  	 * <p>The output is made in the following order: 1, 2, 3
   130  	 * 
   131  	 * @param source (optional) an array that contains values to populate this queue with
   132  	 */
   133  	public function LinearQueue(source:Array) {
   134  		if (source) {
   135  			data = source.concat();
   136  		} else {
   137  			data = new Array();
   138  		}
   139  	}
   140  	
   141  	/**
   142  	 * Adds the passed-in {@code value} to this queue.
   143  	 *
   144  	 * <p>{@code null} and {@code undefined} values are allowed.
   145  	 *
   146  	 * @param value the value to add
   147  	 */
   148  	public function enqueue(value):Void {
   149  		data.push(value);
   150  	}
   151  	
   152  	/**
   153  	 * Removes and returns the firstly inserted value.
   154  	 *
   155  	 * @return the firstly inserted value
   156  	 * @throws EmptyDataHolderException if this queue is empty
   157  	 */
   158  	public function dequeue(Void) {
   159  		if (isEmpty()) {
   160  			throw new EmptyDataHolderException("You tried to dequeue an element from an empty Queue.", this, arguments);
   161  		}
   162  		return data.shift();
   163  	}
   164  	
   165  	/**
   166  	 * Returns the firstly inserted value.
   167  	 *
   168  	 * @return the firstly inserted value
   169  	 * @throws EmptyDataHolderException if this queue is empty
   170  	 */
   171  	public function peek(Void) {
   172  		if (isEmpty()) {
   173  			throw new EmptyDataHolderException("You tried to peek an element from an empty Queue.", this, arguments);
   174  		}
   175  		return data[0];
   176  	}
   177  	
   178  	/**
   179  	 * Returns an iterator that can be used to iterate over the values of this queue.
   180  	 * 
   181  	 * @return an iterator to iterate over this queue's values
   182  	 * @see #toArray
   183  	 */
   184  	public function iterator(Void):Iterator {
   185  		return (new ArrayIterator(data.concat()));
   186  	}
   187  	
   188  	/**
   189  	 * Returns whether this queue contains any values.
   190  	 *
   191  	 * @return {@code true} if this queue contains no values else {@code false}
   192  	 */
   193  	public function isEmpty(Void):Boolean {
   194  		return (data.length < 1);
   195  	}
   196  	
   197  	/**
   198  	 * Returns the number of enqueued elements.
   199  	 *
   200  	 * @return the number of enqueued elements
   201  	 * @see #enqueue
   202  	 */
   203  	public function size(Void):Number {
   204  		return data.length;
   205  	}
   206  	
   207  	/**
   208  	 * Returns an array representation of this queue.
   209  	 *
   210  	 * <p>The elements are copied onto the array in a 'first-in, first-out' order,
   211  	 * similar to the order of the elements returned by a succession of calls to the
   212  	 * {@link #dequeue} method.
   213  	 * ################################################################################
   214  	 * @return the array representation of this queue
   215  	 */
   216  	public function toArray(Void):Array {
   217  		return data.concat();
   218  	}
   219  	
   220  	/**
   221  	 * Returns the string representation of this queue.
   222  	 *
   223  	 * <p>The string representation is obtained via the stringifier returned by the
   224  	 * static {@link #getStringifier} method.
   225  	 * 
   226  	 * @return the string representation of this queue
   227  	 */
   228  	public function toString():String {
   229  		return getStringifier().execute(this);
   230  	}
   231  	
   232  }