//---------------------------------------------------------------------------------
//Usefull prototype methods for JavaScript
//---------------------------------------------------------------------------------
Number.max = function (a,b) {
    return a<b?b:a;
}

Number.min = function (a,b) {
    return a>b?b:a;
}

Math.mod = function(val,mod) {
    if (val < 0) {
        while(val<0) val += mod;
        return val;
    } else {
        return val%mod;
    }
}

window.getInnerWidth = function() {
    if (window.innerWidth) {
        return window.innerWidth;
    } else if (document.body.clientWidth) {
        return document.body.clientWidth;
    } else if (document.documentElement.clientWidth) {
        return document.documentElement.clientWidth;
    }
}

window.getInnerHeight = function() {
    if (window.innerHeight) {
        return window.innerHeight;
    } else if (document.body.clientHeight) {
        return document.body.clientHeight;
    } else if (document.documentElement.clientHeight) {
        return document.documentElement.clientHeight;
    }
}

String.prototype.endsWith = function(str) {
    return (this.length-str.length)==this.lastIndexOf(str);
}

String.prototype.reverse = function() {
    var s = "";
    var i = this.length;
    while (i>0) {
        s += this.substring(i-1,i);
        i--;
    }
    return s;
}

// this trim was suggested by Tobias Hinnerup
//String.prototype.trim = function() {
//    return(this.replace(/^\s+/,'').replace(/\s+$/,''));
//}


String.prototype.toInt = function() {
    var a = new Array();
    for (var i = 0; i < this.length; i++) {
        a[i] = this.charCodeAt(i);
    }
    return a;
}

Array.prototype.intArrayToString = function() {
    var a = new String();
    for (var i = 0; i < this.length; i++) {
        if(typeof this[i] != "number") {
            throw new Error("Array must be all numbers");
        } else if (this[i] < 0) {
            throw new Error("Numbers must be 0 and up");
        }
        a += String.fromCharCode(this[i]);
    }
    return a;
}

Array.prototype.compareArrays = function(arr) {
    if (this.length != arr.length) return false;
    for (var i = 0; i < arr.length; i++) {
        if (this[i].compareArrays) { //likely nested array
            if (!this[i].compareArrays(arr[i])) return false;
            else continue;
        }
        if (this[i] != arr[i]) return false;
    }
    return true;
}

//Array.prototype.map = function(fnc) {
//    var a = new Array(this.length);
//    for (var i = 0; i < this.length; i++) {
//        a[i] = fnc(this[i]);
//    }
//    return a;
//}

Array.prototype.foldr = function(fnc,start) {
    var a = start;
    for (var i = this.length-1; i > -1; i--) {
        a = fnc(this[i],a);
    }
    return a;
}

Array.prototype.foldl = function(fnc,start) {
    var a = start;
    for (var i = 0; i < this.length; i++) {
        a = fnc(this[i],a);
    }
    return a;
}

Array.prototype.exists = function (x) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] == x) return true;
    }
    return false;
}

Array.prototype.filter = function(fnc) {
    var a = new Array();
    for (var i = 0; i < this.length; i++) {
        if (fnc(this[i])) {
            a.push(this[i]);
        }
    }
    return a;
}

Array.prototype.random = function() {
    return this[Math.floor((Math.random()*this.length))];
}


//---------------------------------------------------------------------------------
//Filed: Sun, Mar 04 2007 under Programming|| Tags: toolbox javascript popular list
//---------------------------------------------------------------------------------
//#0 - Trim.
//Trim is one of the things that leave you scratching your head wondering why it was never included in the language to begin with. Thanks to prototyping however it's fairly easy to make up for the original oversight.
String.prototype.trim = function() {
   return this.replace(/^\s+|\s+$/g,"");
}
String.prototype.ltrim = function() {
   return this.replace(/^\s+/g,"");
}
String.prototype.rtrim = function() {
   return this.replace(/\s+$/g,"");
}

String.prototype.mbtrim = function() {
   return this.replace(/^[\s　]+|[\s　]+$/g,"");
}
String.prototype.mbltrim = function() {
   return this.replace(/^[\s　]+/g,"");
}
String.prototype.mbrtrim = function() {
   return this.replace(/[\s　]+$/g,"");
}


//#1 - Numeric Sort.
//Javascript's Array object has a sort() method, and a pretty quick and fast one at that. Unfortunately, by default, it only sorts alphabetically. Which means if you pass it an array of numbers it will sort the array alphabetically instead of numerically (1,15,100,2,25,200 instead of 1,2,15,25,100,200). This is easy enough to fix however by adding a new method called sortNum which will sort a numerical array very nicely.
Array.prototype.sortNum = function() {
   return this.sort( function (a,b) { return a-b; } );
}


//#2 - Formatting Numbers
//Formatting a number with commas is an all-too-often needed ability which is not a part of the core language. Here's a short and sweet tool that will correct that deficiency and another function to revert the formatted string back into a usable number. Simply supply a number and an optional prefix ('$' for example) and get back a formatted (or unformatted) string.
function formatNumber(num,prefix){
   prefix = prefix || '';
   num += '';
   var splitStr = num.split('.');
   var splitLeft = splitStr[0];
   var splitRight = splitStr.length > 1 ? '.' + splitStr[1] : '';
   var regx = /(\d+)(\d{3})/;
   while (regx.test(splitLeft)) {
      splitLeft = splitLeft.replace(regx, '$1' + ',' + '$2');
   }
   return prefix + splitLeft + splitRight;
}

function unformatNumber(num) {
   return num.replace(/([^0-9\.\-])/g,'')*1;
}


//#3 - Search an Array
//A frequent task involving arrays is to actually find some data stored there. Javascript has no built in function to search an array but we can create a prototype to work around the omission.
Array.prototype.find = function(searchStr) {
  var returnArray = false;
  for (i=0; i<this.length; i++) {
    if (typeof(searchStr) == 'function') {
      if (searchStr.test(this[i])) {
        if (!returnArray) { returnArray = [] }
        returnArray.push(i);
      }
    } else {
      if (this[i]===searchStr) {
        if (!returnArray) { returnArray = [] }
        returnArray.push(i);
      }
    }
  }
  return returnArray;
}


//#4 - HTML Entities
//The need to escape HTML control characters (&, <, > ) is a relatively new wrinkle in web-design, but with the ability for web pages to reach out and grab RSS newsfeeds directly from the source instead of a proxy, there comes a need to format the data in a way which will prevent uncontrolled HTML from being displayed on your pages. All this function does is take a string and covert &, <, and > to their respective HTML escape codes.
String.prototype.htmlEntities = function () {
   return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
};
String.prototype.stripTags = function () {
   return this.replace(/<([^>]+)>/g,'');
}


//#5 - Is it an object, or is it an Array?
//Finding out if an Array is, well, an Array is actually a non-trivial task in Javascript. It's one of those things that lurks in the shadow waiting to pounce when you finally need to make that determination. The code is so light-weight that it's worth keeping in your toolbox if as nothing more than a virtual rabbits foot.
function isArray(testObject) {
    return testObject && !(testObject.propertyIsEnumerable('length')) && typeof testObject === 'object' && typeof testObject.length === 'number';
}
Object.prototype.isArray = function() {
   return this.constructor == Array;
}


//#6 - Cookies!
//Cookies are a fact of life on the Web and the tools javascript gives you to work with them are woefully inadequate. There are however, 4 simple functions which will let you work with cookies almost as easily as working with a variable.
function cookiesAllowed() {
   setCookie('checkCookie', 'test', 1);
   if (getCookie('checkCookie')) {
      deleteCookie('checkCookie');
      return true;
   }
   return false;
}

function setCookie(name,value,expires, options) {
   if (options===undefined) { options = {}; }
   if ( expires ) {
      var expires_date = new Date();
      expires_date.setDate(expires_date.getDate() + expires)
   }
   document.cookie = name+'='+escape( value ) +
      ( ( expires ) ? ';expires='+expires_date.toGMTString() : '' ) +
      ( ( options.path ) ? ';path=' + options.path : '' ) +
      ( ( options.domain ) ? ';domain=' + options.domain : '' ) +
      ( ( options.secure ) ? ';secure' : '' );
}

function getCookie( name ) {
   var start = document.cookie.indexOf( name + "=" );
   var len = start + name.length + 1;
   if ( ( !start ) && ( name != document.cookie.substring( 0, name.length ) ) ) {
      return null;
   }
   if ( start == -1 ) return null;
   var end = document.cookie.indexOf( ';', len );
   if ( end == -1 ) end = document.cookie.length;
   return unescape( document.cookie.substring( len, end ) );
}

function deleteCookie( name, path, domain ) {
   if ( getCookie( name ) ) document.cookie = name + '=' +
      ( ( path ) ? ';path=' + path : '') +
      ( ( domain ) ? ';domain=' + domain : '' ) +
      ';expires=Thu, 01-Jan-1970 00:00:01 GMT';
}


//#7 - Function Mapping
//While it's easy enough to write a function to go through each element of an array, it's often easier and makes more sense to have the array call a specific function for each of its elements. This time-saving little trick comes in handy more often than you would think. Here we'll just create a map prototype which accepts a function you want each element of the array passed through. It will return an array with the processed values.
Array.prototype.map = function(f) {
  var returnArray=[];
  for (i=0; i<this.length; i++) {
    returnArray.push(f(this[i]));
  }
  return returnArray;
}


//#8 - Controling Stylesheets
//Web designers have been controlling HTML styles with javascript for nearly a decade now. But altering and modifying the stylesheets themselves has remained a bit of a mystery. With the right tools in your toolbox though, controlling stylesheet rules are as easy as applying styles to an object you retrieved with getElementById or getElementsbyTagName. What this means is that you can disable all of your forms and form elements with just a few lines of code, or reactivate them, or change the layout of your entire page, on the fly, in real time.
function getCSSRule(ruleName, deleteFlag) {
   ruleName=ruleName.toLowerCase();
   if (document.styleSheets) {
      for (var i=0; i<document.styleSheets.length; i++) {
         var styleSheet=document.styleSheets[i];
         var ii=0;
         var cssRule=false;
         do {
            if (styleSheet.cssRules) {
               cssRule = styleSheet.cssRules[ii];
            } else {
               cssRule = styleSheet.rules[ii];
            }
            if (cssRule)  {
               if (cssRule.selectorText.toLowerCase()==ruleName) {
                  if (deleteFlag=='delete') {
                     if (styleSheet.cssRules) {
                        styleSheet.deleteRule(ii);
                     } else {
                        styleSheet.removeRule(ii);
                     }
                     return true;
                  } else {
                     return cssRule;
                  }
               }
            }
            ii++;
         } while (cssRule)
      }
   }
   return false;
}

function killCSSRule(ruleName) {
  return getCSSRule(ruleName,'delete');
}

function addCSSRule(ruleName) {
  if (document.styleSheets) {
    if (!getCSSRule(ruleName)) {
      if (document.styleSheets[0].addRule) {
        document.styleSheets[0].addRule(ruleName, null,0);
      } else {
        document.styleSheets[0].insertRule(ruleName+' { }', 0);
      }
    }
  }
  return getCSSRule(ruleName);
}


//#9 - getElementsByClassName
//It's coming. In the next version of Firefox, getElementsByClassName will be added (and quite possibly in IE8 as well) and is part of a working draft by a group which makes recommendations to the standards body. Until that day, however, the following prototype will let you retrieve elements by class the same way you do it with getElementsByTagName and getElementById. Note that the name is left getElementsByClass so as not to interfere with the upcoming getElementsByClassName addition in newer browsers.
Object.prototype.getElementsByClass = function (searchClass, tag) {
   var returnArray = [];
   tag = tag || '*';
   var els = this.getElementsByTagName(tag);
   var pattern = new RegExp('(^|\\s)'+searchClass+'(\\s|$)');
   for (var i = 0; i < els.length; i++) {
      if ( pattern.test(els[i].className) ) {
         returnArray.push(els[i]);
      }
   }
   return returnArray;
}


//#10 - AJAX
//Any toolbox that doesn't have at least a bare-bones AJAX routine in it isn't worthy of the name toolbox. So here's a basic AJAX object that will allow for concurrent AJAX requests in a nice, tight little package.
function ajaxObject(url, callbackFunction) {
  var that=this;
  this.updating = false;
  this.abort = function() {
    if (that.updating) {
      that.updating=false;
      that.AJAX.abort();
      that.AJAX=null;
    }
  }
  this.update = function(passData,postMethod) {
    if (that.updating) { return false; }
    that.AJAX = null;
    if (window.XMLHttpRequest) {
      that.AJAX=new XMLHttpRequest();
    } else {
      that.AJAX=new ActiveXObject("Microsoft.XMLHTTP");
    }
    if (that.AJAX==null) {
      return false;
    } else {
      that.AJAX.onreadystatechange = function() {
        if (that.AJAX.readyState==4) {
          that.updating=false;
          that.callback(that.AJAX.responseText,that.AJAX.status,that.AJAX.responseXML);
          that.AJAX=null;
        }
      }
      that.updating = new Date();
      if (/post/i.test(postMethod)) {
        var uri=urlCall+'?'+that.updating.getTime();
        that.AJAX.open("POST", uri, true);
        that.AJAX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        that.AJAX.send(passData);
      } else {
        var uri=urlCall+'?'+passData+'&timestamp='+(that.updating.getTime());
        that.AJAX.open("GET", uri, true);
        that.AJAX.send(null);
      }
      return true;
    }
  }
  var urlCall = url;
  this.callback = callbackFunction || function () { };
}
