
var Ajax = {
	//get ajax object if it is created

	oAjaxObject: null,
	oAjaxCreated: false,

	getAjaxObject: function() {
		var xhr = null;
		if (Ajax.oAjaxCreated) {
			return Ajax.oAjaxObject;
		} else {
			try {
				if (window.ActiveXObject) {
					try {
						// Create the request object; Microsoft failed to properly
						// implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
						xhr = new ActiveXObject("Microsoft.XMLHTTP");
					} catch (ex) {
						xhr = new XMLHttpRequest();
					}
				} else {
					xhr = new XMLHttpRequest();
				}
			} catch (err) {
				xhr = null;
			}
		}
		Ajax.oAjaxCreated = true;
		Ajax.oAjaxObject = xhr;
		return Ajax.oAjaxObject;

	},

	ajaxAvailable: function() {
		if (Ajax.getAjaxObject() != null)
			return true;
		else
			return false;
	},
	/******************************************************************************/
	/*	submit

	elem: Pass the form element, or a form input element
	If null, must set a dest link with full parameters in GET style.
	url: Destination URL. If null, form.action will be used.
		
	*/

	submit: function(elem, url, options) {
		elem = $j(elem);
		if (!Ajax.ajaxAvailable()) {
			if (options != undefined && !options.silent) {
				hideMessageBox();
				$j('.titlebar_message_box').hide();
			}
			//always show in progress spining
			if (options != undefined && options.modalInProgress != false)
				Ajax.modalInProgress();

			if (!elem.attr('action')) {
				elem.attr('action', url);
			}
			//overwrite all non-ajax form submit to refresh page (post submit)
			elem.bind("submit", function() { return true; });
			elem.submit();
			return true;
		}
		else {
			var formElem;
			if (elem.is('form')) {
				formElem = elem;
				method = formElem.attr('method');
			} else if (elem[0] && elem[0].form) {
				formElem = $j(elem[0].form);
				method = formElem.attr('method') || "POST";
			} else {
				method = "GET";
			}

			if (!url) {
				url = formElem.attr('action');
			}

			var params;
			if (formElem[0]) params = formElem.serialize(true);

			if (!options) options = {};
			options.type = method;
			options.data = params;
			options.url = url;
			Ajax.send(options);
		}
	},

	modalInProgress: function() {
		startBusyPleaseWaitSpin(false);
	},

	/*	Ajax.send resets the session timer, and has the global error handlers.
	It should always be called for ajax, and should be enhanced if needed
	for additional funcionality before directly calling jQuery.ajax elsewhere.
		
	The default onComplete routine, if text/html content-type is received,
	expects for all top-level items in the html to have id's which should exist
	on the calling page. These items are replaced with the new content.
	TODO: this should probably be optional behavior.
	*/

	send: function(options) {

		options = $j.extend(options, {});
		if (options != undefined && !options.silent) {
			hideMessageBox();
			$j('.titlebar_message_box').hide();
			if (options.modalInProgress != false)
				Ajax.modalInProgress();
		}

		if (!Ajax.ajaxAvailable()) {
			//in case we use ajax send but using a browser that is not using ajax, 
			//then we create a form and put all data into the form and submit the form without ajax
			var formElem = Ajax.createForm(options);
			$j('body').append(formElem);
			formElem.submit();
			return;
		}

		var onComplete;

		if (options.silent) {
			// Response is ignored
			if (options.afterOnComplete) {
				// If the user wants this, give it to them even if silent
				onComplete = function(xhr, textStatus) {
					if (options.afterOnComplete) options.afterOnComplete(xhr, textStatus);
				}
			}
		} else if (options.onComplete) {
			onComplete = function(xhr, textStatus) {
				// Right now we just call the other onComplete.
				// This function in here in case we need to add global processing.
				options.onComplete(xhr, textStatus);
				if (options.afterOnComplete) options.afterOnComplete(xhr, textStatus);
				globalPageInit();
			}
		} else {
			// Default complete function
			onComplete = function(xhr, textStatus) {
				// Set final opacity in case there's a redirect and a delay
				if (textStatus == "success") {
					var contentType = xhr.getResponseHeader("Content-type");
					if (contentType == "text/javascript") {
						eval(xhr.responseText);
					} else if (contentType == "text/html") {
						Ajax.replaceElements(xhr, options);
					} else {
						/* Some calls (i.e. Attachment) might return plain text.
						if (options.closeDialog != false)
						$j.modal.close();
						alertFatalError("Invalid Server Response: Server responded with invalid contentType of '" + 
						contentType + "'.");
						*/
					}
				}
				if (options.afterOnComplete) options.afterOnComplete(xhr, textStatus);
				globalPageInit();
			}
		}

		var onError;
		if (!options.silent) {
			onError = function(xhr, textStatus, errorThrown) {
				// typically only one of textStatus or errorThrown will have info
				// TODO: upgrade this to use global.js:modalAlert()
				var response =
					"<div class='message_box error' style='width: 500px'>" +
					"<div><h1>Server Error</h1>" +
					"The operation could not be completed. Please try again momentarily." +
					"<br/>If you continue to have problems, contact support via the <a href='http://support.virtualsoftware.net' target='_blank'>web site</a> or call (888) 874-1118 x2." +
					"<br/><br/>Status: " + (xhr.responseText || XMLHttpRequest.responseText || "No response received.");
				if (xhr.status != null)
					response += "<br/>Code: " + xhr.status;
				if (xhr.statusText != null && xhr.statusText != "")
					response += "<br/>Text: " + xhr.statusText;
				if (errorThrown)
					response += "<br/><br/>Error: " + errorThrown;
				response +=
					"<br/><br/><button type='button' onclick='$j.modal.close();'>Dismiss</button>" +
					"</div></div>";
				$j.modal.open('<div class="error">' + response + '</div>');
				if (options.afterOnError) options.afterOnError(xhr, textStatus, errorThrown);
			};

			// Default ajax timeout
			var timeout = options.timeout || 45000;
		} else if (options.afterOnError) {
			// If the user wants this, give it to them even if silent
			onError = function(xhr, textStatus, errorThrown) {
				if (options.afterOnError) options.afterOnError(xhr, textStatus, errorThrown);
			};
		}

		if (!options.url && options.relativeUrl) {
			if (window.DocumentData.isapiName != undefined) {
				options.url = window.DocumentData.isapiName + options.relativeUrl;
			} else {
				//default window.DocumentData.isapiName is timecard.dll
				options.url = "timecard.dll" + options.relativeUrl;
			}
		}

		// Clear our status flag before sending
		// We probably should blank this out, and all calls should set to success, but that would require lots of back-end changes.
		// For now, we assume that it will be changed in the event of a failure.
		document.xhrStatus = 'success';
		$j.ajax({
			type: options.type,
			data: options.data,
			url: options.url,
			timeout: timeout,
			//beforeSend: function (XMLHttpRequest) {
			//},
			complete: onComplete,
			error: onError
		});
	},

	replaceElements: function(xhr, options) {
		if ($j.isFunction(options.beforeReplaceElements))
			options.beforeReplaceElements();

		// Create a dummy div to hold the results
		var items = $j("<div/>").append(xhr.responseText);
		var terminate = false;
		items.children().each(function(idx) {
			if (terminate)
				return;
			if (!this.id) {
				// ID is required
				var html = '<code>' + this + '</code>';
				alertFatalError("Invalid Server Response: Response ID missing.");
				terminate = true;
				return;
			}
			var existingElem;
			if (options.context)
				existingElem = $j(options.context).find("#" + this.id);
			else
				existingElem = $j("#" + this.id);
			if (existingElem.length == 0) {
				// Matching destination for response item not found
				alertFatalError("Invalid Server Response: Response ID '" + this.id + "' not found in current document.");
				terminate = true;
				return;
			}
			if ($j.isFunction(window.pngfix)) pngfix(this); // IE6 only
			// Call css fixup routines on new content
			stripeTables($j(this).find('table.striped'));
			styleInputs(this);
			// Replace old element with new, to ensure new style, class, etc. is captured
			existingElem.before(this).remove();
		});

		// Close dialog before afterReplaceElements, it might open another dialog
		if (options.closeDialog != false)
			$j.modal.close();

		if ($j.isFunction(options.afterReplaceElements)) {
			options.afterReplaceElements(xhr);
		}

	},

	createForm: function(options) {
		// dynamically create a form for submit when not using ajax
		var formElem = $j("<form action='' method='' onsubmit='return true;' style='display: none;'></form>");

		// create attributes from the ajax object
		if (options.type)
			formElem.attr("method", options.type);
		if (options.url)
			formElem.attr("action", options.url);
		if (options.relativeUrl)
			formElem.attr("action", DocumentData.isapiName + options.relativeUrl);
		//TODO: add more attr modification here if needed

		// append the input from parsing the data section

		// due to name field can't use attr to set, we have to use string and then convert to a form input
		if (options.data != undefined) {
			if (options.data[0] == undefined) {
				if (typeof (options.data) == "string") {
					//this case if for commands in query string 
					var params = options.data.split("&");
					for (var i in params) {
						var input = "<input type='hidden' ";
						var pairInParam = params[i].split("=");
						if (pairInParam.length == 2) {
							input += "name='" + pairInParam[0] + "' ";
							//since it is query string, the data is escaped. (don't need to unescape it?)
							if (pairInParam[0] == "moddate") {
								pairInParam[1] = pairInParam[1].replace("+", " ")
							}
							input += "value='" + unescape(pairInParam[1]) + "' />";
							var oInput = $j(input);
							formElem.append(oInput);
						}
					}
				} else {
					//this case is for options.data in json format. which is not a array of name/value pair
					for (var i in options.data) {
						var input = "<input type='hidden' ";
						if (typeof (options.data[i]) == "string" || typeof (options.data[i]) == "number") {
							input += "name='" + i + "' ";
							input += "value='" + unescape(options.data[i]) + "' />";
						}
						var oInput = $j(input);
						formElem.append(oInput);
					}
				}
			}
			else {
				//this case if for commands in query string 
				// IE 6 & 8 will fall into this case
				if (typeof (options.data) == "string") {
					var params = options.data.split("&");
					for (var i in params) {
						var input = "<input type='hidden' ";
						var pairInParam = params[i].split("=");
						if (pairInParam.length == 2) {
							input += "name='" + pairInParam[0] + "' ";
							//since it is query string, the data is escaped. (don't need to unescape it?)
							if (pairInParam[0] == "moddate") {
								pairInParam[1] = pairInParam[1].replace("+", " ")
							}
							input += "value='" + unescape(pairInParam[1]) + "' />";
							var oInput = $j(input);
							formElem.append(oInput);
						}
					}
				} else {
					//this case is for options.data in a array of name/value pair format
					for (var i = 0; i < options.data.length; i++) {
						var input = "<input type='hidden' ";
						if (typeof (options.data[i]) == "object") {
							input += "name='" + options.data[i].name + "' ";
							input += "value='" + options.data[i].value + "' />";
						}
						var oInput = $j(input);
						formElem.append(oInput);
					}
				}
			}
		}
		return formElem;
	}

}