/**
 * provides httpRequest object
 * details about request obtained from assigned object callingObject
 * {string} obj.requestCommand :	command string for serverside framework
 * {object} obj.requestParameters:	optional parameters
 * 
 * delivered response triggers callingObject.handleXhrResponse()
 * timeout triggers callingObject.handleXhrTimeout()
 * 
 * @version 2.0.5 2008-09-09
 * 
 * return {
 *  abort()
 * 	setEcho(bool echo)
 * 	setTimeout(int timeout, function callback)
 * 	setAnimation(obj anim)
 * 	handleRequest(string command)
 * }
 */
 
if(!vxJS) { throw new Error("XHR: vxJS core missing."); }

vxJS.xhr = function(reqObj) {
	var	uri = encodeURI(window.location.href),
		timeout = 30000, timeoutCallback,
		animation = {},
		echo, http, timer;

	var init = function() {
		var ms = ["Msxml2.XMLHTTP", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP.4.0", "Msxml2.XMLHTTP.5.0", "Microsoft.XMLHTTP"], i;

		try { http = new XMLHttpRequest(); } catch (e) { }

		if(!http) {
			for (i = ms.length; i--;) {
				try { http = new ActiveXObject(ms[i]); } catch (e) { }
			}
	 	}
		if (!http) { throw new Error ("vxJS.xhr: Can't instantiate XMLHttpRequest!"); }
	};

	var stopTimer = function() {
		if(timer) {
			window.clearTimeout(timer);
		}
		if(animation.node) {
			document.body.removeChild(animation.node);
			delete animation.node;
			animation.running = false;
		}
	};

	var abort = function() {
		stopTimer();
		if(http) { 
			http.onreadystatechange = function() {};
			if(http.readyState !== 0 && http.readyState != 4) {
				http.abort();
			}
		}
	};


	var timeoutHandler = function() {
		abort();

		if(timeoutCallback) {
			timeoutCallback();
		}
		else {
			alert("XHR was not successful!\nTimeout of "+timeout+"ms exceeded!");
		}
	};
	
	var startTimer = function() {
		var n;

		if(timeout > 0) {
			timer = window.setTimeout( function(){ timeoutHandler(); }, timeout);
		}

		if(!animation.img) { return; }
		if(!animation.node) {
			n = "img".__setProp("class", "xhrAnim").__create();
			n.style.position = "absolute";
			n.style.zIndex = 50000;
			animation.node = n;
		}
		else {
			n = animation.node; 
		}

		n.src = animation.img;
		n.style.left = animation.position.x+"px";
		n.style.top = animation.position.y+"px";

		document.body.appendChild(n);
	}

	return {
		setEcho: function(e) { echo = !!e; },

		setUri: function(u) { uri = encodeURI(u); },

		setTimeout: function(t, cb) {
			timeout = parseInt(t, 10) || 5000;
			if(cb) { timeoutCallback = cb; }
		},
	
		setAnimation: function(a) {
			if(a.img) {
				animation.img = a.img;
			}
			if(a.position) {
				animation.position = a.position;
			}
		},
		
		abort: abort,
	
		handleRequest: function(parm) {
			var that = this, pO = reqObj.requestParameters || {};
	
			pO.httpRequest = reqObj.requestCommand;
			pO.echo = echo ? 1 : 0;
	
			if(typeof parm != "undefined") { pO.text = ""+parm; }
	
			abort();
			init();
			
			http.open("post", uri, true);
			http.setRequestHeader("X-Requested-With", "XMLHttpRequest");
			http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	
			http.onreadystatechange = function () {
				if (http.readyState == 4 && /^(0|2\d\d)$/.test(http.status)) {
					stopTimer();
					if(typeof reqObj.handleXhrResponse == "function" && http.responseText) {
						
						try { reqObj.handleXhrResponse(JSON.parse(http.responseText)); } catch (e) {
							
							reqObj.handleXhrResponse("Kemma da her?");
							
						}
							
					}
				}
			};
	
			startTimer();
			http.send("xmlHttpRequest="+encodeURIComponent(JSON.stringify(pO)));
		}
	};
}

/**
 * A simple object to wrap request and response handling 
 */
vxJS.simpleRequester = function(req, callback) {
	var	that = {
			requestCommand: req,
			requestParameters: {},
			triggerRequest: function(parm) {
				switch (typeof parm) {
					case "object":
						this.requestParameters = parm;
					case "undefined":
						xhr.handleRequest();
						break;
					default:
						xhr.handleRequest(parm);
				}
			},
			setXhrUri: function(uri) { xhr.setUri(uri); },
			handleXhrResponse: callback || function() { }
		},
			
		xhr = vxJS.xhr(that);

	return that;
};

/**
 * JSON encoding/decoding by Douglas Crockford http://www.json.org/js.html
 */

if (!this.JSON) {
	JSON = function () {
		function f(n) { return n < 10 ? '0' + n : n; }

		Date.prototype.toJSON = function () {
			return this.getUTCFullYear()	+ '-' +
				f(this.getUTCMonth() + 1)	+ '-' +
				f(this.getUTCDate())		+ 'T' +
				f(this.getUTCHours())		+ ':' +
				f(this.getUTCMinutes())		+ ':' +
				f(this.getUTCSeconds())		+ 'Z';
		};

		var	cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
			escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
			gap, indent, rep, meta = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\' };

		function quote(string) {
			escapeable.lastIndex = 0;
			return escapeable.test(string) ?
				'"' + string.replace(escapeable, function (a) {
					var c = meta[a];
					if (typeof c === 'string') { return c; }
					return '\\u00' + ('0000' + (+(a.charCodeAt(0))).toString(16)).slice(-4);
				}) + '"' :
				'"' + string + '"';
        }

        function str(key, holder) {
			var i, k, v, length, mind = gap, partial, value = holder[key];
			if (value && typeof value === 'object' && typeof value.toJSON === 'function') {
				value = value.toJSON(key);
			}
			if (typeof rep === 'function') {
				value = rep.call(holder, key, value);
			}
			switch (typeof value) {
				case 'string':
					return quote(value);
				case 'number':
					return isFinite(value) ? String(value) : 'null';
				case 'boolean':
				case 'null':
					return String(value);
				case 'object':
					if (!value) { return 'null'; }
					gap += indent;
					partial = [];
				if (typeof value.length === 'number' && !(value.propertyIsEnumerable('length'))) {
					length = value.length;
					for (i = 0; i < length; i += 1) {
						partial[i] = str(i, value) || 'null';
					}
					v = partial.length === 0 ? '[]' :
						gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
					gap = mind;
					return v;
				}

				if (rep && typeof rep === 'object') {
					length = rep.length;
					for (i = 0; i < length; i += 1) {
    					k = rep[i];
    					if (typeof k === 'string') {
							v = str(k, value, rep);
							if (v) {
								partial.push(quote(k) + (gap ? ': ' : ':') + v);
							}
						}
    				}
				}
				else {
					for (k in value) {
						if (Object.hasOwnProperty.call(value, k)) {
							v = str(k, value, rep);
							if (v) {
								partial.push(quote(k) + (gap ? ': ' : ':') + v);
							}
						}
					}
				}

				v = partial.length === 0 ? '{}' :
					gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}';
				gap = mind;
				return v;
			}
		}
		return {
			stringify: function (value, replacer, space) {
				var i;
				gap = '';
				indent = '';
				if(space) {
					if (typeof space === 'number') {
						for (i = 0; i < space; i++) { indent += ' '; }
                    }
					else if (typeof space === 'string') { indent = space; }
                }
                
				rep = replacer;
				if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
					throw new Error('JSON.stringify');
				}
				return str('', {'': value});
			},

			parse: function (text, reviver) {
				var j;

				function walk(holder, key) {
					var k, v, value = holder[key];
					if (value && typeof value === 'object') {
						for (k in value) {
							if (Object.hasOwnProperty.call(value, k)) {
								v = walk(value, k);
								if (v !== undefined) {
									value[k] = v;
								}
								else {
									delete value[k];
								}
							}
						}
					}
					return reviver.call(holder, key, value);
				}

				cx.lastIndex = 0;
				if (cx.test(text)) {
					text = text.replace(cx, function (a) { return '\\u' + ('0000' + (+(a.charCodeAt(0))).toString(16)).slice(-4); });
				}
				if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
					j = eval('(' + text + ')');
					return typeof reviver === 'function' ?
					walk({'': j}, '') : j;
				}
				throw new SyntaxError('JSON.parse');
			}
		};
	}();
}
