/**
 * Request - wrapper for XML HTPP Requests
 * @class
 */
var Request = ( function ( ) {
	var create = ( function ( ) {
		if ( window.XMLHttpRequest ) {
			return function ( ) {
				try {
					return new XMLHttpRequest();
				} catch ( e ) {
					throw "Unable to create request";
				}
			}
		} else if ( window.ActiveXObject ) {
			return function ( ) {
				try {
					return new ActiveXObject("Msxml2.XMLHTTP");
				} catch ( e ) {
					try {
						return new ActiveXObject("Microsoft.XMLHTTP");
					} catch ( e ) {
						throw "Unable to create request";
					}
				}
			}
		} else {
			return function ( ) {
				throw "Unable to create request";
			}
		}
	} )();
	var init = function ( method, location, headers ) {
		var connection = create();
		connection.open ( method, location );
		if ( headers && Object.prototype.toString.call(headers) == "[object Object]" )
			for ( var header in headers )
				connection.setRequestHeader ( header, headers[header] );
		return connection;
	}
	var parseHeaders = function ( connection ) {
		var headers = connection.getAllResponseHeaders().split("\n");
		var rsp = {};
		for ( var i = 0, header; header = headers[i]; i ++ ) {
			header = header.split ( /: / );
			rsp[header.shift()] = header.join(": ");
		}
		return rsp;
	}
	var fire = function ( request, connection, data, callback ) {
		var finish = function ( response, success ) {
			var headers = parseHeaders ( connection );
			if ( typeof callback == "function" )
				callback ( response, success, headers );
			if ( success && ( typeof request.onSuccess == "function" ) )
				request.onSuccess ( response, headers );
			if ( !success && ( typeof request.onError == "function" ) )
				request.onError ( response.status, response.message, headers );
			if ( typeof request.onComplete == "function" )
				request.onComplete ( response, success, headers );
		}
		connection.onreadystatechange = function ( ) {
			if ( typeof request.onChange == "function" ) request.onChange ( connection.readyState, connection );
			if ( connection.readyState == 4 ) {
				if ( connection.status == 200 ) {
					finish ( connection.responseXML && connection.responseXML.documentElement ? connection.responseXML : connection.responseText, true );
				} else {
					finish ( { status : connection.status, message : connection.statusText }, false );
				}
			}
		}
		connection.send ( data );
	}
	var $class = function ( location ) {
		var headers = {};
		location = location || document.location.pathname;
		return {
			setHeader : function ( key, value, replace ) {
				if ( !headers[key] || !!replace )
					headers[key] = value;
			},
			removeHeader : function ( key ) {
				delete headers[key];
			},
			clearHeaders : function ( ) {
				headers = {};
			},
			send : function ( data, callback ) {
				var data = $class.encode ( data );
				var dataLocation = data ? location + ( location.indexOf('?') == -1 ? "?" : "&" ) + data : location;
				dataLocation = dataLocation.replace ( /\?&/, '?' );
				fire ( this, init ( "GET", dataLocation, headers ), null, callback );
			},
			post : function ( data, callback ) {
				fire ( this, init ( "POST", location, headers ), $class.encode ( data ), callback );
			}
		}
	}
	$class.encode = function ( data ) {
		if ( (""+data) === data )
			return (""+data);
		if ( Object.prototype.toString.call ( data ) != "[object Object]" )
			return "";
		var d = [];
		for ( var key in data ) {
			d.push ( encodeURI ( key ) + "=" + encodeURI ( data[key] ) );
		}
		return d.join("&");
	}
	return $class;
} )();
