/* 
	ADDITIONAL (CORE) PROTOTYPE FUNCTIONALITY
	@requires: prototype.js
*/

/*
document.createElement convenience wrapper

The data parameter is an object that must have the "tag" key, containing
a string with the tagname of the element to create.  It can optionally have
a "children" key which can be: a string, "data" object, or an array of "data"
objects to append to this element as children.  Any other key is taken as an
attribute to be applied to this tag.

Release homepage:
http://www.arantius.com/article/dollar+e

Available under an MIT license:
http://www.opensource.org/licenses/mit-license.php

@param {Object} data The data representing the element to create
@return {Element} The element created.
*/
function $E(data) {
	var el;
	if ('string'==typeof data) {
		el=document.createTextNode(data);
	} else {
		//create the element
		el=document.createElement(data.tag);
		delete(data.tag);

		//append the children
		if ('undefined'!=typeof data.children) {
			if ('string'==typeof data.children ||
				'undefined'==typeof data.children.length
			) {
				//strings and single elements
				el.appendChild($E(data.children));
			} else {
				//arrays of elements
				for (var i=0, child=null; 'undefined'!=typeof (child=data.children[i]); i++) {
					el.appendChild($E(child));
				}
			}
			delete(data.children);
		}

		//any other data is attributes
		for (attr in data) {
			el[attr]=data[attr];
		}
	}

	return el;
}

/*
Extends Prototype functionality of String Object
*/
Object.extend(String.prototype, {

	stripTags : function(include) {
		//if include is provided (string or array), then strip tags only strips out the defined tags in include
		//todo: think of good (working) regex that would allow excluding tags
		var extra;

		if (include) {
		    if (typeof include == 'object' && include.constructor == Array) {
		        extra = include.join('|');
		    } else if (typeof include == 'string') {
				extra = include;
			}
		}
		return this.replace(new RegExp('(<\\/?' + (extra ? '\\b(' + extra + ')\\b' : '') + '[^>]*>)', 'gi'), '');
	},

	trim: function(nbsp) {
		// if nbsp is set (true), then also removes non-breaking spaces (&nbsp;)
		return this.replace(new RegExp('^[\s'+(nbsp?'\xA0':'')+']+', 'g'),'').replace(new RegExp('[\s'+(nbsp?'\xA0':'')+']+$', 'g'),'');
	}

});

/*
Enchancement to HTML DOM, returns a parent of the child element. If a targetType is specified, then it will return the first instance of the
specified element type (eg DIV), otherwise, it simply returns the direct parent. targetTag may be a single string (eg 'DIV'), or an array of
potential elements (eg ['DIV', 'SPAN']), in this case, the first element found in the array is returned.
*/
function getParent(child, targetTag) {
	// locates a specific parent node for a given child node... if no targetTag is given, simply return the direct parent node
	// targetTag can be either a string, or an array, if an array, as soon as a match occurs, the node is returned
	if (child == null) { return null; }

	if (typeof targetTag == 'object' && targetTag.constructor == Array) { //array
		targetTag = targetTag.join('|');
	} else if (typeof targetTag == 'object' && !targetTag) { //null
		return child.parentNode;
	}

	if (child.nodeType == 1 && child.tagName.match(new RegExp('^('+targetTag+')$','i'))) { return child; }
	else { return getParent(child.parentNode, targetTag); }
}

// extension to DOM elements and document with a helper function to allow multiple getElementsByTagName calls in one function
Object.extend(document, {
	getElementsByTagNames: function() {
		arguments = $A(arguments);
		var x = [];
		var targ = this == document ? document : arguments.shift();
		var len = arguments.length;
		for (var i = 0; i < len; i++) {
		    x += $A(targ.getElementsByTagName(arguments[i]));
		}
		return x;
	}
	/*getElementsByClassName: function() {
		arguments = $A(arguments);
		var targ = this == document ? document : arguments.shift();
		var className = arguments.shift();
		var children = (targ.getElementsByTagName('*'));
		var return_array = $A(children).inject([], function(elements, child) {
			if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) {
				elements.push(Element.extend(child));
			}	
			return elements;
		});
		return return_array[0] ? return_array : false;
	},*/

});

// extensions to Event class
Object.extend(Event, {
	relatedElement: function(event) { // returns the element that caused the event to fire instead of the element the event is attached to
		return event.relatedTarget || event.toElement
	}
});

Element.addMethods({
	getElementsByTagNames: document.getElementsByTagNames
//	getElementsByClassName: document.getElementsByClassName
});

if (typeof HTMLElement != 'undefined') {
	HTMLElement.prototype.contains = function(node) {
		if (node == null) {
			return false;
		} else if (node == this) {
			return true;
		} else if (node.ParentNode){
			return this.contains(node.parentNode);
		}
	}
}