/** public URLUtility : Encapsulates functionality to access/modify a request.
  * @param HTMLDocument doc Document to read querystring from; default is current document
  */
function URLUtility(doc) {
	this.location = (doc) ? doc.location : document.location;
	this.qs = URLUtility.trim(this.location.search);
	this.map = URLUtility.generateMap(this.qs);
	return this;
}
/** public static Map generateMap : Build a key/value map out of a querystring.
  * Keys with multiple values contain an array of their values.
  * Basically the opposite of URLUtility.generateQuerystring().
  * @param String querystring String of key/value pairs to build into map
  * @return Map of paramName:paramValues
  */
URLUtility.generateMap = function(querystring) {
	if (querystring.length > 0) {
		var qspairs = querystring.split("&");
		var qsparms = new Array();
		for (var i=0; i<qspairs.length; i++) {
			if (!qspairs[i]) continue;
			var spaceRE = new RegExp("\\+", "g");
			var qspair = qspairs[i].split("=");
			var qskey = unescape(qspair[0].replace(spaceRE, " "));
			var qsval = (qspair[1]) ? unescape(qspair[1].replace(spaceRE, " ")) : "";
			if (qsparms[qskey] && (qsparms[qskey] == qsval)) continue;
			if (!qsparms[qskey]) {
				qsparms[qskey] = qsval;
				continue;
			}
			if (typeof qsparms[qskey] == "string") qsparms[qskey] = [qsparms[qskey], qsval];
			else qsparms[qskey][qsparms[qskey].length] = qsval;
		}
		return qsparms;
	}
	return null;
}
/** public static String generateQuerystring : Convert a parameter map to a querystring.
  * Basically the opposite of URLUtility.generateMap().
  * @return Querystring built from map.
  */
URLUtility.generateQuerystring = function(map) {
	if (!map) return "";
	var str = "";
	for (var key in map) {
		if (isArray(map[key])) {
			for (var i=0; i<map[key].length; i++) str += key + "=" + map[key][i] + "&";
		} else {
			str += key + "=" + map[key] + "&";
		}
	}
	return URLUtility.trim(str);
}
/* public static String prefix : Prepend a "?" if necessary.
 * @param String querystring Querystring to trim
 * @return Prepended querystring
 */
URLUtility.prefix = function(querystring) {
	return (querystring.charAt(0) == "?") ? querystring : "?" + querystring;
}
/* public static String trim : Strip off a leading "?", and a trailing "&".
 * @param String querystring Querystring to trim
 * @return Trimmed querystring
 */
URLUtility.trim = function(querystring) {
	var trimRE = new RegExp("^\\??(.*[^&])&?$");
	return (trimRE.test(querystring)) ? RegExp.$1 : "";
}

/** public void addParameterValue : Add a value to a parameter with multiple values,
  * e.g. a checkbox array. Automatically converts parameter's value to an array.
  * @param String paramName Name of parameter to add value to
  * @param String paramValue Value to add
  */
URLUtility.prototype.addParameterValue = function(paramName, paramValue) {
	if (!this.map[paramName]) this.map[paramName] = [];
	else if (!isArray(this.map[paramName])) this.map[paramName] = [this.map[paramName]];
	this.map[paramName].push(paramValue);
}
/** public String getBaseHref : Get the base href of the current site, as defined in the
  * <base href...> tag. Excludes VehicleDetails vehicle ids and AdWizard ad ids.
  * @return Website's base href
  */
URLUtility.prototype.getBaseHref = function() { return document.getElementById("baseHref").href; }
/** public String||Array getParameter : Get the value of the given parameter in the querystring;
  * can be a string or a string array, e.g. of checkbox array values.
  * @param String paramName Name of parameter
  * @return Value of parameter
  */
URLUtility.prototype.getParameterMap = function() { return this.map; }
URLUtility.prototype.getParameter = function(paramName) {
	var paramValue = [];
	for (var key in this.map) {
		if (key == paramName) return this.map[key];
	}
	return null;
}
/** public Map getParameterMap : Get the map of querystring parameter values.
  * @return Map of parameter values
  */
URLUtility.prototype.getParameterMap = function() { return this.map; }
/** public String getQuerystring : Get the querystring this instance refers to.
  * @return Querystring
  */
URLUtility.prototype.getQuerystring = function() { return this.qs; }
/** public String getUrl : Get a full url, based on the current request,
  * using an updated querystring from this instance's map.
  * @return URL with updated querystring
  */
URLUtility.prototype.getUrl = function() {
	var currentHref = this.location.href;
	return currentHref.replace(/\?.*$/, URLUtility.prefix(this.toString()));
}
/** public boolean populateForm : Populate a form from this instance's map.
  * Does not populate "file" inputs, due to browser security rules.
  * @param HTMLForm form Form object to populate
  * @return True if form population was successful
  */
URLUtility.prototype.populateForm = function(form) {
	if (!form) return false;
	var returnValue = false;
	for (var fieldname in this.map) {
		if (form[fieldname]) {
			returnValue = true;
			switch(form[fieldname].type) {
			case "file": case "button": case "submit": case "reset": case "image":
				break;
			case "text": case "password": case "textarea": case "hidden":
				form[fieldname].value = this.map[fieldname];
				break;
			default:
				if (typeof this.map[fieldname] == "string") {
					setSelected(form[fieldname], this.map[fieldname]);
				} else {
					for (var i=0; i<this.map[fieldname].length; i++) setSelected(form[fieldname], this.map[fieldname][i]);
				}
				break;
			}
		}
	}
	return returnValue;
}
/** public void removeParameter : Delete a parameter's entry in the map.
  * Optionally specify a value, if only one value in an array should be deleted.
  * @param String paramName Name of parameter to remove
  * @param String paramValue Specific value to remove; default is all
  */
URLUtility.prototype.removeParameter = function(paramName, paramValue) {
	for (var key in this.map) {
		if (key == paramName) {
			if ((arguments.length > 1) && isArray(this.map[key])) {
				for (var i=0; i<this.map[key].length; i++) {
					if (this.map[key][i] == paramValue) delete(this.map[key][i]);
				}
			} else {
				delete(this.map[key]);
			}
			break;
		}
	}
}
/** public void setParameter : Set the value for the given parameter.
  * Does NOT handle params with multiple values; use addParameterValue().
  * @param paramName Name of parameter
  * @param paramValue Value to set
  */
URLUtility.prototype.setParameter = function(paramName, paramValue) { this.map[paramName] = paramValue; }
/** public void setParameterMap : Set the map of querystring parameter values.
  * @param Map newMap New map to set
  */
URLUtility.prototype.setParameterMap = function(newMap) { this.map = newMap; }
/** public void setQuerystring : Set the querystring this instance refers to.
  * @return String newQS New querystring for this instance
  */
URLUtility.prototype.setQuerystring = function(newQS) { this.qs = newQS; }
/** public String toString : Convert this instance's parameter map to a querystring.
  * @return Querystring built from map.
  */
URLUtility.prototype.toString = function() { return URLUtility.generateQuerystring(this.map); }

if (!window.pageUrlUtility) {
	/** public URLUtility pageUrlUtility : A JS wrapper for accessing/manipulating the querystring. */
	var pageUrlUtility = new URLUtility();
	/** public Hashmap pageParams : Encapsulates the key/value pairs on the querystring. */
	var pageParams = pageUrlUtility.getParameterMap();
	if (!pageParams) pageParams = {};
}

/** public boolean isArray : Test if given object is an array.
  * @param obj Object to test
  * @return True if object is an array
  */
isArray = function(obj) {
	return (((typeof obj).toLowerCase() == "object") && (obj.length != undefined));
}

/** public String trim : Trim the whitespace off the ends of a string.
  * @return Trimmed string
  */
String.prototype.trim = function() {
	return this.replace(/^\s*([^\s].*[^\s])?\s*$/, "$1");
}

attachEventListener = function(targetObject, eventName, listener, useCapture) {
	if (arguments.length <= 3) var useCapture = false;
	var result = true;
	if (targetObject.attachEvent) result = targetObject.attachEvent("on" + eventName, listener);
	else targetObject.addEventListener(eventName, listener, useCapture);
	return result;
}

function linkToPage(url, target, replaceURL) {
	if (editMode) return;	
	// if relative link, use base href.
	if ((url.toLowerCase().indexOf("http:") != 0) && (url.toLowerCase().indexOf("https:") != 0)) {
		url = pageUrlUtility.getBaseHref() + url;
	}

	var win = null;
	if (target && window[target.replace(/^_/, "")]) win = window[target.replace(/^_/, "")];
	else if (!target) win = window;
	
	if (win) {
		win.document.location.href = url;
	} else {
		var newwin = window.open(url, "", "");
		newwin.name = target;
	}
}


/** public void toggleDebug : Toggle the debugging information on an error page.
  * @param String errorIndex Numeric index of the error page instance, since there can be multiple
  */
function toggleDebug() {
	var debugWrapper = document.getElementById("errorDebugWrapper");
	var displayDebug = (debugWrapper.style.display == "block") ? false : true;
	document.images["errorToggleDebugDown"].style.display = (displayDebug) ? "none" : "inline";
	document.images["errorToggleDebugUp"].style.display = (displayDebug) ? "inline" : "none";
	document.getElementById("errorToggleActionShow").style.display = (displayDebug) ? "none" : "inline";
	document.getElementById("errorToggleActionHide").style.display = (displayDebug) ? "inline" : "none";
	debugWrapper.style.display = (displayDebug) ? "block" : "none";
}
