/**
 * 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 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;
		}
	}
}