/**
 * Extends the native <code>Array</code> class with the functions added in JavaScript 1.6.
 * <p>For more information, please visit 
 * <a href="http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6#Array_extras" target="_blank">http://developer.mozilla.org</a>.</p>
 * @class Array
 * @version 0.3
 * @author Henrik Lindqvist &lt;<a href="mailto:henrik.lindqvist@llamalab.com">henrik.lindqvist@llamalab.com</a>&gt;
 */
(function (ap) {

/**
 * Tests whether all elements in the array pass the 
 * test implemented by the provided function.
 * @function {boolean} every
 * @param {function} fn - function.
 * @param {optional object} thisp - <code>this</code> for function.
 * @returns passed
 */
if (!ap.every) {
  ap.every = function (fn, thisp) {
    for (var l = this.length, i = 0; --l >= 0; i++)
      if (i in this && !fn.call(thisp, this[i], i, this)) return false;
    return true;
  };
}
/**
 * Creates a new array with all elements that pass the test 
 * implemented by the provided function.
 * @function {Array} filter
 * @param {function} fn - function.
 * @param {optional object} thisp - <code>this</code> for function.
 * @returns new {@link Array}
 */
if (!ap.filter) {
  ap.filter = function(fn, thisp) {
    var r = [];
    for (var l = this.length, i = 0, v; --l >= 0; i++)
      if (i in this && fn.call(thisp, v = this[i], i, this)) r.push(v);
    return r;
  };
}
/**
 * Executes a provided function once per array element.
 * @function forEach
 * @param {function} fn - function.
 * @param {optional object} thisp - <code>this</code> for function.
 */
if (!ap.forEach) {
  ap.forEach = function (fn, thisp) {
    for (var l = this.length, i = 0; --l >= 0; i++)
      if (i in this) fn.call(thisp, this[i], i, this);
  };
}
/**
 * Returns the first index at which a given element can be 
 * found in the array, or -1 if it is not present.
 * @function {number} indexOf
 * @param {object} e - element.
 * @param {optional number} i - start index.
 * @returns index or -1
 */
if (!ap.indexOf) {
  ap.indexOf = function (e, i) {
    var l = this.length;
    i = (i < 0) ? Math.ceil(i) : (i > 0) ? Math.floor(i) : 0;
    if (i < 0) i += l;
    for (; i < l; i++)
      if (i in this && this[i] === e) return i;
    return -1;
  };
}
/**
 * Returns the last index at which a given element can be 
 * found in the array, or -1 if it is not present. The array 
 * is searched backwards.
 * @function {number} lastIndexOf
 * @param {object} e - element.
 * @param {optional number} i - start index.
 * @returns index or -1
 */
if (!ap.lastIndexOf) {
  ap.lastIndexOf = ap.lastIndexOf = function (e, i) {
    var l = this.length;
    if (isNaN(i)) i = l - 1;
    else {
      i = (i < 0) ? Math.ceil(i) : Math.floor(i);
      if (i < 0) i += l;
      else if (i >= l) i = l - 1;
    }
    for (; i >= 0; i--)
      if (i in this && this[i] === e) return i;
    return -1;
  };
}  
/**
 * Creates a new array with the results of calling a provided 
 * function on every element in this array.
 * @function {Array} map
 * @param {function} fn - function.
 * @param {optional object} thisp - <code>this</code> for function.
 * @returns new {@link Array}
 */
if (!ap.map) {
  ap.map = function (fn, thisp) {
    var l = this.length, r = new Array(l);
    for (var i = 0; --l >= 0; i++)
      if (i in this) r[i] = fn.call(thisp, this[i], i, this);
    return r;
  };
}
/**
 * Tests whether some element in the array passes the test 
 * implemented by the provided function.
 * @function {boolean} some
 * @param {function} fn - function.
 * @param {optional object} thisp - <code>this</code> for function.
 * @returns passed
 */
if (!ap.some) {
  ap.some = function (fn, thisp) {
    for (var l = this.length, i = 0; --l >= 0; i++)
      if (i in this && fn.call(thisp, this[i], i, this))
        return true;
    return false;
  };
}
// Array Generics
[ 'join', 'concat', 'pop', 'push', 'reverse',
  'shift', 'slice', 'sort', 'splice', 'unshift',
  // 1.6
  'indexOf', 'lastIndexOf', 'filter', 'forEach',
  'every', 'map', 'some'
].forEach(function (n) { 
  if (!Array[n]) 
    Array[n] = new Function('return Function.prototype.call.apply(Array.prototype.'+n+', arguments)');
});

})(Array.prototype);