/*!
	simplecart.js version 2.00.02 2011-03-09
	javascript client-side functions for SimpleCart PHP system
	copyright © 2007-2011 WebAware Pty Ltd
*/

/**
 * javascript client-side functions for SimpleCart PHP system
 *
 * @class
 * @static
 */
var SimpleCart = {

	/**
	 * Initialise this object, and add dynamic interactions to carts on page
	 */
	init : function() {
		var	reCartTableClass = /\bcart_items\b/,
			tables = document.getElementsByTagName("table"),
			i = tables.length;

		// find carts, identified as tables with class "cart_items"
		while (--i >= 0) {
			if (reCartTableClass.test(tables[i].className)) {
				this.cartSetActions(tables[i]);
			}
		}
	},

	/**
	 * Add dynamic interactions to a cart
	 *
	 * @param {HTMLTableElement} cart
	 */
	cartSetActions : function(cart) {
		// find forms for updating item quantities
		var	anchor,
			row, cells, cell, formID,
			updateForm, updateForms = cart.getElementsByTagName("form"),
			reCartForm = /^cartForm_\d+$/,
			i = updateForms.length, j;

		// find all qty update forms in cart
		while (--i >= 0) {
			updateForm = updateForms[i];
			// NB: bug in IE means can't access form's ID normally when field has name "id", so have to access via attributes collection
			formID = updateForm.attributes.id.value;

			if (reCartForm.test(formID)) {

				// get row containing form
				row = updateForm.parentNode.parentNode;

				// get cell containing cart update links
				cells = row.getElementsByTagName("td");
				j = cells.length;
				while (--j >= 0) {
					cell = cells[j];
					if (cell.className == "cartUpdateLinks") {
						// add link for updating quantity
						anchor = document.createElement("a");
						anchor.appendChild(document.createTextNode("update"));
						anchor.href = "#";
						anchor.title = "Update quantity of this item in cart";
						anchor.setAttribute("data-formID", formID);
						anchor.onclick = function() {
							var	formID = this.getAttribute("data-formID"),
								frm = document.getElementById(formID);
							if (frm)
								frm.submit();
							return false;
						};
						cell.appendChild(anchor);
						break;
					}
				}
			}
		}
	},

	/**
	 * Confirm that shopper wants to clear the shopping cart of all items
	 *
	 * @returns {boolean} true for clear, false for retain cart
	 */
	clearCart : function() {
		return confirm("Clear shopping cart of all items - are you sure?");
	},

	/**
	 * Validate PayPal form to confirm required information provided.
	 *
	 * Delegates actual validation to function validatePayPal(), which must be provided by website code.
	 *
	 * @param {HTMLFormElement} frm the PayPal form to validate
	 * @returns {boolean} true if validates
	 */
	onSubmitPayPal : function(frm) {
		var	errmsg = this.validatePayPal(),
			waiting = document.getElementById("waiting");

		if (errmsg.length > 0) {
			alert(errmsg);
			return false;
		}

		if (waiting)
			waiting.style.visibility = "visible";

		return true;
	},

	/**
	 * Default validation function for PayPal form
	 *
	 * To replace with own instance if required, simply implement the method again in page head, e.g.
	 * SimpleCart.validatePayPal = function(frm) { ... }
	 *
	 * @param {HTMLFormElement} frm the PayPal form to validate
	 * @returns {string} any error messages (newline delimited), or empty string if no errors
	 */
	validatePayPal : function(frm) {
		return '';
	},

	/**
	 * Send an AJAX request, either GET or POST, and return the response in parameters to a callback function.
	 *
	 * Pass an object to override default configuration for request, as follows:
	 * <dl>
	 * <dt>method:</dt><dd>string, GET or POST (default: "POST")</dd>
	 * <dt>url:</dt><dd>string, where to send the AJAX request (default: current document location)</dd>
	 * <dt>data:</dt><dd>string, URL-encoded data to send (default: ""); or object, no attributes can be arrays or objects</dd>
	 * <dt>responseFormat:</dt><dd>string, one of "XML", "JSON", "Text" (default: "XML")</dd>
	 * <dt>callbackSuccess:</dt><dd>function, a callback function to receive the response on success</dd>
	 * <dt>callbackError:</dt><dd>function, a callback function to receive the error information</dd>
	 * </dl>
	 *
	 * @param {object} params an object containing configuration parameters for the AJAX request
	 * @returns {boolean} true if request sent successfully
	 */
	ajaxRequest : function(params) {
		var	xhr, i, delim,
			config = {
				callbackError: false,
				callbackSuccess: false,
				data: "",
				method: "POST",
				responseFormat: "XML",
				url: document.location.href
			},
			parseJSON = function(data) {
				if (typeof JSON != "undefined")
					return JSON.parse(data);
				else {
					if (/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(data.replace(/"(?:\\.|[^"\\])*"/g, "")))
						throw new SyntaxError("JSON.parse");
					else
						return eval("(" + data + ")");
				}
			};

		// override the default config with supplied parameters
		if (typeof params == "object") {
			for (i in params) {
				config[i] = params[i];
			}

			// if data is an object, unroll as HTTP post data
			if (typeof params.data == "object") {
				config.data = delim = "";
				for (i in params.data) {
					config.data += delim + encodeURIComponent(i) + '=' + encodeURIComponent(params.data[i]);
					delim = "&";
				}
			}
		}

		// get the XHR object -- standards-compliant browsers
		if (typeof XMLHttpRequest != "undefined") {
			xhr = new XMLHttpRequest();
		}
		else {
			// Internet Explorer
			try {
				xhr = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (e) {
				// older Internet Explorer
				try {
					xhr = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch (e) {
					xhr = false;
				}
			}
		}

		if (xhr) {
			xhr.onreadystatechange = function() {
				if (xhr.readyState == 4) {
					// check for HTTP status of OK
					if (xhr.status == 200) {
						try {
							if (config.callbackSuccess) {
								var response;
								switch(config.responseFormat) {
									case 'XML':
										response = xhr.responseXML;
										break;
									case 'JSON':
										response = parseJSON(xhr.responseText);
										break;
									default:
										response = xhr.responseText;
										break;
								}
								config.callbackSuccess("success", response, xhr);
							}
						}
						catch(e) {
							if (config.callbackError)
								config.callbackError("error", "AJAX request incomplete:\n" + e.toString(), xhr);
						}
					}
					else {
						if (config.callbackError)
							config.callbackError("error", "AJAX request failed: " + xhr.status, xhr);
					}
				}
			};

			if (config.method == "POST") {
				xhr.open("POST", config.url, true);
				xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
				xhr.send(config.data);
			}
			else {
				xhr.open("GET", config.url + "?" + config.data, true);
				xhr.send(null);
			}
			return true;
		}

		// no XHR, so AJAX failed
		return false;
	},

	/**
	 * Hook the "ready" event on either DOM or IE browser
	 *
	 * @param {function} hook a function object to be called when event triggers
	 */
	hookReady : function(hook) {
		if (window.addEventListener)
			window.addEventListener("DOMContentLoaded", hook, false);
		else if (window.attachEvent)
			window.attachEvent("onload", hook);
	},

	/**
	 * Hook an event on either DOM or IE browser
	 *
	 * @param {HTMLHtmlElement} element the HTML element to hook an event on
	 * @param {string} name of the event to hook (e.g. "click", "mouseover")
	 * @param {function} hook a function object to be called when event triggers
	 */
	hookEvent : function(element, event, hook) {
		if (element.addEventListener)
			element.addEventListener(event, hook, false);
		else if (element.attachEvent)
			element.attachEvent("on" + event, function() { hook.call(element, window.event); });
	}

};

// hook page ready to add dynamic interactions to cart
SimpleCart.hookReady(function() { SimpleCart.init(); });

