String.prototype.ucfirst = function(){
     return this.toLowerCase().replace(/\w+/g,function(s){
          return s.charAt(0).toUpperCase() + s.substr(1);
     })
}

String.prototype.ucwords = function(){
     return this.toLowerCase().replace(/\w+/g,function(s){
          var a = s.split(' ');
          for(var i = 0; i < a.length; ++i) {
             s = s.replace(a[i],a[i].ucfirst());
          }
          return s;
     })
}

String.prototype.charpac = function(n){
      var str = '';
      for(var i = 0; i < n; ++i) { str += this; }
      return str;
}

String.prototype.trim = function() {
    str = this != window? this : str;
    return str.replace(/^\s+/, '').replace(/\s+$/, '');
}

var PO = new ParseObj();

function traceAry(obj) {
   /*
    * Like print_p() in php except this ones is on the javascript side.
    * this is mainly used for a debugging function to view your objects.
    * use alert(traceAry(myObject)); to see how it works.
    */
   return PO.traceIt(obj);
}

function ParseObj() {
/*
 * ParseObj.js
 * Created Sept 26, 2006
 * Author: Wes Jones
 * Purpose: take any url or query string and parse it into a hiearchal object return as array of objects
 * PO is already defined in this script so you don't define it. You just use
 * it.
 * Example: gets variables out of a query string
 *   var str = 'test=hello&user[id]=1&user[level]=2';
 *   var obj = PO.parseIt(str);
 *   alert(traceIt(obj)); // traces like print_r in php
 * Example 2: gets variables out of the url
 *   var urlvars = PO.getURL();
 *   alert(traceIt(urlvars));
 * Example 3: use the PO.toString(obj) to convert items to a url encoded string.
 * all objects passed through ajax are encoded this way automatically.
 */
   this.obj = new Object();
   this.unique_keys = new Object(); // for avoiding recursion when toString()
   this.getURL = function () { // get url and parseIt
      var str = document.location+'';
      var spobj = new Object();
      var sp = str.split('?');
      spobj.url = sp[0];
      spobj.query = this.parseIt(sp[1]);
      return spobj;
   }
   this.parseIt = function (vars,chr) {
      // parese query string into variable object and return it
      this.obj = new Object();
      chr = chr ? chr : '&';
      vars = (vars+'').trim();
      if(typeof(vars) != 'string') { vars = vars+''; }
      var v = vars.split(chr);
      for(var i in v) {
         v[i] = v[i].toString().split('=');
         var tmp = v[i][0].toString().split('[');
         if (tmp.length > 1) {
            if (this.obj[tmp[0]] == undefined) {
               this.obj[tmp[0]] = new Object();
            }
            var keys = v[i][0].toString().split('[');
            keys = keys.splice(1,keys.length-1);
            for(var j in keys) {
               keys[j] = keys[j].toString().replace(']','');
            }
            this.obj[tmp[0]] = this.addKV(this.obj[tmp[0]],keys,v[i][1]);
         } else {
            if (v[i][0]) {
               this.obj[v[i][0]] = unescape(v[i][1]);
            }
         }
      }
      return this.obj;
   }
   this.addKV = function (obj,keys,val) {
      // add sub child objects recursivly
      if(keys.length > 1) {
         if(!obj[keys[0]]) {
            obj[keys[0]] = new Object();
         }
         obj[keys[0]] = this.addKV(obj[keys[0]],keys.splice(1,keys.length-1),val);
      } else {
         val = unescape(val);
         if(!isNaN(val)) {
         	val = parseFloat(val);
         	val = isNaN(val) ? 0 : val;
         } else if (val.toLowerCase() == 'true') {
         	val = true;
         } else if (val.toLowerCase() == 'false') {
         	val = false;
         }
         obj[keys[0]] = val;
      }
      return obj;
   }
   this.charPac = function (c,d) {
      // add spacing for legibility
      var str = '';
      for(var i = 0; i < d; ++i) { str += c; }
      return str;
   }
   this.traceIt = function (obj,depth) {
      // recursivly trace the array and ouput in hiearchal string
      var str = '';
      depth = depth ? parseInt(depth) : 0;
      if((typeof(obj)+'').toLowerCase() == 'array') { //.length) {
         for(var i=0; i < obj.length; ++i) {
         	str += this.traceStr(obj,i,depth);
         }
      } else {
         for(var i in obj) {
            str += this.traceStr(obj,i,depth);
         }
      }
      return str;
   }
   this.traceStr = function (obj,i,depth) {
      str = '';
      type = (typeof(obj[i])+'').toLowerCase();
      var unique = true;//!exists(this.unique_keys,i);
      str += this.charPac('---',depth+1)+'['+i+'] '+(type == 'object' && unique  ? '= Object (\n'+this.traceIt(obj[i],depth+2) : ' = '+obj[i]+',')+'\n';
      str += type == 'object' && unique  ? this.charPac('---',depth+1)+'),\n' : '';
      if(type == 'object') { this.unique_keys[i] = 1; }
      return str;
   }
   this.toString = function (obj,name) {
      // make a query string
      // this will remove all functions that are in the object
      // since only simple objects can be passed.
      var str = '';
      for (i in obj) {
         if (typeof(obj[i]) != 'function') {
            if(typeof(obj[i]) == 'object' || typeof(obj[i]) == 'array') {
               if(!name) { // single dimentional
                  str += this.toString(obj[i],i);
               } else { // multi dimentional
	              str += this.toString(obj[i],name+'['+i+']');
               }
            } else if (name) {
               str += name+'['+i+']='+escape(obj[i])+'&';
            } else {
               str += i+'='+escape(obj[i])+'&';
            }
         }
      }
      return str;
   }
}
