/*
		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 (hook) {
		try {
			if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
					test(this)) {
				var j = eval('(' + this + ')');
				if (typeof hook === 'function') {
					function walk(v) {
						if (v && typeof v === 'object') {
							for (var i in v) {
								if (v.hasOwnProperty(i)) {
									v[i] = walk(v[i]);
								}
							}
						}
						return hook(v);
					}
					return walk(j);
				}
				return j;
			}
		} catch (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 + '"';
	}
});