/*
 * Global Ajax event handlers.  Use these methods to handle showing 
 * progress and error feedback to the user.
 * 
 * Currently, we use a Singleton to handle showing the global progress bar
 * and we might be able to improve on this by actually having the singleton 
 * class listen to the ajax calls as opposed to being called by the global
 * ajax callback functions
 */

function callInProgress(xmlhttp) {
	switch (xmlhttp.readyState){
		case 1: case 2: case 3:
			return true;
			break;
		// case 4 and 0
		default:
			return false;
			break;
	}
}

function showFailureMessage(){
	alert("oh pooh, the Ajax call timed out");
}

Ajax.onCreate = function(request){
	// add this request to the progress bar singleton
	ProgressBar.getInstance().addEvent(request);
	// create a timer and store the ID in the request oject so that we can later remove the timer
	request["timeoutId"] = window.setTimeout( 
		function(){
			if (callInProgress(request.transport)) {
				request.transport.abort();
				//showFailureMessage();
				// Run th eonFailure method if we set one up when creating the Ajax object
				if (request.options["onFailure"]){
					request.options["onFailure"](request.transport, request.json);
				}
			}
		}, 5000);
}
Ajax.onException = function(request, jsonData){
	// remove this event from the progress bar singleton
	ProgressBar.getInstance().removeEvent(request);
	alert("global onException handler, request = " + request);
}

Ajax.onFailure = function(request, jsonData){
	// remove this event from the progress bar singleton
	ProgressBar.getInstance().removeEvent(request);
	alert("global onFailure handler, request = " + request);
}

Ajax.onComplete = function(request, jsonData){
	//alert("global onComplete handler, jsonData = " + jsonData);
	// remove this event from the progress bar singleton
	ProgressBar.getInstance().removeEvent(request);
	// clear out the timer that we set in the onCreate callback
	window.cleartimeout(request["timeoutId"]);
}

/*
 * Attach these methods to the Ajax Responders list
 */
Ajax.Responders.register({
	onCreate: Ajax.onCreate,
	onException: Ajax.onException,
	onFailure: Ajax.onFailure,
	//onSuccess: Ajax.onSuccess, -- don't bother with onSuccess, it is only received by the calling function
	onComplete: Ajax.onComplete
});


/*
 * This class handles displaying a progress bar for any number of ajax events
 * that are taking place.  It is written as a singleton so that all you need to
 * do is call ProgressBar.getInstance().addEvent(XXX) or ...removeEvent(XXX).
 * Because javascript does not have static properties, we use a workaround by 
 * creating this class as an anonymous function.
 */
var ProgressBar = new function(){
	this._instance = null;
	this.events = new Array();
	this.progressBarDisplay = null;
	
	this.getInstance = function(){
		// check if there is an instance created already, if not, create it and call
		// createChildren()
		if (this._instance == null){
			this.createChildren();
			this._instance = this;
		}
		return this._instance;
	};
	
	this.addEvent = function(request){
		// check to make sure we're not adding the same event again
		for (var i=0; i<this.events.length; i++){
			if (request == this.events[i]){
				return;
			}
		}
		this.events.push(request);
		Element.show(this.progressBarDisplay);
	};
	
	this.removeEvent = function(request){
		for (var i=0; i<this.events.length; i++){
			if (request == this.events[i]){
				this.events.splice(i,1);
				// check to see if this was the last event we were watching, if so, hide the progress bar
				if (this.events.length == 0){
					Element.hide(this.progressBarDisplay);
				}
				return;
			}
			alert("unable to remove event, event not found");
		}
	};
	
	/*
	 * This method may be replaced if we decide to put the div right in the HTML, which would
	 * solve the issue of hard-coding text ("IN PROGRESS") in the javascript
	 */
	this.createChildren = function(){
		var pageBody = document.getElementsByTagName("body")[0];
		var progressBarDiv = document.createElement("div");
		progressBarDiv.setAttribute("id", "progressBarDisplay");
		progressBarDiv.className = "progressBar";
		progressBarDiv.appendChild(document.createTextNode("IN PROGRESS"));
		pageBody.appendChild(progressBarDiv);
		// save a reference to this div
		this.progressBarDisplay = $("progressBarDisplay");
		
		// hide the div, watch for window resizes, and set the initial position
		Element.hide(this.progressBarDisplay);
		Event.observe(window, "resize", this.setPosition, false);
		Event.observe(window, "scroll", this.setPosition, false);
		this.setPosition();
	};
	
	this.setPosition = function(){
		/*
		var progressBarSize = Element.getDimensions("progressBarDisplay");
		var windowWidth = window.innerWidth || document.body.offsetWidth;
		var windowHeight = window.innerHeight || document.body.offsetHeight;
		var scrollXDelta = self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
		var scrollYDelta = self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
		var padding = 10;
		this.progressBarDisplay.style.left = windowWidth - progressBarSize.width - padding + scrollXDelta + "px";
		this.progressBarDisplay.style.top = scrollYDelta + padding + "px";
		*/
		var progressBarSize = Element.getDimensions("progressBarDisplay");
		var padding = 10;
		var posY = 0;
		if (window.innerHeight){
			posY = window.pageYOffset;
		} else if (document.documentElement && document.documentElement.scrollTop){
			posY = document.documentElement.scrollTop;
		} else if (document.body){
			posY = document.body.scrollTop;
		}
		posY = (posY < padding) ? padding : posY;
		this.progressBarDisplay.style.top = posY + "px";
	}.bind(this);
};


/*
 * This class handles displaying a feedback message for any number of ajax events.
 */
var FeedbackWindow = new function(){
	this._instance = null;
	this.events = new Array();
	this.progressBarDisplay = null;
	
	this.getInstance = function(){
		// check if there is an instance created already, if not, create it and call
		// createChildren()
		if (this._instance == null){
			this.createChildren();
			this._instance = this;
		}
		return this._instance;
	};
	
	this.showMessage = function(request){
		// check to make sure we're not adding the same event again
		for (var i=0; i<this.events.length; i++){
			if (request == this.events[i]){
				return;
			}
		}
		this.events.push(request);
		Element.show(this.progressBarDisplay);
	};
	
	this.removeEvent = function(request){
		for (var i=0; i<this.events.length; i++){
			if (request == this.events[i]){
				this.events.splice(i,1);
				// check to see if this was the last event we were watching, if so, hide the progress bar
				if (this.events.length == 0){
					Element.hide(this.progressBarDisplay);
				}
				return;
			}
			alert("unable to remove event, event not found");
		}
	};
	
	/*
	 * This method may be replaced if we decide to put the div right in the HTML, which would
	 * solve the issue of hard-coding text ("IN PROGRESS") in the javascript
	 */
	this.createChildren = function(){
		var pageBody = document.getElementsByTagName("body")[0];
		var progressBarDiv = document.createElement("div");
		progressBarDiv.setAttribute("id", "progressBarDisplay");
		progressBarDiv.className = "progressBar";
		progressBarDiv.appendChild(document.createTextNode("IN PROGRESS"));
		pageBody.appendChild(progressBarDiv);
		// save a reference to this div
		this.progressBarDisplay = $("progressBarDisplay");
		
		// hide the div, watch for window resizes, and set the initial position
		Element.hide(this.progressBarDisplay);
		Event.observe(window, "resize", this.setPosition, false);
		Event.observe(window, "scroll", this.setPosition, false);
		this.setPosition();
	};
	
	this.setPosition = function(){
		/*
		var progressBarSize = Element.getDimensions("progressBarDisplay");
		var windowWidth = window.innerWidth || document.body.offsetWidth;
		var windowHeight = window.innerHeight || document.body.offsetHeight;
		var scrollXDelta = self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
		var scrollYDelta = self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
		var padding = 10;
		this.progressBarDisplay.style.left = windowWidth - progressBarSize.width - padding + scrollXDelta + "px";
		this.progressBarDisplay.style.top = scrollYDelta + padding + "px";
		*/
		var progressBarSize = Element.getDimensions("progressBarDisplay");
		var padding = 10;
		var posY = 0;
		if (window.innerHeight){
			posY = window.pageYOffset;
		} else if (document.documentElement && document.documentElement.scrollTop){
			posY = document.documentElement.scrollTop;
		} else if (document.body){
			posY = document.body.scrollTop;
		}
		posY = (posY < padding) ? padding : posY;
		this.progressBarDisplay.style.top = posY + "px";
	}.bind(this);
};



/*
var Single = (function(){
	var instance = null;
	function InnerSingle(){
		// actual constructor
		this.X = "something";
	}
	InnerSingle.prototype.getX = function(){
		return this.X; //example method
	}
	return ({
		getInstance: function(){
			if (!instance){
				instance = new InnerSingle();
			}
			return instance;
		}
	});
})();

var obj1 = Single.getInstance();
var obj2 = Single.getInstance();
alert("obj1 == obj2: " + (obj1==obj2));

//var pb1 = ProgressBar().getInstance();
//var pb2 = ProgressBar().getInstance();
//alert("pb1 == pb2: " + (pb1==pb2));

var sin1 = Singleton.getInstance();
var sin2 = Singleton.getInstance();
alert("sin1 == sin2: " + (sin1==sin2));
*/