//  latest & greatest ajax object by AF
//
//  started with proto example from softwaresecretweapons.com
//  "JavaScript Refactoring for safer, faster, better AJAX.
//   (Copyright 2005, Pavel Simakov)"
//
//  adapted by AF to incorporate the best other stuff I've 
//   found, such as the ajaxrequest object from the-art-of-web.com
//   - converted XMLHTTP object stuff to use try / catch syntax
//   - added Msxml2.XMLHTTP
//   - added POST method
//   - touched up cosmetically to fit my style and make it easier to 
//       read, e.g. changing "internal" to "_" and converting functions 
//       and objects to syntactically sensible names


function ajax() {
	var method;
	var nocache = false;
	var status = null;
	var url = null;
	var params = null;
	var req = null;
	var inProgress = false;
	var isComplete = false;
	var objType;
	var timer;
	var timerStart;
	var msgs;
	
	this.method = "GET";
	this.timer = new Date();
	this.timerStart = this.timer.getTime();
	this.msgs = [];
}

// checks to see if we have too many messages in log
ajax.prototype._CanMsg = function() {
	return this.msgs.length < 100;
}
// adds message to internal log
ajax.prototype._log = function(msg) {
	if (this.onLog && this._CanMsg()) {
		this.onLog(this.timer.getTimestamp() + " " + msg);
		this.msgs.push(msg);
	}
}
// adds message to internal error handler
ajax.prototype._err = function(msg) {
	if (this.onError && this._CanMsg()) {
		this.onError(this.timer.getTimestamp() + " " + msg);
		this.msgs.push(msg);
	}
}

// tells us whether we are busy waiting for the response to another request
ajax.prototype._IsBusy = function() {
	return this.inProgress && !this.isComplete;
}

// internal callback function for the browser; called when state of request object changes
ajax.prototype._RequestComplete = function() {

	var STATE_COMPLETED = 4;
	var STATUS_200 = 200;

	if (!this._IsBusy()) {
		this._err("_RequestComplete: error - no request submitted");
	}

	this._log("_RequestComplete: readyState " + this.req.readyState);

	if (this.req.readyState == STATE_COMPLETED) {
		// AF - add 0 to make sure it's a number 
		//  so we don't get a 'no properties' error
		this.status = this.req.status + 0;
		
		this.inProgress = false;
		this.isComplete = true;

		this._log("_RequestComplete: status " + this.status);

		if (this.status == STATUS_200) {
			this._log("_RequestComplete: calling callback on content with length " + this.req.responseText.length + " chars");
			if (this.onComplete) {
				this.onComplete(this.req.responseText, this.req.responseXML);
			}
			this._log("_RequestComplete: complete");
		} else {
			this._err("_RequestComplete: error - bad status while fetching " + this.url);
		}
		//alert("msgs: " + this.msgs.join("\n"));
		
	} else {
		// we need to review other state codes for XMLRPC provider
	}
}

// call this function to figure out version of this class
ajax.prototype.getVersion = function() {
	return "1.0.1";
}

// call this function to figure out if current browser supports XML HTTP Requests
ajax.prototype.isSupported = function() {
	return window.XMLHttpRequest || (new ActiveXObject("Msxml2.XMLHTTP") != null) || (new ActiveXObject("Microsoft.XMLHTTP") != null);
}

// call this function to find out if more calls are possible and if request has been completely received
ajax.prototype.isBusy = function() {
	return this._IsBusy();
}



//  call this function to submit new request
ajax.prototype.submit = function(_url, _params) {
	if (this._IsBusy()) {
		this._err("submit: error - busy processing another request " + _url);
	}
	this._log("submit: started for " + _url + " (params: " + _params + ")");

	this.url = _url;
	this.params = encodeURI(_params + "");
	this.status = null;
	this.inProgress = true;
	this.isComplete = false;
	
	var _this = this;
	this.objType = '';
	var sendVar = "";  // AF - IE likes "", others like null
	
	if (window.XMLHttpRequest) {
		sendVar = null;
		this.objType = "XMLHttpRequest";
		try {
			this.req = new XMLHttpRequest();
		} catch(e) {
			this.req = false;
		}
	} else if (window.ActiveXObject) {
		this.objType = "Msxml2.XMLHTTP";
		try {
			this.req = new ActiveXObject(this.objType);
		} catch(e) {
			this.objType = "Msxml2.XMLHTTP";
			try {
				this.req = new ActiveXObject(this.objType);
			} catch(e) {
				this.req = false;
			}
		}
	}
	
	if (!this.req) {
		this._err("submit: error - browser does not support XML HTTP Request");
		return false;
	}
	
	this._log("submit: " + this.method + " using " + this.objType);
	this.req.onreadystatechange = function() { _this._RequestComplete(); };
	
	if (this.method == "POST") {
		this.req.open("POST", this.url, true);
		this.req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		this.req.send(this.params);
	} else {
		this.req.open("GET", this.url + "?" + this.params, true);
		if (this.nocache) {
			this.req.setrequestheader("Pragma", "no-cache");
			this.req.setrequestheader("Cache-control", "no-cache");
		}
		this.req.send(sendVar);
	}
	this._log("submit: complete");
}



// call this function to abort current request
ajax.prototype.abort = function() {
	this._log("abort: " + this.url);

	if (!this._IsBusy()) {
		this._err("abort: error - no request submitted");
	}
	this.onComplete = null;
	this.req.abort();
}

// call this function to find out current url
ajax.prototype.getUrl = function() {
	return this.url + "?" + this.params;
}

// call this function to find out HTTP status code after response completes
ajax.prototype.getStatus = function() {
	return this.status;
}

// please can override this; function is called when fatal error occurs
ajax.prototype.onError = function(msg) {
	
}

// user can override this; function is called when log message is created
ajax.prototype.onLog = function(msg) {

}

// user can override this; function is called when response is received without errors
ajax.prototype.onComplete = function(responseText, responseXML) {
	return false;
}
