/*
		json.js
		2006-12-06

		Tweaked by Kramer & Grady 070104
			Used Object.extend()
			Converted Object.prototype changes to a global function toJSONString()

		This file adds these methods to JavaScript:

				array.toJSONString()
				boolean.toJSONString()
				date.toJSONString()
				number.toJSONString()
				string.toJSONString()
				toJSONString() (for objects)
						These methods produce a JSON text from a JavaScript value.
						It must not contain any cyclical references. Illegal values
						will be excluded.

						The default conversion for dates is to an ISO string. You can
						add a toJSONString method to any date object to get a different
						representation.

				string.parseJSON(hook)
						This method parses a JSON text to produce an object or
						array. It can throw a SyntaxError exception.

						The optional hook parameter is a function which can filter and
						transform the results. It receives each of the values, and its
						return value is used instead. If it returns what it received, then
						structure is not modified.

						Example:

						// Parse the text. If it contains any "NaN" strings, replace them
						// with the NaN value. All other values are left alone.

						myData = text.parseJSON(function (value) {
								if (value === 'NaN') {
										return NaN;
								}
								return value;
						});

		It is expected that these methods will formally become part of the
		JavaScript Programming Language in the Fourth Edition of the
		ECMAScript standard in 2007.
*/
Object.extend(Array.prototype, {
	toJSONString: function () {
			var a = ['['], b, i, l = this.length, v;

			function p(s) {
					if (b) {
							a.push(',');
					}
					a.push(s);
					b = true;
			}

			for (i = 0; i < l; i += 1) {
					v = this[i];
					switch (typeof v) {
					case 'undefined':
					case 'function':
					case 'unknown':
							break;
					case 'object':
							if (v) {
									if (typeof toJSONString === 'function') {
											p(toJSONString(v));
									}
							} else {
									p("null");
							}
							break;
					default:
							p(toJSONString(v));
					}
			}
			a.push(']');
			return a.join('');
	}
});

Object.extend(Boolean.prototype, {
	toJSONString: function () {
			return String(this);
	}
});

Object.extend(Date.prototype, {
	toJSONString: function () {

			function f(n) {
					return n < 10 ? '0' + n : n;
			}

			return '"' + this.getFullYear() + '-' +
							f(this.getMonth() + 1) + '-' +
							f(this.getDate()) + 'T' +
							f(this.getHours()) + ':' +
							f(this.getMinutes()) + ':' +
							f(this.getSeconds()) + '"';
	}
});

Object.extend(Number.prototype, {
	toJSONString: function () {
			return isFinite(this) ? String(this) : "null";
	}
});

function toJSONString(subject) {
	if (subject instanceof Object) {
		var a = ['{'], b, i, v;

		function p(s) {
				if (b) {
						a.push(',');
				}
				a.push(toJSONString(i), ':', s);
				b = true;
		}

		for (i in subject) {
				if (subject.hasOwnProperty(i)) {
						v = subject[i];
						switch (typeof v) {
						case 'undefined':
						case 'function':
						case 'unknown':
								break;
						case 'object':
								if (v) {
										if (typeof toJSONString === 'function') {
												p(toJSONString(v));
										}
								} else {
										p("null");
								}
								break;
						default:
								p(toJSONString(v));
						}
				}
		}
		a.push('}');
		return a.join('');
	} else {
		return subject.toJSONString();
	}
};


Object.extend(String.prototype, {
	parseJSON: function (filter) {
		try {
                var j;
                function walk(k, v) {
                    var i, n;
                    if (v && typeof v === 'object') {
                        for (i in v) {
                            if (Object.prototype.hasOwnProperty.apply(v, [i])) {
                                n = walk(i, v[i]);
                                if (n !== undefined) {
                                    v[i] = n;
                                }
                            }
                        }
                    }
                    return filter(k, v);
                }

// Parsing happens in three stages. In the first stage, we run the text against
// regular expressions that look for non-JSON patterns. We are especially
// concerned with '()' and 'new' because they can cause invocation, and '='
// because it can cause mutation. But just to be safe, we want to reject all
// unexpected forms.

// We split the first stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace all backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

                if (/^[\],:{}\s]*$/.test(this.replace(/\\./g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(:?[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the second stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                    j = eval('(' + this + ')');

                    return typeof filter === 'function' ? walk('', j) : j;
                }

                return j;
            
  			} catch (e) { //alert('rutro: '+e);
		}
		throw new SyntaxError("parseJSON");
	},

	toJSONString: function () {
		var m = {
			'\b': '\\b',
			'\t': '\\t',
			'\n': '\\n',
			'\f': '\\f',
			'\r': '\\r',
			'"' : '\\"',
			'\\': '\\\\'
		};
		if (/["\\\x00-\x1f]/.test(this)) {
			return '"' + this.replace(/([\x00-\x1f\\"])/g, function(a, b) {
				var c = m[b];
				if (c) {
					return c;
				}
				c = b.charCodeAt();
				return '\\u00' +
					Math.floor(c / 16).toString(16) +
					(c % 16).toString(16);
			}) + '"';
		}
		return '"' + this + '"';
	}
});