JSON = new function(){

	/* Section: Methods - Public */
	
	/*
	Method: decode
		decodes a valid JSON encoded string.
	
	Arguments:
		[String / Function] - Optional JSON string to decode or a filter function if method is a String prototype.
		[Function] - Optional filter function if first argument is a JSON string and this method is not a String prototype.
	
	Returns:
		Object - Generic JavaScript variable or undefined
	
	Example [Basic]:
		>var	arr = JSON.decode('[1,2,3]');
		>alert(arr);	// 1,2,3
		>
		>arr = JSON.decode('[1,2,3]', function(key, value){return key * value});
		>alert(arr);	// 0,2,6
	Note:
		Internet Explorer 5 and other old browsers should use a different regular expression to check if a JSON string is valid or not.
		This old browsers dedicated RegExp is not safe as native version is but it required for compatibility.
	*/
	this.decode = function(){
		var	filter, result, self, tmp;
		if(checkConstructor("toString")) {
			switch(arguments.length) {
				case	2:
					self = arguments[0];
					filter = arguments[1];
					break;
				case	1:
					if(objConstructor[typeof arguments[0]](arguments[0]) === Function) {
						self = this;
						filter = arguments[0];
					}
					else
						self = arguments[0];
					break;
				default:
					self = this;
					break;
			};
			if(checkJSON.test(self)){
				try{
					result = safeEval("(".concat(self, ")"));
					if(filter && result !== null && (tmp = objConstructor[typeof result](result)) && (tmp === Array || tmp === Object)){
						for(self in result)
							result[self] = skipObject(self, result) ? filter(self, result[self]) : result[self];
					}
				}
				catch(z){}
			}
		};
		return result;
	};
	
	/*
	Method: encode
		encode a generic JavaScript variable into a valid JSON string.
	
	Arguments:
		[Object] - Optional generic JavaScript variable to encode if method is not an Object prototype.
	
	Returns:
		String - Valid JSON string or undefined
	
	Example [Basic]:
		>var	s = JSON.encode([1,2,3]);
		>alert(s);	// [1,2,3]
	*/
	this.encode = function() {
		var	self = arguments.length ? arguments[0] : this,
			result, tmp;
		if(self === null)
			result = "null";
		else if(self !== undefined && (tmp = objConstructor[typeof self](self))) {
			switch(tmp) {
				case	Array:
					result = [];
					for(var	i = 0, j = 0, k = self.length; j < k; j++) {
						if(self[j] !== undefined && (tmp = JSON.encode(self[j])))
							result[i++] = tmp;
					};
					result = "[".concat(result.join(","), "]");
					break;
				case	Boolean:
					result = String(self);
					break;
				case	Date:
					result = '"'.concat(self.getFullYear(), '-', numToString(self.getMonth() + 1), '-', numToString(self.getDate()), 'T', numToString(self.getHours()), ':', numToString(self.getMinutes()), ':', numToString(self.getSeconds()), '"');
					break;
				case	Function:
					break;
				case	Number:
					result = isFinite(self) ? String(self) : "null";
					break;
				case	String:
					result = '"'.concat(self.replace(checkString1, escapeString1).replace(checkString2, escapeString2), '"');
					break;
				default:
					var	i = 0, key;
					result = [];
					for(key in self) {
						if(self[key] !== undefined && (tmp = JSON.encode(self[key])))
							result[i++] = '"'.concat(key.replace(checkString1, escapeString1).replace(checkString2, escapeString2), '":', tmp);
					};
					result = "{".concat(result.join(","), "}");
					break;
			}
		};
		return result;
	};
		
	/* Section: Properties - Private */
	
	/*
	Property: Private
	
	List:
		Object - 'dictionary' - a dictionary with useful keys / values for fast encode convertion
		Function - 'numToString' - returns decimal string representation of a number ("14", "03", etc)
		Function - 'safeEval' - safe and native code evaluation
		Array - 'zero' - a list with different "0" strings for fast special chars escape convertion
		RegExp - 'checkJSON' - regular expression to check JSON strings (different for IE5 or old browsers and new one)
		RegExp - 'checkString1' - regular expression to check string chars to modify using c (char) values
		RegExp - 'checkString2' - regular expression to check string chars to escape using "\u" prefix
		Function - 'escapeString1' - returns escaped string adding "\\" char as prefix ("\\" => "\\\\", etc.)
		Function - 'escapeString2' - returns escaped string, modifyng special chars using "\uNNNN" notation
		Function - 'skipObject' - returns boolean value to skip object methods or prototyped parameters (length, others), used for optional decode filter function
		Function - 'objConstructor' - returns object constructor if it was not cracked (someVar = {}; someVar.constructor = String <= ignore them)
		Function - 'checkConstructor' - returns boolean value to check native Array and Object constructors before convertion
	*/
	var	dictionary = {"\b":"b","\t":"t","\n":"n","\f":"f","\r":"r",'"':'"',"\\":"\\","/":"/"},
		numToString = function(n){
				return n<10 ? "0".concat(n) : n;
			},
		safeEval = function(c,f,e){
				e = eval;
				delete eval;
				if (typeof eval==="undefined") {
					eval = e;
				}
				f = eval("" + c);
				eval = e;
				return f;
			},
		zero = ["", "000", "00", "0", ""],
		checkJSON = null,
		checkString1 = /(\x5c|\x2F|\x22|[\x0c-\x0d]|[\x08-\x0a])/g,
		checkString2 = /([\x00-\x07]|\x0b|[\x0e-\x1f])/g,
		escapeString1 = function(i,d) {
				return "\\".concat(dictionary[d]);
		},
		escapeString2 = function(i,d) {
			var	n = d.charCodeAt(0).toString(16);
			return "\\u".concat(zero[n.length],n);
		},
		skipObject = function(k,v){
			return objConstructor[typeof result] (result)!==Function && (v.hasOwnProperty ? v.hasOwnProperty(k) : v.constructor.prototype[k]!==v[k]);
		},
		objConstructor = {
			"boolean":function() { return Boolean },
			"function":function() { return Function },
			"number":function() { return Number },
			"object":function(o) { return o instanceof o.constructor?o.constructor:null },
			"string":function() { return String },
			"undefined":function() { return null }
		},
		checkConstructor = function(m) {
			function objConstructor(c,t) {
				t = dictionary[m];
				delete dictionary[m];
				try {
					safeEval(c);
				} catch(z) {
					dictionary[m] = t;
					return 1;
				}
			};
			return objConstructor(Array)&&objConstructor(Object);
		};
	try {
		checkJSON = new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$');
	} catch(z) {
		checkJSON = /^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/;
	}
};
