/**
 *
 * Produces a string in which '<', '>', and '&' are replaced with their HTML entity equivalents. <br>
 * This is essential for placing arbitrary strings into HTML texts. So,<br>
 *<br>
 *   "if (a < b && b > c) {".entityify()<br>
 *<br>
 *  produces<br>
 *<br>
 *   "if (a &lt; b &amp;&amp; b &gt; c) {"<br>
 *
 */
String.prototype.entityify =  function () {
   return this.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}

/**
 *
 * Produces a quoted string.
 * @return a string which is like the original string except that it is wrapped in quotes
 * and all quote and backslash characters are preceded with backslash.
 *
 */
String.prototype.quote = function () {
   return '"' + this.replace(/(["\\])/g, '\\$1') + '"';
}

/**
 *
 * Note: Open and close tags should be 1 char long.
 *
 * Does variable substitution on the string. It scans through the string looking for expressions enclosed in { } braces. <br>
 * If an expression is found, use it as a key on the object, and if the key has a string value or number value, it is substituted <br>
 * for the bracket expression and it repeats. This is useful for automatically fixing URLs. So<br>
 *       param = {domain: 'valvion.com', media: 'http://media.{domain}/'};<br>
 *       url = "{media}logo.gif".supplant(param);<br>
 *<br>
 *  produces a url containing "http://media.valvion.com/logo.gif".
 *  @param oProps Object with prperty names which are the variables in the string that will be replaced
 *  There are 2 special properties '__open_tag' and '__close_tag' which define the tags in which the variables
 *  in the passed string are enclosed
 *  @param bReplaceWithBlank -- will replace with blank any propertyin the template which is not found int the Props object
 *  @param oCallBack - function to use when replacing the variables. Callback function receives the variable name and the oProps object as params
 *
 */
String.prototype.supplant = function (oProps, bReplaceWithBlank, oCallBack) {
   var i, j, vValue;
   var sString = this;
   var q = 0;
   var sOpenTag  = (isUndefined(oProps.__open_tag))  ? '{' : oProps.__open_tag ;
   var sCloseTag = (isUndefined(oProps.__close_tag)) ? '}' : oProps.__close_tag ;

   for (;;) {
      i = q + sString.substring(q, sString.length).indexOf(sOpenTag);

      if (i < 0) {
         break;
      }
      if (i + 1 <= q) {
         break;
      }

      j = sString.indexOf(sCloseTag, i + 1);
      if (j == -1) {
         break;
      }

      if (isDefined(oCallBack)) {
         vValue = oCallBack(sString.substring(i + 1, j), oProps);
      } else {
         vValue = oProps[sString.substring(i + 1, j)];
      }

      if (isUndefined(vValue)) {
         if (bReplaceWithBlank) {
            vValue = '';
         } else {
            q = i + 1;
            continue;
         }

      }
      sString = sString.substring(0, i) + vValue + sString.substring(j + 1);
   }
   return sString;
}

/**
 *
 * Removes whitespace characters from the beginning and end of the string
 *
 */
String.prototype.trim = function () {
   return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
}

if (!isFunction(Function.apply)) {
   Function.prototype.apply = function (o, a) {
      var r, x = '____apply';
      if (!isObject(o)) {
         o = {};
      }
      o[x] = this;
      switch ((a && a.length) || 0) {
         case 0:
            r = o[x]();
            break;
         case 1:
            r = o[x](a[0]);
            break;
         case 2:
            r = o[x](a[0], a[1]);
            break;
         case 3:
            r = o[x](a[0], a[1], a[2]);
            break;
         case 4:
            r = o[x](a[0], a[1], a[2], a[3]);
            break;
         case 5:
            r = o[x](a[0], a[1], a[2], a[3], a[4]);
            break;
         case 6:
            r = o[x](a[0], a[1], a[2], a[3], a[4], a[5]);
            break;
         default:
            //alert('Too many arguments to apply.');
      }
      delete o[x];
      return r;
   }
}

/*
   Sugar methods

*/

/**
 * Sugar method <br><a href = "http://en.wikipedia.org/wiki/Syntactic_sugar">Sugar</a>}
 * Indicates that one class inherits from another.
 * Make an instance of the parent class and use it as the new prototype.
 * Also correct the constructor field, and add the uber method to the prototype as well.
 *
 */
Function.prototype.inherits = function (parent) {
   var d = 0, p = (this.prototype = new parent());
   this.prototype.uber = function uber(name) {
      var f, r, t = d, v = parent.prototype;
      if (t) {
         while (t) {
            v = v.constructor.prototype;
            t -= 1;
         }
         f = v[name];
      } else {
         f = p[name];
         if (f == this[name]) {
            f = v[name];
         }
      }
      d += 1;
      r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
      d -= 1;
      return r;
   }
   return this;
}

/**
 *
 * Loops through the arguments. For each name, it copies a member from the parent's
 * prototype to the new class's prototype.
 *
 */
Function.prototype.swiss = function (parent) {
   for (var i = 1; i < arguments.length; i += 1) {
      var name = arguments[i];
      this.prototype[name] = parent.prototype[name];
   }
   return this;
}

/**
 *
 * Internet Explorer holds references to objects which are not JavaScript objects, <br>
 * and which produce errors if they are treated as JavaScript objects. This is a problem <br>
 * because typeof identifies them as JavaScript objects. The isAlien() function will <br>
 * return true if a is one of those alien objects.<br>
 *
 */
function isAlien(a) {
   return isObject(a) && typeof a.constructor != 'function';
}

function isArray(a) {
   return isObject(a) && a.constructor == Array;
}

function isBoolean(a) {
   return typeof a == 'boolean';
}

/**
 * @return true if 'a' is an object or array or function containing no enumerable members.
 *
 */
function isEmpty(o) {
   var i, v;
   if (isObject(o)) {
      for (i in o) {
         v = o[i];
         if (isUndefined(v) && isFunction(v)) {
            return false;
         }
      }
   }
   return true;
}

/**
 *
 * @return returns true if a is a function.
 * Beware that some native functions in IE were made to look like objects instead <br>
 * of functions. This function does not detect that.
 *
 */
function isFunction(a) {
   return typeof a == 'function';
}

function isNull(a) {
   return typeof a == 'object' && !a;
}

/**
 * @return true if a is a finite number. It returns false if a is <br>
 * NaN or Infinite. It also returns false if a is a string that <br>
 * could be converted to a number
 *
 */
function isNumber(a) {
   return typeof a == 'number' && isFinite(a);
}

/**
 *
 * @return true if a is an object, and array, or a function.
 * It returns false if a is a string, a number, a boolean, or null, or undefined
 *
 */
function isObject(a) {
   return (a && typeof a == 'object') || isFunction(a);
}

/**
 * @return true if 'a' is a string.
 *
 */
function isString(a) {
   return typeof a == 'string';
}

/**
 *
 * @return  true if a is undefined value. You can get the undefined
 * value from an uninitialized variable or from a missing member of an object.
 *
 */
function isUndefined(a) {
   return typeof a == 'undefined';
}

/**
 *
 * see isUndefined
 *
 */
function isDefined(a) {
   return typeof a != 'undefined';
}

/**
 *
 * Take an object and produce a JSON string from it.
 * @return JSON string
 * @type String
 *
 */
function stringify(arg) {
   var i, o, v;

   switch (typeof arg) {
      case 'object':
         if (arg) {
            if (arg.constructor == Array) {

               o = '[';
               for (i = 0; i < arg.length; ++i) {
                  v = stringify(arg[i]);
                  if (v != 'function' && !isUndefined(v)) {
                     o += (o != '[' ? ',' : '') + v;
                  } else {
                     o += ',';
                  }
               }
               return o + ']';
            } else if (typeof arg.toString != 'undefined') {
               o = '{';
               for (i in arg) {
                  v = stringify(arg[i]);
                  if (v != 'function' && !isUndefined(v)) {
                     o += (o != '{' ? ',' : '') +
                        i.quote() + ':' + v;
                  }
               }
               return o + '}';
            } else {
               return;
            }
         }
         return 'null';
      case 'unknown':
      case 'undefined':
         return;
      case 'string':
         return arg.quote();
      case 'function':
         return 'function';
      default:
         return String(arg);
   }
}


