Coverage Report - org.as3collections.queues.PriorityIndexQueue
 
Classes in this File Line Coverage Branch Coverage Complexity
PriorityIndexQueue
100%
47/47
N/A
0
 
 1  
 /*
 2  
  * Licensed under the MIT License
 3  
  * 
 4  
  * Copyright 2010 (c) Flávio Silva, http://flsilva.com
 5  
  *
 6  
  * Permission is hereby granted, free of charge, to any person
 7  
  * obtaining a copy of this software and associated documentation
 8  
  * files (the "Software"), to deal in the Software without
 9  
  * restriction, including without limitation the rights to use,
 10  
  * copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  
  * copies of the Software, and to permit persons to whom the
 12  
  * Software is furnished to do so, subject to the following
 13  
  * conditions:
 14  
  *
 15  
  * The above copyright notice and this permission notice shall be
 16  
  * included in all copies or substantial portions of the Software.
 17  
  *
 18  
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 19  
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 20  
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 21  
  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 22  
  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 23  
  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 24  
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 25  
  * OTHER DEALINGS IN THE SOFTWARE.
 26  
  * 
 27  
  * http://www.opensource.org/licenses/mit-license.php
 28  
  */
 29  
 
 30  1
 package org.as3collections.queues 
 31  
 {
 32  
         import org.as3collections.ICollection;
 33  
         import org.as3collections.IIterator;
 34  
         import org.as3collections.lists.ArrayList;
 35  
         import org.as3collections.utils.CollectionUtil;
 36  
         import org.as3coreaddendum.errors.ClassCastError;
 37  
         import org.as3coreaddendum.events.IndexEvent;
 38  
         import org.as3coreaddendum.events.PriorityEvent;
 39  
         import org.as3coreaddendum.system.IComparator;
 40  
         import org.as3coreaddendum.system.IIndexable;
 41  
         import org.as3coreaddendum.system.IPriority;
 42  
         import org.as3coreaddendum.system.comparators.PriorityIndexComparator;
 43  
         import org.as3utils.ReflectionUtil;
 44  
 
 45  
         import flash.errors.IllegalOperationError;
 46  
         import flash.events.Event;
 47  
         import flash.events.IEventDispatcher;
 48  
 
 49  
         /**
 50  
          * This queue uses an <code>org.as3coreaddendum.system.comparators.PriorityIndexComparator</code> object to sort the elements.
 51  
          * All elements must implement the <code>org.as3coreaddendum.system.IPriority</code> and <code>org.as3coreaddendum.system.IIndexable</code> interfaces, otherwise a <code>org.as3coreaddendum.errors.ClassCastError</code> is thrown.
 52  
          * <p>This queue is useful when you want to sort the objects by priority, but if the priority of two objects are equal, the <code>index</code> property of the objects are compared to decide wich object comes before.</p>
 53  
          * <p>This queue also adds an event listener on elements to <code>org.as3coreaddendum.events.PriorityEvent</code> and <code>org.as3coreaddendum.events.IndexEvent</code> (if elements implement <code>flash.events.IEventDispatcher</code>).
 54  
          * Thus this queue keeps itself automatically sorted if its elements dispatch a <code>org.as3coreaddendum.events.PriorityEvent</code> or <code>org.as3coreaddendum.events.IndexEvent</code> when its priority or index changes.</p>
 55  
          * 
 56  
          * @example
 57  
          * 
 58  
          * <listing version="3.0">
 59  
          * package test
 60  
          * {
 61  
          *     import org.as3coreaddendum.system.IIndexable;
 62  
          *     import org.as3coreaddendum.system.IPriority;
 63  
          * 
 64  
          *     public class TestIndexablePriority implements IIndexable, IPriority
 65  
          *     {
 66  
          *         private var _index:int;
 67  
          *         private var _name:String;
 68  
          *         private var _priority:int;
 69  
          * 
 70  
          * 
 71  
          *         public function get priority(): int { return _priority; }
 72  
          * 
 73  
          *         public function set priority(value:int): void { _priority = value; }
 74  
          * 
 75  
          *         public function get index(): int { return _index; }
 76  
          * 
 77  
          *         public function set index(value:int): void { _index = value; }
 78  
          * 
 79  
          *         public function TestIndexablePriority(name:String, priority:int, index:int)
 80  
          *         {
 81  
          *             _name = name;
 82  
          *             _priority = priority;
 83  
          *             _index = index;
 84  
          *         }
 85  
          * 
 86  
          *         public function toString(): String
 87  
          *         {
 88  
          *             return "[TestIndexablePriority " + _name + "]";
 89  
          *         }
 90  
          *     }
 91  
          * }
 92  
          * </listing>
 93  
          * 
 94  
          * <listing version="3.0">
 95  
          * import org.as3collections.ISortedQueue;
 96  
          * import org.as3collections.queues.IndexablePriorityQueue;
 97  
          * import test.TestIndexablePriority;
 98  
          * 
 99  
          * var queue1:ISortedQueue = new IndexablePriorityQueue();
 100  
          * 
 101  
          * var o1:TestIndexablePriority = new TestIndexablePriority("o1", 1, 0);
 102  
          * var o2:TestIndexablePriority = new TestIndexablePriority("o2", 2, 1);
 103  
          * var o3:TestIndexablePriority = new TestIndexablePriority("o3", 2, 2);
 104  
          * var o4:TestIndexablePriority = new TestIndexablePriority("o4", 4, 3);
 105  
          * 
 106  
          * queue1.offer(o2)            // true
 107  
          * queue1                      // [[TestIndexablePriority o2]]
 108  
          * queue1.size()               // 1
 109  
          * 
 110  
          * queue1.offer(o3)            // true
 111  
          * queue1                      // [[TestIndexablePriority o2],[TestIndexablePriority o3]]
 112  
          * queue1.size()               // 2
 113  
          * 
 114  
          * queue1.offer(o2)            // true
 115  
          * queue1                      // [[TestIndexablePriority o2],[TestIndexablePriority o2],[TestIndexablePriority o3]]
 116  
          * 
 117  
          * queue1.offer(o1)            // true
 118  
          * queue1                      // [[TestIndexablePriority o2],[TestIndexablePriority o2],[TestIndexablePriority o3],[TestIndexablePriority o1]]
 119  
          * 
 120  
          * queue1.offer(o4)            // true
 121  
          * queue1                      // [[TestIndexablePriority o4],[TestIndexablePriority o2],[TestIndexablePriority o2],[TestIndexablePriority o3],[TestIndexablePriority o1]]
 122  
          * 
 123  
          * queue1.offer(1)             // false
 124  
          * queue1                      // [[TestIndexablePriority o4],[TestIndexablePriority o2],[TestIndexablePriority o2],[TestIndexablePriority o3],[TestIndexablePriority o1]]
 125  
          * 
 126  
          * queue1.add(1)               // ClassCastError: The element must implement the 'org.as3coreaddendum.system.IPriority' interface. Type received: int
 127  
          * </listing>
 128  
          * 
 129  
          * @see         http://as3coreaddendum.org/en-us/documentation/asdoc/org/as3coreaddendum/system/IPriority.html        org.as3coreaddendum.system.IPriority
 130  
          * @see         http://as3coreaddendum.org/en-us/documentation/asdoc/org/as3coreaddendum/system/IIndexable.html        org.as3coreaddendum.system.IIndexable
 131  
          * @see         http://as3coreaddendum.org/en-us/documentation/asdoc/org/as3coreaddendum/events/PriorityEvent.html        org.as3coreaddendum.events.PriorityEvent
 132  
          * @see         http://as3coreaddendum.org/en-us/documentation/asdoc/org/as3coreaddendum/events/IndexEvent.html        org.as3coreaddendum.events.IndexEvent
 133  
          * @author Flávio Silva
 134  
          */
 135  
         public class PriorityIndexQueue extends SortedQueue
 136  
         {
 137  
                 /**
 138  
                  * <code>IndexablePriorityQueue</code> does not allow changing its <code>comparator</code> object.
 139  
                  * <p><code>IndexablePriorityQueue</code> was designed to be used exclusively with its default comparator object.
 140  
                  * If you want to change the comparator object using this setter, consider using <code>SortedQueue</code> class instead.</p>
 141  
                  * <p>If this setter is used an <code>IllegalOperationError</code> is thrown.</p>
 142  
                  */
 143  
                 override public function set comparator(value:IComparator): void
 144  
                 {
 145  1
                         throw new IllegalOperationError("IndexablePriorityQueue does not allow changing its comparator object.\nIf you want to change it consider using SortedQueue class instead.");
 146  
                 }
 147  
                 
 148  
                 /**
 149  
                  * <code>IndexablePriorityQueue</code> does not allow changing its options.
 150  
                  * <p><code>IndexablePriorityQueue</code> was designed to be used exclusively with its default options.
 151  
                  * If you want to change the options using this setter, consider using <code>SortedQueue</code> class instead.</p>
 152  
                  * <p>If this setter is used an <code>IllegalOperationError</code> is thrown.</p>
 153  
                  */
 154  
                 override public function set options(value:uint): void
 155  
                 {
 156  1
                         throw new IllegalOperationError("IndexablePriorityQueue does not allow changing its options.\nIf you want to change it consider using SortedQueue class instead.");
 157  
                 }
 158  
                 
 159  
                 /**
 160  
                  * Constructor, creates a new <code>IndexablePriorityQueue</code> object.
 161  
                  * 
 162  
                  * @param         source                 an array to fill the queue.
 163  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if one or more elements in the <code>source</code> argument do not implement the <code>org.as3coreaddendum.system.IPriority</code> and <code>org.as3coreaddendum.system.IIndexable</code> interfaces.
 164  
                  */
 165  
                 public function PriorityIndexQueue(source:Array = null)
 166  
                 {
 167  1
                         validateCollection(new ArrayList(source));
 168  
                         
 169  1
                         super(source, new PriorityIndexComparator());
 170  1
                 }
 171  
 
 172  
                 /**
 173  
                  * Inserts the specified element into this queue if it is possible to do so immediately without violating restrictions.
 174  
                  * This method differs from <code>offer</code> only in that it throws an error if the element cannot be inserted.
 175  
                  * <p>This implementation returns the result of <code>offer</code> unless the element cannot be inserted.</p>
 176  
                  * <p>This implementation only allow elements that implements the <code>org.as3coreaddendum.system.IPriority</code> and <code>org.as3coreaddendum.system.IIndexable</code> interfaces.
 177  
                  * A <code>org.as3coreaddendum.errors.ClassCastError</code> is thrown if the element does not implements this interfaces.</p>
 178  
                  * 
 179  
                  * @param element
 180  
                  * @throws         ArgumentError          if the specified element is <code>null</code>.
 181  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the element does not implements the <code>org.as3coreaddendum.system.IPriority</code> or <code>org.as3coreaddendum.system.IIndexable</code> interfaces.
 182  
                  * @throws         flash.errors.IllegalOperationError                          if the specified element cannot be inserted.
 183  
                  * @return         <code>true</code> if this queue changed as a result of the call.
 184  
                  */
 185  
                 override public function add(element:*): Boolean
 186  
                 {
 187  1
                         if (element == null) throw new ArgumentError("The 'element' argument must not be 'null'.");
 188  1
                         validateElement(element);
 189  
                         
 190  1
                         var b:Boolean = offer(element);
 191  
                         
 192  1
                         if (!b) throw new IllegalOperationError("The element cannot be inserted: " + element);
 193  
                         
 194  1
                         return b;
 195  
                 }
 196  
 
 197  
                 /**
 198  
                  * Creates and return a new <code>IndexablePriorityQueue</code> object containing all elements in this queue (in the same order).
 199  
                  * 
 200  
                  * @return         a new <code>IndexablePriorityQueue</code> object containing all elements in this queue (in the same order).
 201  
                   */
 202  
                 override public function clone(): *
 203  
                 {
 204  1
                         var q:PriorityIndexQueue = new PriorityIndexQueue(data);
 205  1
                         return q;
 206  
                 }
 207  
 
 208  
                 /**
 209  
                  * Inserts the specified element into this queue if it is possible to do so immediately without violating restrictions.
 210  
                  * When using a restricted queue (like <code>TypedQueue</code> and <code>UniqueQueue</code>), this method is generally preferable to <code>add</code>, which can fail to insert an element only by throwing an error. 
 211  
                  * <p>This implementation only allow elements that implements the <code>org.as3coreaddendum.system.IPriority</code> and <code>org.as3coreaddendum.system.IIndexable</code> interfaces.
 212  
                  * If the element does not implements this interfaces the method returns <code>false</code>.</p>
 213  
                  * <p>Before returning, the queue is reordered.</p>
 214  
                  * 
 215  
                  * @param          element         the element to add.
 216  
                  * @return         <code>true</code> if the element was added to this queue, else <code>false</code>. 
 217  
                  */
 218  
                 override public function offer(element:*): Boolean
 219  
                 {
 220  1
                         if (element == null || !isValidElement(element)) return false;
 221  
                         
 222  1
                         return super.offer(element);
 223  
                 }
 224  
                 
 225  
                 /**
 226  
                  * @private
 227  
                  */
 228  
                 protected function isValidElement(element:*): Boolean
 229  
                 {
 230  1
                         return element is IPriority && element is IIndexable;
 231  
                 }
 232  
                 
 233  
                 /**
 234  
                  * @private
 235  
                  */
 236  
                 protected function validateCollection(collection:ICollection): void
 237  
                 {
 238  1
                         if (!collection || collection.isEmpty()) return;
 239  
                         //TODO:pensar em criar metodo em CollectionUtil que recebe varios types e valida. pensar em incluir em org.as3utils.ArrayUtil
 240  1
                         var containsOnlyTypePriority:Boolean = CollectionUtil.containsOnlyType(collection, IPriority, false);
 241  1
                         var containsOnlyTypeIndexable:Boolean = CollectionUtil.containsOnlyType(collection, IIndexable, false);
 242  1
                         if (containsOnlyTypePriority && containsOnlyTypeIndexable) return;
 243  
                         
 244  1
                         var it:IIterator = collection.iterator();
 245  
                         var element:*;
 246  
                         
 247  1
                         while (it.hasNext())
 248  
                         {
 249  1
                                 element = it.next();
 250  1
                                 if (!isValidElement(element)) break;
 251  
                         }
 252  
                         
 253  1
                         var error:ClassCastError = getInvalidElementError(element);
 254  1
                         throw error;
 255  
                 }
 256  
                 
 257  
                 /**
 258  
                  * @private
 259  
                  */
 260  
                 override protected function elementAdded(element:*):void
 261  
                 {
 262  1
                         super.elementAdded(element);
 263  1
                         if (element && element is IEventDispatcher) addPriorityIndexEventListenerToElement(element);
 264  1
                 }
 265  
                 
 266  
                 /**
 267  
                  * @private
 268  
                  */
 269  
                 override protected function elementRemoved(element:*):void
 270  
                 {
 271  1
                         super.elementRemoved(element);
 272  1
                         if (element && element is IEventDispatcher) removePriorityIndexEventListenerFromElement(element);
 273  1
                 }
 274  
                 
 275  
                 /**
 276  
                  * @private
 277  
                  */
 278  
                 protected function validateElement(element:*): void
 279  
                 {
 280  1
                         if (isValidElement(element)) return;
 281  
                         
 282  1
                         var error:ClassCastError = getInvalidElementError(element);
 283  1
                         throw error;
 284  
                 }
 285  
                 
 286  
                 /**
 287  
                  * @private
 288  
                  */
 289  
                 private function addPriorityIndexEventListenerToElement(element:IEventDispatcher):void
 290  
                 {
 291  1
                         element.addEventListener(IndexEvent.CHANGED, elementPriorityIndexChanged, false, 0, true);
 292  1
                         element.addEventListener(PriorityEvent.CHANGED, elementPriorityIndexChanged, false, 0, true);
 293  1
                 }
 294  
                 
 295  
                 /**
 296  
                  * @private
 297  
                  */
 298  
                 private function elementPriorityIndexChanged(event:Event):void
 299  
                 {
 300  1
                         _sort();
 301  1
                 }
 302  
                 
 303  
                 /**
 304  
                  * @private
 305  
                  */
 306  
                 private function getInvalidElementError(element:*): ClassCastError
 307  
                 {
 308  1
                         var message:String = "Element must implement org.as3coreaddendum.system.IPriority and org.as3coreaddendum.system.IIndexable\n";
 309  1
                         message += "element: <" + element + ">\n";
 310  1
                         message += "element type: <" + ReflectionUtil.getClassPath(element) + ">";
 311  
                         
 312  1
                         return new ClassCastError(message);
 313  
                 }
 314  
                 
 315  
                 /**
 316  
                  * @private
 317  
                  */
 318  
                 private function removePriorityIndexEventListenerFromElement(element:IEventDispatcher):void
 319  
                 {
 320  1
                         element.removeEventListener(IndexEvent.CHANGED, elementPriorityIndexChanged, false);
 321  1
                         element.removeEventListener(PriorityEvent.CHANGED, elementPriorityIndexChanged, false);
 322  1
                 }
 323  
 
 324  
         }
 325  
 
 326  
 }