/*
 * Change two array elements
 * @param {Array} arr array to affect
 * @param {Number} first element index
 * @param {Number} second element index
 */
function swap (arr, a, b) {
  var tmp=arr[a];
  arr[a]=arr[b];
  arr[b]=tmp;
}
/*
 * Sort process
 * @param {Array} array array to sort
 * @param {Number} begin  start index
 * @param {Number} end end index
 * @param {Number} pivot end index
 * @param {Boolean} key sort by key
 * @param {Boolean} desc descending sort
 * @param {Boolean} cins insensitive sort
 */
function partition(array, begin, end, pivot, key, desc, cins) {
  var piv;
  piv = key ? array[pivot][key] : array[pivot];
  piv  = (cins & isNaN(piv)) ? piv.toLowerCase() : piv;

  swap(array, pivot, end-1);
  var store=begin;
  var ix;
  for(ix=begin; ix<end-1; ++ix) {
    val = key ? array[ix][key] : array[ix];
    val = (cins & isNaN(val)) ? val.toLowerCase() : val;
    if (desc) {
      if(val > piv) {
        swap(array, store, ix);
        ++store;
      }
    } else {
      if(val < piv) {
        swap(array, store, ix);
        ++store;
      }
    }
   } 

  swap(array, end-1, store);
  return store;
}
/*
 * Agregate sort method calls
 * @param {Array} array array to sort
 * @param {Number} begin  start index
 * @param {Number} end end index
 * @param {Boolean} key sort by key
 * @param {Boolean} desc descending sort
 * @param {Boolean} cins insensitive sort
 */
function processSort(array, begin, end, key, desc, cins) {
  if(end-1>begin) {
    //before there was Math.random() instead of 0.25 - changed cause of swapping of equal values
    var pivot=begin+Math.floor(0.25*(end-begin));
    pivot=partition(array, begin, end, pivot, key, desc, cins);
    processSort(array, begin, pivot, key, desc, cins);
    processSort(array, pivot+1, end, key, desc, cins);
  }
}
/*
 * Common wrapper to sort entire array
 * @param {Array} array array to sort
 * @param {Boolean} key sort by key
 * @param {Boolean} desc descending sort
 * @param {Boolean} cins insensitive sort
 */
function quickSort(array, key, desc, cins) {
  processSort(array, 0, array.length, key, desc, cins);
}
