/**
 * General utility functions
 */
var HTMLUtil = new function() {

	/**
	 * Add unlimited number of events to any element
	 */
	this.addEvent = function(obj, evType, fn) {
		if (obj.addEventListener) {
			obj.addEventListener(evType, fn, false);
			return true;
		} else if (obj.attachEvent) {
			var r = obj.attachEvent("on" + evType, fn);
			return r;
		} else {
			return false;
		}
	}

	/**
	 * Get the dimensions of the document
	 */
	this.getPageSize = function() {
		var xScroll, yScroll;

		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if (self.innerHeight) {	// all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	

		// for small pages with total height less then height of the viewport
		if (yScroll < windowHeight) {
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}

		// for small pages with total width less then width of the viewport
		if (xScroll < windowWidth){	
			pageWidth = windowWidth;
		} else {
			pageWidth = xScroll;
		}

		arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight) 
		return arrayPageSize;
	}

	/**
	 * Find all links, look for the value of the rel attribute and
	 * attach onclick events based on the parameter
	 *
	 * linkRelEvents	- A hash containing the rel values to trigger events
	 *					  as keys and the function pointers as values
	 */
	this.linkRelEvents = function(linkRelEvents) {
		var link;

		for (var i = 0; (link = document.getElementsByTagName('a')[i]); i++) {
			for (var relTrigger in linkRelEvents) {
				if (link.rel == relTrigger) {
					link.onclick = linkRelEvents[relTrigger];
					break;
				}
			}
		}
	}

	/**
	 * Scroll page to an anchor
	 */
	this.scrollToAnchor = function(anchor) {
		if (window.location.href.indexOf('#') >= 0)
			window.location = window.location.href.split('#')[0] + '#' + anchor;
		else
			window.location = window.location + '#' + anchor;
	}
}

/**
 * DOM utils for HTML documents
 */
var HTMLDOMUtil = new function() {
	/**
 	* Dynamically add a class to an element
 	*
 	* element  - The element to add a class to
 	* classAdd - The class to add to the element
	*/
	this.addClass = function(element, classAdd) {
		if (element.className.indexOf(classAdd) >= 0)
			return;

		element.className += element.className ? ' ' + classAdd : classAdd;
	}

	/**
	 * Dynamically remove a class from an element
	 *
	 * element		- The element to remove a class from
	 * className	- The class to remove, if it exists
	 */
	this.removeClass = function(element, className) {
		if (element.className.indexOf(className) < 0)
			return;

		var replace = element.className.match(' ' + className) ? ' ' + className : className;
		element.className = element.className.replace(replace, '');
	}

	/**
	 * Get all elements by class name.
	 *
	 * className	- The class name to fetch elements by
	 * tagName		- Optional, the tag name of the elements returned
	 * rootNode		- Optional, the root node to look form
	 */
	this.getElementsByClassName = function(className, tagName, rootNode) {
		if (tagName == null) tagName = '*';
		if (rootNode == null) rootNode = document;

		var elements = rootNode.getElementsByTagName(tagName);
		var nodes = new Array();

		for (var i = 0; i < elements.length; i++)
			if (elements[i].className.indexOf(className) >= 0)
				nodes[nodes.length] = elements[i];

		return nodes;
	}

	/**
	 * Shorthand for creating DOM nodes. Allows for easily creating
	 * new nodes.
	 *
	 * tagName		   - The tag name of the new node
	 * className	   - Optional, the element class
	 * id			   - Optional, the element id
	 * content		   - Optional, content of the node. If a string it is set
	 *				     to the innerHTML property, else it's appended as a child
	 * extraAttributes - An array of attributes to add: new Array(attribute, value, attr, val, ...)
	 */
	this.createElement = function(tagName, className, id, content, extraAttributes) {
		className = className || null;
		id = id || null;
		content = content || null;
		var attr = extraAttributes || null;

		var el = document.createElement(tagName);

		if (className != null) el.className = className;
		if (id != null) el.id = id

		if (content != null)
			if (typeof(content) == 'string')
				el.innerHTML = content;
			else
				el.appendChild(content);

		if (attr != null)
			for (var i = 0; i < attr.length; i += 2)
				el[attr[i]] = attr[i+1];

		return el;
	}

	/**
	 * Wrap an element in a new element defined by input parameters
	 *
	 * element 		- The element to wrap
	 * wrapTag		- The tag name of the new wrapper (defaults to 'div')
	 * wrapId		- The id of the wrapper
	 * wrapClass	- The class of the wrapper
	 */
	this.wrap = function(element, wrapTag, wrapId, wrapClass) {
		if (element == null || element.parentNode == null)
			return;

		wrapTag = wrapTag || 'div';
		var parent = element.parentNode;
		var radios = HTMLDOMUtil.innerRadios(element);

		var next = element.nextSibling;
		while (next != null && next.nodeType != 1) next = next.nextSibling;

		parent.removeChild(element);
		var wrapper = HTMLDOMUtil.createElement(wrapTag, wrapClass, wrapId, element);
		wrapper.isInsertedDynamically = true;

		if (next != null)
			parent.insertBefore(wrapper, next);
		else
			parent.appendChild(wrapper);

		HTMLDOMUtil.preserveRadios(radios);
	}

	/**
	 * Unwrap an element from it's parent. Discards the parent (and all of the elments siblings) and
	 * attaches the element to it's grandparent
	 */
	this.unwrap = function(element) {
		if (!element.parentNode.isInsertedDynamically)
			return false;

		if (element == null || element.parentNode == null || element.parentNode.parentNode == null)
			return;

		var radios = HTMLDOMUtil.innerRadios(element);
		var el = element;
		var remove = element.parentNode;
		remove.parentNode.insertBefore(el, remove);
		remove.parentNode.removeChild(remove);
		HTMLDOMUtil.preserveRadios(radios);
	}

	/**
	 * Helper function for wrap and unwrap. Need to collect radio buttons and remember if
	 * they are checked since IE doesn't seem to manage this itself
	 */
	this.innerRadios = function(root) {
		var radios = new Array();
		var inputs = root.getElementsByTagName('input');

		for (var i = 0; i < inputs.length; i++)
			if (inputs[i].type == 'radio' && inputs[i].checked)
				radios[radios.length] = inputs[i];

		return radios;
	}

	/**
	 * Helper function for wrap and unwrap. Need to collect radio buttons and remember if
	 * they are checked since IE doesn't seem to manage this itself
	 */
	this.preserveRadios = function(radios) {
		for (var i = 0; i < radios.length; i++)
			radios[i].checked = true;
	}
}

var Cookie = new function() {

	/**
	 * Set a cookie
	 */
	this.set = function(name, value, expires, path, domain, secure) {
		var today = new Date();
		today.setTime(today.getTime());

		/*
		  * if the expires variable is set, make the correct expires time, the current script below will set
		  * it for x number of days, to make it for hours,  delete * 24, for minutes, delete * 60 * 24
		  */
		if (expires)
			expires = expires * 1000 * 60 * 60 * 24;

		var expires_date = new Date(today.getTime() + (expires));
		document.cookie = name + "=" +escape(value) + ((expires) ? ";expires=" + expires_date.toGMTString() : "") + 
						  ((path) ? ";path=" + path : "") + ((domain) ? ";domain=" + domain : "") + ((secure) ? ";secure" : "");
	}

	/**
	  * Get cookie if it exists
	  */
	this.get = function(name) {
		var start = document.cookie.indexOf(name + "=");
		var len = start + name.length + 1;

		if ((!start) && (name != document.cookie.substring(0, name.length)))
			return null;

		if (start == -1)
			return null;

		var end = document.cookie.indexOf(";", len);

		if (end == -1)
			end = document.cookie.length;

		return unescape(document.cookie.substring(len, end));
	}

	/**
	  * Delete cookie
	  */
	this.deleteCookie = function(name, path, domain) {
		path = path != null && path != '' ? ";path=" + path : "";
		domain = domain != null && domain != '' ? ";domain=" + domain : "";

		if (this.get(name))
			document.cookie = name + "=" + path + domain + ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
	}
}