/**
 * DOM
 * More advanced functionality will reside in an external dom.js file
 * @alias $dom
 */
PopJavaScriptFramework.v1B1.dom = {
	/**
	 * Create a new DOM node
	 * @param {String} nodeName			The kind of node to create (div, br, p, etc);
	 * @param {Object} attributes		Optional object map of attributes and values. Example: {id: 'myEl', class: 'myClass'}
	 * @param {String/Array} content	Optional text to set as the textNode OR array of DOMNodes to add to the returned element
	 * @return {DOMNode} DOMNode
	 * NOTE: dom.create is *heavily* influence by the prototype library
	 */
	create: function(nodeName /* obj attributes, str text */) {
		var node = document.createElement(nodeName);
		for (var i=1; i<arguments.length; i++) {
			if (typeof arguments[i] == 'string' && (arguments[i].indexOf('<') > -1 && (arguments[i].indexOf('</') > -1 || arguments[i].indexOf('/>') > -1))) {
				// HTML STRING
				node.innerHTML += arguments[i];
			} else if (typeof arguments[i] == 'string') {
				// STRING
				node.appendChild(this._text(arguments[i]));
			} else if (typeof arguments[i] == 'object' && typeof arguments[i].nodeName != 'undefined') {
				// NODE
				node.appendChild(arguments[i]);
			} else if (typeof arguments[i] == 'object' && typeof arguments[i].length != 'undefined') {
				// ARRAY OF NODES OR NODELIST
				for (var j=0; j<arguments[i].length; j++) {
					node.appendChild(arguments[i][j].cloneNode(true));
				}
			} else if (typeof arguments[i] == 'object') {
				// ATTRIBUTES
				this._attributes(node, arguments[i]);
			}
		}
		return node;
	},
	/**
	 * Cycles through the supplied attributes and applies them to the supplied element
	 * @param {DOMNode} node The node to apply attributes to
	 * @param {Object} attributes A JSON Object of attributes: {className:'myclass', id:'myID'}
	 * @return void
	 * WARNING: An attibute can NOT be named 'class', but must be 'className'
	 */
	_attributes: function(node, attributes) {
		for (var attr in attributes) {
			switch (true) {
				case (attr=='className'):
					node.className = attributes[attr];
					break;
				case (attr=='htmlFor'): // must pass htmlFor, as 'for' is a keyword
					node.htmlFor = attributes[attr];
					break;
				default:
					node.setAttribute(attr, attributes[attr]);
			}
		}
	},
	/**
	 * Creates and returns a text node with the supplied value
	 * @param {String} text
	 */
	_text: function(text) {
		return document.createTextNode(text);
	},
	
	/**
	 * Removes nodes from the DOM
	 * @param {String/Object} Elements The node you want to remove passed via Node OR ID string
	 * @return {Object/Array} The Element or an Array of Elements removed
	 * FIXME This method currently won't accept an Array of elements or element ID's
	 */
	remove: function(Elements) {
		var removed = new Array();
		for (var i=0; i<arguments.length; i++) {
			var el = (typeof arguments[i] == 'string') ? this.getById(arguments[i]) : arguments[i] ;
			removed.push(el.parentNode.removeChild(el));
		}
		return (removed.length > 1) ? removed : removed[0];
	},
	
	/**
	 * Gets the requested element(s).
	 * If you pass in a single string, returns FALSE on failure or the DOMNode
	 * on success. If you pass in many strings an Array of all found elements 
	 * is returned, which means an Empty array on failure
	 * @param {String} ElementIDs A comma-seperated list of element ID's
	 * @return Boolean/Array/DOMNode
	 */
	getById: function(ElementIDs) {
		var elements = new Array();
		var result;
		for (var i=0; i<arguments.length; i++) {
			var el;
			if (el = document.getElementById(arguments[i])) {
				elements.push(el);
			}
		}
		switch (true) {
			case (arguments.length == 1 && elements.length == 1):
				result = elements[0];
				break;
			case (arguments.length > 1):
				result = elements;
				break;
			default:
				result = false;
				break;
		}
		return result;
	},
	
	/**
	 * Returns an Array of all found elements by supplied tag name
	 * @param String ElementTagNames A comma seperated list of NodeNames
	 * @return Array An Array of all found elements. An empty Array on failure
	 */
	getByTag: function(ElementTagNames) {
		var elements = new Array();
		for (var i=0; i<arguments.length; i++) {
			els = document.getElementsByTagName(arguments[i]);
			for (var j=0; j<els.length; j++) {
				elements.push(els[j]);
			}
		}
		return elements;
	},
	
	/**
	 * Get all nodes with the given className
	 * @param String classNames A list of node.className(s) to check for
	 * @return An array of elements or an empty array on failure
	 */
	getByClass: function(classNames) {
		var o = new Array();
		var all = (typeof document.getElementsByTagName != 'undefined') ? document.getElementsByTagName('*') : document.all ;
		for (var i=0; i<all.length; i++) {
			(this.hasClass(all[i],arguments)) ? o.push(all[i]) : true ;
		}
		return o;
	},

	/**
	 * Add a class to an element
	 * @param Object node The element to work on
	 * @param String cls The class to add to the element
	 */
	addClass: function(node, cls) {
		var c = node.className.split(' ');
		(!c.contains(cls)) ? c.push(cls) : true ;
		node.className = c.join(' ');
	},

	/**
	 * Remove a class from an element
	 * @param Object node The element to work on
	 * @param String cls The class to remove from the element
	 */
	removeClass: function(node, cls) {
		var c = node.className.split(' ');
		(c.contains(cls)) ? c.remove(cls) : true ;
		node.className = c.join(' ');
	},
	
	/**
	 * Swap one class with another. If the first class doesn't exist the new 
	 * class is added.
	 * @param Object node The element to work on
	 * @param String sOldClass The class to swap out
	 * @param String sNewClass The class to swap in
	 */
	swapClass: function(node, sOldClass, sNewClass) {
		if (this.hasClass(node,sOldClass)) {
			this.removeClass(node, sOldClass);
		}
		this.addClass(node, sNewClass);
	},

	/**
	 * Check an element for the given className(s)
	 * @param {Object} node The node to check for a className
	 * @param {String} classNames A list of classNames to check for
	 * @return Boolean
	 */
	hasClass: function(node, classNames) {
		var args = arguments;
		var start = 1;
		if (typeof arguments[1] == 'object') {
			args = arguments[1];
			start = 0;
		}
		var success = false;
		for (var i=start; i<args.length; i++) {
			if (node.className.split(' ').contains(args[i])) {
				success = true;
				break;
			}
		}
		return success;
		// return (node.className.split(' ').contains(cls));
	},
	
	/**
	 * Gets a property from an elements computed style in a x-browser fashion
	 * @param DOMNode oNode The element to work on
	 * @param String sProperty The CSS property to find
	 */
	getComputedStyle: function(oNode, sProperty) {
		var computedStyle = null;
		if (typeof oNode.currentStyle != 'undefined') {
			computedStyle = oNode.currentStyle;
		} else {
			computedStyle = document.defaultView.getComputedStyle(oNode,null);
		}
		return computedStyle[sProperty];
	}
}

$dom = PopJavaScriptFramework.v1B1.dom;

