// Interface fixes

/**
*	If Node is undefined, then define some constants for IE.
*/
if (typeof Node == "undefined") {
	Node = function() {};
	Node.ELEMENT_NODE = 1;
    Node.ATTRIBUTE_NODE = 2;
    Node.TEXT_NODE = 3;
    Node.CDATA_SECTION_NODE = 4;
    Node.ENTITY_REFERENCE_NODE = 5;
    Node.ENTITY_NODE = 6;
    Node.PROCESSING_INSTRUCTION_NODE = 7;
    Node.COMMENT_NODE = 8;
    Node.DOCUMENT_NODE = 9;
    Node.DOCUMENT_TYPE_NODE = 10;
    Node.DOCUMENT_FRAGMENT_NODE = 11;
    Node.NOTATION_NODE = 12;
}

/**
*	Give IE a NodeFilter.
*/
if (typeof NodeFilter == "undefined") {
	NodeFilter = function() {
	};
	NodeFilter.FILTER_ACCEPT = 1;
	NodeFilter.FILTER_REJECT = 2;
	NodeFilter.FILTER_SKIP = 3;
	NodeFilter.SHOW_ALL = -1;
	NodeFilter.SHOW_ELEMENT = 1;
	NodeFilter.SHOW_ATTRIBUTE = 2;
	NodeFilter.SHOW_TEXT = 4;
	NodeFilter.SHOW_CDATA_SECTION = 8;
	NodeFilter.SHOW_ENTITY_REFERENCE = 16;
	NodeFilter.SHOW_ENTITY = 32;
	NodeFilter.SHOW_PROCESSING_INSTRUCTION = 64;
	NodeFilter.SHOW_COMMENT = 128;
	NodeFilter.SHOW_DOCUMENT = 256;
	NodeFilter.SHOW_DOCUMENT_TYPE = 512;
	NodeFilter.SHOW_DOCUMENT_FRAGMENT = 1024;
	NodeFilter.SHOW_NOTATION = 2048;
}

// Prototype (Javascript, not the library) additions.

/**
	Trim both sides of a string.
*/
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
};

/**
	Trim left side of a string.
*/
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
};

/**
	Trim right side of a string.
*/
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
};

/**
	Parses a string into a JSONObject.
*/
String.prototype.parseJSON = function () {
    try {
    	 return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
            eval('(' + this + ')');
    } catch (e) {
        return false;
    }
};

// Event listener wrappers

/**
	Returns an eventListener-style object for a particular browser. It'll either be W3C or MS.
*/
function addListener(node, event, funktion, bubble) {
	if (node.addEventListener) {
		node.addEventListener(event, funktion, bubble);
	} else if (node.attachEvent) {
		node.attachEvent(["on", event].join(""), funktion);
	}
};

/**
	Removes an eventListener-style object for a particular browser.
*/
function removeListener(node, event, func, bubble) {
	if (node.removeEventListener) {
		node.removeEventListener(event, func, bubble);
	} else if (node.detachEvent) {
		node.detachEvent(["on", event].join(""), func);
	}
};

/**
*	Force events to return false if they are handled in listeners.
*/
function stopEvent(e) {
	if (e.preventDefault) {
		e.preventDefault();
	} else if (e.returnValue) {
		e.returnValue = false;
	}
};

// DOM utilities

/**
	Finds the actual type of an object. For some reason, typeof [1, 2, 3] will return "object" instead of "array". This is true for all browsers.
*/
function typeOf(what) {
	var t = typeof what;
	if (t === "object") {
		if (what) {
			if (what instanceof Array) {
				t = "array";
			}
		} else {
			t = "null";
		}
		
	}
	return t;
};

/**
*	Is it a function?
*/
function isFunction(what) {
	if (typeOf(what) == "function") {
		return true;
	}
	return false;
};

/**
	Overwrites a node's class name.
	
	@param node The node to change.
	@param className The class name to apply to the node.
*/
function setClass(node, className) {
	node.className = className;
};

/**
	Adds a class to a node's existing set of class names.
	
	@param node The node to add the class name to.
	@param className The name of the class to add.
*/
function addClass(node, className) {
	var classes = node.className.split(" ");
	classes.push(className);
	node.className = classes.join(" ");
};

/**
	Removes a class name from a node's existing set of class names.
	
	@param node The node to remove the class name from.
	@param className The name of the class to remove.
*/
function removeClass(node, className) {
	var pattern = new RegExp(["(^|\\s)" , className , "(\\s|$)"].join(""));
	node.className = node.className.replace(pattern, " ");
};

/**
	Replaces a class name on a node's existing set of class names.
	
	@param node The node to remove the class name from.
	@param search The name of the class to remove.
	@param replace The name of the class to add.
*/
function replaceClass(node, search, replace) {
	removeClass(node, search);
	addClass(node, replace);
};

function kill(node) {
	if (node) {
		log("killing " + node);
		return node.parentNode.removeChild(node);
	}
};


/**
	Gets the style object for a node.
	
	@param node The node from which to extract the style.
*/
function getStyle(node) {
	if (node.style) {
		return node.style;
	} else if (node.currentStyle) {
		return node.currentStyle;
	}
	return false;
};

/**
	Produces a collection of nodes based on their class name.
	
	@param node Reference to a root node to begin the search
	@param className The class name you're looking for
	@param tagName (Optional) The name of the tag you're looking for. Including this parameter will make this function run faster. This can either be an array of tags or a string.
*/
function getElementsByClassName(node, className, tagName) {
	var classes = [];
	var tags = (tagName != null) ? tagName : "*";
	
	if (typeOf(tags) !== "array") {
		tags = [tags];
	}
	for (var i in tags) {
		var tag = tags[i];
		var elements = node.getElementsByTagName(tag);
		var eLength = elements.length;
		var pattern = new RegExp(["(^|\\s)" , className , "(\\s|$)"].join(""));
		var i = 0;
		var j = 0;
		for (i = 0, j = 0; i < eLength; i++) {
			if (pattern.test(elements[i].className)) {
				classes.push(elements[i]);
			}
		}
	}
	return classes;
};


/**
	Produces a collection of nodes based on their class name.
	
	@param node Reference to a root node to begin the search
	@param classNames A collection of class names and their types
	
*/
function getElementsByManyClassNames(node, classNames) {
	
	var klasses = {};

	
	if (typeOf(classNames) !== "array") {
		classNames = [classNames];
	}
	
	for (var i in classNames) {
		var className = classNames[i].klass;
		var tags = classNames[i].tag;
		if (typeOf(tags) != "array") {
			tags = [tags];			
		}
		
		for (var tag in tags) {
			var elements = node.getElementsByTagName(tags[tag]);
			var eLength = elements.length;
		
			var pattern = new RegExp(["(^|\\s)" , className , "(\\s|$)"].join(""));
			var i = 0;
			var j = 0;
			for (i = 0, j = 0; i < eLength; i++) {
				if (pattern.test(elements[i].className)) {
					if (!klasses[className]) {
						klasses[className] = [];
					}
					klasses[className].push(elements[i]);
				}
			}
		}
	}
	for (var i in klasses) {
		if (!klasses[i]) {
			klasses[i] = [];
		}
	}
	return klasses;
};

/**
	IE's implementation of document.getElementsByName is idiotic. This will slow things down for that
	browser, but should work correctly for others.<b>

	@param node The node to search for.
	@param name The name to search for.
*/
function getElementsByName(node, name) {
	if (webapp.isIE()) {
		var nodes = document.getElementsByTagName(node);
		var ie_nodes = [];
		var nlen = nodes.length;
		for (var i = 0; i < nlen; i++) {
			var n = nodes[i];
			if (n.name && n.name == name) {
				ie_nodes.push(n);
			}
		}	
		return ie_nodes;
	} else {
		return document.getElementsByName(name);
	}
};

function findPosition(node) {
	var curleft = curtop = 0;
	if (node.offsetParent) {
		do {
			curleft += node.offsetLeft;
			curtop += node.offsetTop;
		} while (node = node.offsetParent);
	}
	return { x: curleft, y: curtop };
};

// Objects

/**
	Makes an ajax request object
*/
function XHR() {
	var xhr;
	try {
		xhr = new XMLHttpRequest();
	} catch (e) {
		try {
			xhr = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xhr = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				return false;
			}
		}
	}
	return xhr;
};

function InternetExplorer() {
	if (!InternetExplorer._I) {
	
		InternetExplorer.prototype.SELECT_CLASS_NAME = "ie-hide-select";
		
		InternetExplorer.prototype.init = function() {
		
		};
		
		InternetExplorer.prototype.forceFlyoutWidths = function(node) {
			if (!node) {
				return;
			}
			var style = getStyle(node);
			
		};
		
		InternetExplorer.prototype.unwreckSelects = function(node) {
			var coords = {};
			coords.top = { x : node.offsetLeft, y : node.offsetTop };
			coords.bottom = { x : node.offsetLeft, y : coords.y + node.offsetHeight };
			coords.width = node.offsetWidth;
			coords.height = node.offsetHeight;
			
			// now get all the selects and see where they are on the page
			var selects = document.getElementsByTagName("select");
			for (var i = selects.length - 1; i > -1; i -= 1) {
				var sel = selects[i];
				var parent = sel.offsetParent;
				var left = sel.offsetLeft;
				var top = sel.offsetTop;
				left += parent.offsetLeft;
				top += parent.offsetTop;
				while (parent = parent.offsetParent) {
					left += parent.offsetLeft;
					top += parent.offsetTop;
				}
				var bottom = top + sel.offsetHeight;
				if (left >= coords.top.x && left <= coords.top.x + coords.width) {

					if ((top >= coords.top.y && top <= coords.top.y + coords.height) || (bottom >= coords.top.y && bottom <= coords.top.y + coords.height)) {
						sel.className = this.SELECT_CLASS_NAME;
					}
				}
				

			}	
		};
		
		InternetExplorer.prototype.wreckSelects = function(node) {
			var selects = document.getElementsByTagName("select");
			var pattern = /ie-hide-select/;
			for (var i = selects.length - 1; i > -1; i -= 1) {
				if (selects[i].className.match(pattern)) {
					selects[i].className = selects[i].className.replace(pattern, "");
				}
			}
		};
		
		InternetExplorer.prototype.fixFlyout = function(node) {
			if (!node) {
				return;
			}
			var width = node.offsetWidth;
			var style = getStyle(node);
			style.width = [width, "px"].join("");
		};
		
		InternetExplorer._I = 1;
	}
};

/**
	Convenience wrapper for getting/setting cookies.
*/
function Cookie() {
	if (!Cookie._i) {
		Cookie.prototype.set = function(key, value, maxAge) {
			var today = new Date();
			var later;
			if (maxAge) {
				later = new Date(today.getTime() + (maxAge * 1000));	
			} else {
				later = new Date(today.getTime() + 31536000000);
			}
			document.cookie = [key, "=", escape(value), "; expires=", later.toGMTString(), "; path=/"].join("");
		};
		Cookie.prototype.get = function(key) {
			var keyLength = key.length;
			var cookie = document.cookie;
			var cookieLength = cookie.length;
			var cookieEnd = null;
			for (var i = 0; i < cookieLength; i++) {
				var j = i + keyLength;
				if (cookie.substring(i, j) == key) {
					cookieEnd = cookie.indexOf(";", j);
					if (cookieEnd == -1) {
						cookieEnd = cookie.length;
					}
					return unescape(cookie.substring(j + 1, cookieEnd));
				}
			}
			return false;
		};
		Cookie.prototype.expire = function(key) {
			var today = new Date();
			var before = new Date(today.getTime() - 31536000000);
			document.cookie = [key, "=; expires=", before.toGMTString(), "; path=/"].join("");
		};
		Cookie.prototype.dump = function() {
			alert(document.cookie);
		};
		Cookie._i = 1;
	}
};

/**
	Convenience method to treat URL query strings as if it were a common map.
*/
function QueryStringParser(str) {
	this.qs = "";
	this.host = "";
	this.chunks = {};

	QueryStringParser.prototype.init = function() {
		var string = "";
		if (str) {
			string = str.split("?");
		} else {
			string = window.location.href.split("?"); 
		}
		if (!string || string.length < 2) { return; }
		this.host = string[0];
		var pieces = string[1].split("&");
		for (var i = 0; i < pieces.length; i++) {
			try {
				var bits = pieces[i].split("=");
				this.chunks[bits[0]] = bits[1];
			} catch (e) {
				alert(e);
			}
		}
	};
	
	QueryStringParser.prototype.get = function(key) {
		return this.chunks[key];
	};
	
	QueryStringParser.prototype.getHost = function() {
		return this.host;
	};

	QueryStringParser.prototype.set = function(key, value) {
		this.chunks[key] = value;
	};
		
	this.init();
};


/**
	Browser sniffer.
*/
function BrowserDetector() {

	this.browserName;
	this.browserVersion;
	this.ie = false;
	this.broken = false;
	
	if (!BrowserDetector._I) {
		BrowserDetector.prototype.init = function() {
			if (document.all) {
				this.ie = true;
			}
			var version = 0;
			if (navigator.appVersion.indexOf("MSIE") != -1) {
				version = navigator.appVersion.split("MSIE");
				this.browserName = "Internet Explorer";
				this.browserVersion = parseFloat(version[1]);
			} else if (navigator.userAgent.match(/applewebkit/i)) {
				var versions = navigator.userAgent.split("/");
				versions = versions[versions.length - 2].split(" ");
				this.browserName = "Safari";
				this.browserVersion = versions[0];
			} else if (navigator.userAgent.match(/gecko/i)) {
				var versions = navigator.userAgent.split("/");
				this.browserName = "Mozilla";
				this.browserVersion = versions[versions.length - 1];
			} else {
				this.browserName = "Unknown";
				this.browserVersion = 0;
			}
		};
		
		BrowserDetector.prototype.isIE = function() {
			return this.ie;
		};
		
		BrowserDetector.prototype.isBroken = function() {
			if (this.ie && this.browserVersion < 7) {
				return true;
			}
			return false;
		};
		
		BrowserDetector.prototype.getName = function() {
			return this.browserName;
		};
		
		BrowserDetector.prototype.getVersion = function() {
			return this.browserVersion;
		};
				
		BrowserDetector._I = 1;
	}
	this.init();
};

/**
*	Main interface to the web application.
*/
function Webapp() {
	
	this.debug = false;
	this.loggingEnabled = true;
	this.ieLoggingEnabled = false;
	this.URLPrefix = "/consumer";
	
	if (!Webapp._I) {
		Webapp.prototype.browserDetector = new BrowserDetector();
		Webapp.prototype.init = function() {
			
		};
		
		Webapp.prototype.getURL = function(path) {
			return [this.URLPrefix, path].join("");
		};
		
		/**
			Returns whether or not the webapp is in debug mode.
		*/
		Webapp.prototype.isDebug = function() {
			return this.debug;
		};
		
		Webapp.prototype.reload = function() {
			window.location.reload();
		};
		
		Webapp.prototype.isIE = function() {
			return this.browserDetector.isIE();
		};
		
		Webapp.prototype.isBroken = function() {
			return this.browserDetector.isBroken();
		};
		
		Webapp.prototype.log = function(message) {
			if (this.loggingEnabled && typeof console != "undefined" && console.log) {
				if (typeof message == "object") {
					console.log(message.join(" "));
				} else {
					console.log(message);
				}
			} 
		};
		
		Webapp._I = 1;
	}
	this.init();
};

var webapp = new Webapp();

/**
*	Shortcut to Firebug's console log.
*/
function log(message) {
	webapp.log(message);
};

function addListener(node, event, funktion, bubble) {
	if (node.addEventListener) {
		node.addEventListener(event, funktion, bubble);
	} else if (node.attachEvent) {
		node.attachEvent(["on", event].join(""), funktion);
	}
};

function removeListener(node, event, func, bubble) {
	if (node.removeEventListener) {
		node.removeEventListener(event, func, bubble);
	} else if (node.detachEvent) {
		node.detachEvent(["on", event].join(""), func);
	}
};

function getStyle(node) {
	if (node.style) {
		return node.style;
	} else if (node.currentStyle) {
		return node.currentStyle;
	}
	return false;
};

function updateInnerHTML(node, innerHTML) {
	node.innerHTML = "";
	var div = document.createElement("div");
	div.innerHTML = innerHTML;
	node.appendChild(div);
};


String.prototype.parseJSON = function () {
    try {
    	 return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
            eval('(' + this + ')');
    } catch (e) {
        return false;
    }
};

function XHR() {
	var xhr;
	try {
		xhr = new XMLHttpRequest();
	} catch (e) {
		try {
			xhr = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xhr = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				return false;
			}
		}
	}
	return xhr;
};

function materialize(node) {
	var style = getStyle(node);
	style.display = "block";
};

function spiritualize(node) {
	var style = getStyle(node);
	style.display = "none";
};

function getCoordinates(e) {
	var px;
	var py;
	if (e.pageX && e.pageY) {
		px = e.pageX;
		py = e.pageY;
	} else {
		px = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - document.body.clientLeft;
		py = e.clientY + document.body.scrollTop + document.documentElement.scrollTop - document.body.clientTop;
	}
	var coords = { x : px , y : py };
	return coords;
};


function Flyout(e, func) {
	if (!e) {
		return false;
	}

	this.event = e;
	this.id = "flyout";
	this.headerId = "flyout-header";
	this.contentId = "flyout-content";
	this.imgSrc = "/images/search_button-close.gif";
	this.imgAlt = "[close]";
	this.imgId = "close-flyout";
	this.header = null;
	this.content = null;
	this.ieStyleSet = false;

	if (!Flyout._I) {
		Flyout.prototype.init = function() {
			kill($(this.id));
			this.build();
		};
		
		Flyout.prototype.setStyle = function(property, value) {
			var style = getStyle($(this.id));
			style[property] = value;
			log(style[property] + " " + value);
			this.ieStyleSet = true;
		};
		
		Flyout.prototype.setHeader = function(node) {
			var header = $(this.headerId);
			if (header) {
				this.header = header;
				header.appendChild(node);
				header.appendChild(this.getCloseButton());
			}
		};
		
		Flyout.prototype.fixIE = function() {
			
			var node = $(this.id);
			var style = getStyle(node);
			if (webapp.isIE() && this.ieStyleSet) {
				style.width = "auto";							
				var dt = node.getElementsByTagName("dt")[0];
				var dd = node.getElementsByTagName("dd")[0];
				var dtStyle = getStyle(dt);
				var ddStyle = getStyle(dd);

				dtStyle.width = new Pixel().get(node.offsetWidth - 20);
				ddStyle.width = "auto";
				
			} else {
				style.width = "250px";
			}
			style.border = "0";
			style.zoom = "1.0";
			style.backgroundColor = "transparent";
			var ie = new InternetExplorer();
			ie.wreckSelects(node);
			ie.unwreckSelects(node);
			ie.fixFlyout(node);
		};
		
		Flyout.prototype.getCloseButton = function() {
			var img = document.createElement("img");
			img.id = this.imgId;
			img.src = webapp.getURL(this.imgSrc);
			img.alt = this.imgAlt;
			var me = this;
			img.onclick = function() {
				var node = $(me.id);
				if (webapp.isIE()) {
					var ie = new InternetExplorer();
					ie.wreckSelects();
				}
				kill(node);
				if (isFunction(func)) {
					func();
				}
			};
			return img;
		};
		
		Flyout.prototype.setStandardHeader = function() {
			this.setHeader(this.getCloseButton());
		};
		
		Flyout.prototype.setContent = function(dom) {
			var content = $(this.contentId);
			if (content) {
				content.appendChild(dom);
				if (webapp.isIE()) {
					var ie = new InternetExplorer();
					ie.fixFlyout($(this.id));
				}
			}
		};
		
		Flyout.prototype.clear = function() {
			var content = $(this.contentId);
			if (content) {
				clear(content);
			}
		};
		
		Flyout.prototype.build = function() {
			var div = document.createElement("div");
			div.id = "flyout";
			var content = document.createElement("div");
			content.appendChild(this.getCloseButton());
			
			content.id = "flyout-content";
			div.appendChild(content);
			document.body.appendChild(div);
			this.position();
		};
		
		Flyout.prototype.position = function() {
			var e = this.event || window.event;
			var node = e.target || e.srcElement;
			var xy = getCoordinates(e);
			var style = getStyle($(this.id));
			for (var i in xy) {
				xy[i] = [xy[i], "px"].join("");
			}
			style.top = xy.y;
			style.left = xy.x;
		};
		
		Flyout.prototype.cleanup = function() {
			var style = getStyle($(this.id));
			
		};
		
		Flyout.prototype.show = function(func) {
			var style = getStyle($(this.id));
			
			materialize($(this.id), func);
			
			if (webapp.isIE()) {
				this.fixIE();
			}
		};
		
		Flyout._I = 1;
	}
	this.init();
};





function Followupper() {
	if (!Followupper._I) {
		Followupper.prototype.init = function() {
			var getParent = function(node) {
				var id = node.id;
				if (id) {
					var parent = $(id.split(":")[1]);
					parent.clicked = false;
					return (parent) ? parent : false;
				}
				return false;
			};
			
			var getChild = function(node) {
				if (node.id) {
					var childId = ["fup", node.id].join(":");
					return $(childId);
				}
				return false;
			};
			
			var handleClick = function(e) {
				e = e || window.event;
				var node = e.target || e.srcElement;
				node.clicked = !node.clicked;
				var child = getChild(node);
				if (child) {
					var childStyle = getStyle(child);
					if (node.clicked) {
						childStyle.display = "block";
					} else {
						childStyle.display = "none";
					}
				}
				stopEvent(e);
				return false;
				
			};
			
			var shouldAutoExpand = function(node) {
				var formNodeNames = ["input", "select", "textarea"];
				var autoExpand = false;
				outer_loop:
				for (var i = formNodeNames.length - 1; i > -1; i--) {
					var formNodes = node.getElementsByTagName(formNodeNames[i]);
					if (formNodes) {
						for (var j = formNodes.length - 1; j > -1; j--) {
							var formNode = formNodes[j];
							switch (formNode.nodeName.toLowerCase()) {
								case "input":
									switch(formNode.type.toLowerCase()) {
										case "text":
										case "file":
											if (formNode.value && formNode.value.length > 0) {
												autoExpand = true;
												break outer_loop;
											}	
											break;
									}
									break;
								case "textarea":
									if (formNode.value && formNode.value.length > 0) {
										autoExpand = true;
										break outer_loop;
									}
									break;
								case "select":
									if (formNode.selectedIndex > 0) {
										autoExpand = true;
										break outer_loop;
									}
									break;
							}
						}
					}
				}
				return autoExpand;
			};
			
			var nodes = document.getElementsByClassName("fup");
			var nlen = nodes.length;
			for (var i = 0; i < nlen; i++) {
				var parent = getParent(nodes[i]);
				if (parent) {
					var autoExpand = shouldAutoExpand(nodes[i]);
					
					if (autoExpand) {
						parent.clicked = true;
						var style = getStyle(nodes[i]);
						style.display = "block";
					}
					
					addListener(parent, "click", handleClick, false);
				}
			}
		};
		Followupper._I = 1;
	}
	this.init();
};

function Helper() {
	if (!Helper._I) {
		Helper.prototype.init = function() {
			var handleClick = function(e) {
				e = e || window.event;
				var target = e.target || e.srcElement;
				var id = target.id;
				if (!id) {
					return false;
				}
				var xhr = new XHR();
				var url = webapp.getURL(["/util/get_help.jsp?fragment=", id].join(""));
				xhr.open("GET", url, false);
				xhr.send(null);
				var event = e;
				var div = document.createElement("div");
				updateInnerHTML(div, xhr.responseText); 
				var flyout = new Flyout(event);
				flyout.setContent(div);
				flyout.show();
				stopEvent(e);
				return false;
			};
			var helpers = [];
			var links = document.getElementsByTagName("a");
			var nlen = links.length;
			for (var i = 0; i < nlen; i++) {
				var link = links[i];
				if (link.rel && link.rel.match(/^help$/)) {
					helpers.push(link);
				}
			}
			var hlen = helpers.length;
			for (var i = 0; i < hlen; i++) {
				var helper = helpers[i];
				helper.clicked = false;
				addListener(helper, "click", handleClick, false);
			}
		};
		Helper._I = 1;
	}
	this.init();
};

function IEGalleryFixer() {
	if (!webapp.isIE()) {
		return;
	}
	if (!IEGalleryFixer._I) {
		IEGalleryFixer.prototype.init = function() {
			var gpage = $("galleryPage");
			if (gpage) {
				gtable = getElementsByClassName(gpage, "galleryContainer", "table")[0];
				if (gtable) {
					var handleMouseover = function(e) {
						e = e || window.event;
						var target = e.target || e.srcElement;
						var style = getStyle(target);
						style.filter = "alpha(opacity=75)";
					};
					
					var handleMouseout = function(e) {
						e = e || window.event;
						var target = e.target || e.srcElement;
						var style = getStyle(target);
						style.filter = "alpha(opacity=100)";
					};
					var images = gtable.getElementsByTagName("img");
					for (var i = images.length - 1; i > -1; i--) {
						addListener(images[i], "mouseover", handleMouseover, false);
						addListener(images[i], "mouseout", handleMouseout, false);
					}
				}
			}
		}	
	}
	this.init();
};

function FormValidator() {
	
	this.extraRules = [];
	
	if (!FormValidator._I) {
		
		FormValidator.prototype.redecorateLabels = function(labels) {
			var llen = labels.length;
			for (var i = 0; i < llen; i++) {
				labels[i].id = ["for", labels[i].htmlFor].join(":");	
				removeClass(labels[i], "error");
			}
		};
		
		FormValidator.prototype.addRule = function(node, rule) {
			var ok = true;
			var elen = elements.length;
			
		};
		
		FormValidator.prototype.init = function() {
			
			var handleSubmit = function(e) {
				e = e || window.event;
				
				var form = e.target || e.srcElement;
				var labels = form.getElementsByTagName("label");
				FormValidator.prototype.redecorateLabels(labels);
				
				var elements = form.elements;
				var elen = elements.length;
				var ok = true;
				var firstElement = null;
				var errorNodes = [];
				
				for (var i = 0; i < elen; i++) {
					var element = elements[i];
					if (element.className && element.className.match(/jsRequired/)) {
						switch (element.nodeName.toLowerCase()) {
							case "input":
							case "textarea":
								if (!element.value || element.value.length < 1) {
									ok = false;
									if (!firstElement) {
										firstElement = element;
									}
									errorNodes.push(element);
								}
								break;
							case "select":
								// don't do anything right now because viking doesn't always use empty top options
								break;
						}
					}	
				}
				
				if (!ok) {
					
					var addErrorMessages = function() {
						var errorList = $("errorList");
						if (errorList) {
							var list = errorList.getElementsByTagName("ul")[0];
							if (!list) {
								list = document.createElement("ul");
								errorList.appendChild(list);
							}
							// Remove any javascript-generated nodes before appending new ones.
							var jsErrorListNodes = getElementsByClassName(list, "jsErrorListNode", "li");
							for (var i = jsErrorListNodes.length - 1; i > -1; i--) {
								jsErrorListNodes[i].parentNode.removeChild(jsErrorListNodes[i]);
							}
							var elen = errorNodes.length;
							for (var i = 0; i < elen; i++) {
								var node = errorNodes[i];
								var li = document.createElement("li");
								li.className = "jsErrorListNode";
								var errorLabel = $(["for", node.id].join(":"));
								//Uncomment the following line for the 2.2.2 release
								//addClass(errorLabel, "error");
								var errorLabelText = "";
								if (errorLabel) {
									errorLabelText = ["You must supply a value for the '", errorLabel.firstChild.data.trim(), "' field of this form."].join("");	
								} else {
								
								}
								li.appendChild(document.createTextNode(errorLabelText));
								list.appendChild(li);
							}
						}	
					};
					
					var addPrettyErrorMessages = function() {
						var errorList = $("errorList");
						if (errorList) {
							var errorHeaderId = "jsErrorListHeader";
							var p = $(errorHeaderId);
							if (p) {
								p.parentNode.removeChild(p);
							}
							p = document.createElement("p");
							p.id  = errorHeaderId;
							var errorHeaderText = "";
							if (errorNodes.length > 1) {
								errorHeaderText = "The following required fields are missing:";
							} else if (errorNodes.length == 1) {
								errorHeaderText = "The following required field is missing:";
							}
							p.appendChild(document.createTextNode(errorHeaderText));
							errorList.parentNode.insertBefore(p, errorList);
							
							var list = errorList.getElementsByTagName("ul")[0];
							if (!list) {
								list = document.createElement("ul");
								errorList.appendChild(list);
							}
							// Remove any javascript-generated nodes before appending new ones.
							var jsErrorListNodes = getElementsByClassName(list, "jsErrorListNode", "li");
							for (var i = jsErrorListNodes.length - 1; i > -1; i--) {
								jsErrorListNodes[i].parentNode.removeChild(jsErrorListNodes[i]);
							}
							var elen = errorNodes.length;
							for (var i = 0; i < elen; i++) {
								var node = errorNodes[i];
								var li = document.createElement("li");
								li.className = "jsErrorListNode";
								var errorLabel = $(["for", node.id].join(":"));
								addClass(errorLabel, "error");
								var errorLabelText = "";
								if (errorLabel) {
									errorLabelText = errorLabel.firstChild.data.trim()	
								} else {
								
								}
								li.appendChild(document.createTextNode(errorLabelText));
								list.appendChild(li);
							}
						}
					};
					
					addErrorMessages();
					//addPrettyErrorMessages();
					
					var position = findPosition(firstElement);
					window.scrollTo(0, position.y - 35);
					var elen = errorNodes.length;
					/*
					for (var i = 0; i < elen; i++) {
						errorNodes[i].style.border = "1px solid red";	
					}
					*/
					firstElement.focus();
					stopEvent(e);
					return false;
				}	
			};
			
			var forms = document.getElementsByTagName("form");
			var flen = forms.length;
			
			for (var i = 0; i < flen; i++) {
				var form = forms[i];
				if (form.className && form.className.match(/jsValidate/)) {
					addListener(form, "submit", handleSubmit, false);
				}
			}
		};
	}
	this.init();
};

function DownloadExtender() {
	if (!DownloadExtender._I) {
		DownloadExtender.prototype.init = function() {
			var cookie = new Cookie();
			var val = cookie.get("extranetDownload");
			if (val !== false) {
				cookie.set("extranetDownload", "yes", 60 * 60 * 24);
			} 
		}
	}
	this.init();
};

var windowLoad = function() {
	var functions = [
		Followupper,
		Helper,
		IEGalleryFixer,
		FormValidator,
		DownloadExtender
	];
	var flen = functions.length;
	for (var i = 0; i < flen; i++) {
		new functions[i]();
	}
};

addListener(window, "load", windowLoad, false);
