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.env.except.IllegalArgumentException;
    19  import org.as2lib.data.holder.NoSuchElementException;
    20  
    21  /**
    22   * {@code ArrayUtil} contains fundamental methods to manipulate {@code Array}s.
    23   * 
    24   * @author Simon Wacker
    25   * @author Martin Heidegger
    26   * @author Christophe Herreman
    27   */
    28  class org.as2lib.util.ArrayUtil extends BasicClass {
    29  	
    30  	/**
    31  	 * Clones an array.
    32  	 *
    33  	 * @param array the array to clone
    34  	 * @return a clone of the passed-in {@code array}
    35  	 */
    36  	public static function clone(array:Array):Array {
    37  		return array.concat();
    38  	}
    39  	
    40  	/**
    41  	 * Removes the given {@code element} out of the passed-in {@code array}.
    42  	 * 
    43  	 * @param array the array to remove the element out of
    44  	 * @param element the element to remove
    45  	 * @return {@code true} if {@code element} was removed and {@code false} if it was
    46  	 * not contained in the passed-in {@code array}
    47  	 */
    48  	public static function removeElement(array:Array, element):Array {
    49  		return removeAllOccurances(array, element);
    50  	}
    51  	
    52  	
    53  	/**
    54  	 * Removes all occurances of a the given {@code element} out of the passed-in
    55  	 * {@code array}.
    56  	 * 
    57  	 * @param array the array to remove the element out of
    58  	 * @param element the element to remove	 
    59  	 * @return List that contains the index of all removed occurances
    60  	 */
    61  	public static function removeAllOccurances(array:Array, element):Array {
    62  		var i:Number = array.length;
    63  		var found:Array = new Array();
    64  		while (--i-(-1)) {
    65  			if (array[i] === element) {
    66  				found.unshift(i);
    67  				array.splice(i, 1);
    68  			}
    69  		}
    70  		return found;
    71  	}
    72  	
    73  	/**
    74  	 * Removes the last occurance of the given {@code element} out of the passed-in
    75  	 * {@code array}.
    76  	 * 
    77  	 * @param array the array to remove the element out of
    78  	 * @param element the element to remove
    79  	 * @return {@code -1} if it could not be found, else the position where it had been deleted
    80  	 */
    81  	public static function removeLastOccurance(array:Array, element):Number {
    82  		var i:Number = array.length;
    83  		while(--i-(-1)) {
    84  			if(array[i] === element) {
    85  				array.splice(i, 1);
    86  				return i;
    87  			}
    88  		}
    89  		return -1;
    90  	}
    91  	
    92  	/**
    93  	 * Removes the first occurance of the given {@code element} out of the passed-in
    94  	 * {@code array}.
    95  	 * 
    96  	 * @param array the array to remove the element out of
    97  	 * @param element the element to remove
    98  	 * @return {@code -1} if it could not be found, else the position where it had been deleted
    99  	 */
   100  	public static function removeFirstOccurance(array:Array, element):Number {
   101  		var l:Number = array.length;
   102  		var i:Number = 0;
   103  		while(i<l) {
   104  			if (array[i] === element) {
   105  				array.splice(i, 1);
   106  				return i;
   107  			}
   108  			i-=-1;
   109  		}
   110  		return -1;
   111  	}
   112  	
   113  	/**
   114  	 * Checks if the passed-in {@code array} contains the given {@code object}.
   115  	 * 
   116  	 * <p>The content is searched through with a for..in loop. This enables any type of
   117  	 * array to be passed-in, indexed and associative arrays.
   118  	 * 
   119  	 * @param array the array that may contain the {@code object}
   120  	 * @param object the object that may be contained in the {@code array}
   121  	 * @return {@code true} if the {@code array} contains the {@code object} else
   122  	 * {@code false}
   123  	 */
   124  	public static function contains(array:Array, object):Boolean {
   125  		for (var i:String in array) {
   126  			if (array[i] === object) {
   127  				return true;
   128  			}
   129  		}
   130  		return false;
   131  	}
   132  	
   133  	/**
   134  	 * Returns the index of first occurance of the given {@code object} within
   135  	 * the passed-in {@code array}.
   136  	 * 
   137  	 * <p>The content of the {@code array} is searched through by iterating through the
   138  	 * array. This method returns the first occurence of the passed-in {@code object}
   139  	 * within the {@code array}. If the object could not be found {@code -1} will be
   140  	 * returned.
   141  	 * 
   142  	 * @param array the array to search through
   143  	 * @param object the object to return the position of
   144  	 * @return the position of the {@code object} within the {@code array} or {@code -1}
   145  	 */
   146  	public static function indexOf(array:Array, object):Number{
   147  		for (var i:Number=0; i < array.length; i++) {
   148  			if (array[i] === object) {
   149  				return i;
   150  			}
   151  		}
   152  		return -1;
   153  	}
   154  	
   155  	/**
   156  	 * Returns the index of the last occurance of the given {@code object} within
   157  	 * the passed-in {@code array}.
   158  	 * 
   159  	 * <p>The content of the {@code array} is searched through by iterating through the
   160  	 * array. This method returns the last occurence of the passed-in {@code object}
   161  	 * within the {@code array}. If the object could not be found {@code -1} will be
   162  	 * returned.
   163  	 * 
   164  	 * @param array the array to search through
   165  	 * @param object the object to return the position of
   166  	 * @return the position of the {@code object} within the {@code array} or {@code -1}
   167  	 */
   168  	public static function lastIndexOf(array:Array, object):Number{
   169  	    var i:Number = array.length;
   170  		while (--i-(-1)) {
   171  			if (array[i] === object) {
   172  				return i;
   173  			}
   174  		}
   175  		return -1;
   176  	}
   177  	
   178  	/**
   179  	 * Shuffles the passed-in {@code array}.
   180  	 * 
   181  	 * @param array the array to shuffle
   182  	 */
   183  	public static function shuffle(array:Array):Void {
   184  		var len:Number = array.length; 
   185  		var rand:Number;
   186  		var temp;
   187  		for (var i:Number = len-1; i >= 0; i--){ 
   188  			rand = Math.floor(Math.random()*len); 
   189  			temp = array[i]; 
   190  			array[i] = array[rand]; 
   191  			array[rand] = temp; 
   192  		} 
   193  	}
   194  	
   195  	
   196  	/**
   197  	 * Swaps the value at position {@code i} with the value at position {@code j} of the
   198  	 * passed-in {@code array}.
   199  	 *
   200  	 * <p>The modifications are directly made to the passed-in {@code array}.
   201  	 * 
   202  	 * @param array the array whose elements to swap
   203  	 * @param i the index of the first value
   204  	 * @param j the index of the second value
   205  	 * @return array the passed-in {@code array}
   206  	 * @throws IllegalArgumentException if the argument {@code array} is {@code null}
   207  	 * @throws NoSuchElementException if the passed-in positions {@code i} and {@code j}
   208  	 * are less than 0 or greater than the array's length
   209  	 */
   210  	public static function swap(array:Array, i:Number, j:Number):Array {
   211  		if (!array) {
   212  			throw new IllegalArgumentException("Array to swap content has to be available", eval("th"+"is"), arguments);
   213  		}
   214  		if (i > array.length-1 || i < 0) {
   215  			throw new NoSuchElementException("The first index "+i+" is not available within the array", eval("th"+"is"), arguments);
   216  		}
   217  		if (j > array.length-1 || j < 0) {
   218  			throw new NoSuchElementException("The second index "+j+" is not available within the array", eval("th"+"is"), arguments);
   219  		}
   220  		var tmp = array[i];
   221  		array[i] = array[j];
   222  		array[j] = tmp;
   223  		return array;
   224  	}
   225  	
   226  	/**
   227  	 * Compares the two arrays {@code array1} and {@code array2}, whether they contain
   228  	 * the same values at the same positions.
   229  	 * 
   230  	 * @param array1 the first array for the comparison
   231  	 * @param array2 the second array for the comparison
   232  	 * @return {@code true} if the two arrays contain the same values at the same
   233  	 * positions else {@code false}
   234  	 */
   235  	public static function isSame(array1:Array, array2:Array):Boolean {
   236  		var i:Number = array1.length;
   237  		if (i != array2.length) {
   238  			return false;
   239  		}
   240  		while (--i-(-1)) {
   241  			if (array1[i] !== array2[i]) {
   242  				return false;
   243  			}
   244  		}
   245  		return true;
   246  	}
   247  	
   248  	/**
   249  	 * Private constructor.
   250  	 */
   251  	private function ArrayUtil(Void) {
   252  	}
   253  	
   254  }