/** 
 * @fileoverview
 * @author			Michael Ord <michael.ord@think.eu>
 * @version			0.1
 * @class
 * @requires		YAHOO.util.Dom
 * @requires		YAHOO.util.Event
 * 
 * @file			init.js
 * @description		
 */

/**
 * Toggles the class of elements either on or off
 * @method toggleClass
 * @param {String | HTMLElement | Array} el The element or collection to test
 * @param {String} className the class name to search for
*/
YAHOO.util.Dom.toggleClass = function (el, className) {
	if (YAHOO.util.Dom.hasClass (el, className)) {
		YAHOO.util.Dom.removeClass (el, className);
	} else {
		YAHOO.util.Dom.addClass (el, className);
	};
};

/**
 * TODO Description
 * @method getAncestorsByClassName
 * @param {Object} obj
 * @param {Object} className
 * @param {Object} tag
 */
YAHOO.util.Dom.getAncestorsByClass = function (obj, className, tag, iterations, findFirst) {

	className	= className		|| false;
	tag			= tag			|| false;
	obj			= YAHOO.util.Dom.get (obj);

	if (!obj) {
		return false;
	};

	// an array to store the ancestors/parent nodes that match the className
	var ancestors	= new Array;
	// start with the parent of the object
	var parent		= obj.parentNode;
	// set a maximum number or parent nodes to look through - may be removed
	var iteration	= iterations || 20;
	// loop backwards through the DOM
	while (parent && iteration--){
		// if the element has a matching class, add it to the array
		if (YAHOO.util.Dom.hasClass (parent, className) || !className){
			if (!tag || (tag && parent.nodeName.toLowerCase () == tag)){
				ancestors.push (parent);
				if (findFirst) {
					return parent;
				};
			};
		};
		// move on to the next parent
		parent	= parent.parentNode;
	};
	// return the list
	return ancestors.length ? ancestors : false;
};

/**
 * TODO Description
 * @method getElementsBySelector
 * @param {Object} selector
 */
YAHOO.util.Dom.getElementsBySelector = function (selector) {

	if (!document.getElementsByTagName){
		return new Array;
	};

	var getAllChildren = function (e)	{
		return e.all ? e.all : e.getElementsByTagName ('*');
	};

	// Split selector in to tokens
	var tokens			= selector.split (' ');
	var currentContext	= new Array (document);

	for (var i = 0; i < tokens.length; i++) {

		token	= tokens [ i ].replace (/^\s+/,'').replace (/\s+$/, '');

		if (token.indexOf ('#') > -1) {

			// Token is an ID selector
			var bits	= token.split ('#');
			var tagName	= bits [ 0 ];
			var id		= bits [ 1 ];
			var element	= YAHOO.util.Dom.get(id);

			if ( !element ) {
				return new Array;// tag with that ID not found, return false
			}

			if (tagName && element.nodeName.toLowerCase() != tagName) {
				return new Array;// tag with that ID not found, return false
			};
			// Set currentContext to contain just this element
			currentContext	= new Array (element);

			continue; // Skip to next token
		};

		if (token.indexOf ('.') > -1) {

			// Token contains a class selector
			var bits		= token.split('.');
			var tagName		= bits[0];
			var className	= bits[1];

			if (!tagName) {
				tagName		= '*';
			};

			// Get elements matching tag, filter them for class selector
			var found		= new Array;
			var foundCount	= 0;

			for (var h = 0; h < currentContext.length; h++) {

				var elements	= tagName == '*' ? getAllChildren (currentContext [ h ]) : currentContext [ h ].getElementsByTagName (tagName);

				for (var j = 0; j < elements.length; j++) {
					found [ foundCount++ ]	= elements [ j ];
				};
			};

			currentContext			= new Array;
			var currentContextIndex	= 0;

			for (var k = 0; k < found.length; k++) {

				if (found [ k ].className && found [ k ].className.match (new RegExp ('\\b' + className + '\\b'))) {
					currentContext [ currentContextIndex++ ] = found [ k ];
				};
			};
			continue; // Skip to next token
		};
		// Code to deal with attribute selectors
		if (token.match (/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {

			var tagName			= RegExp.$1;
			var attrName		= RegExp.$2;
			var attrOperator	= RegExp.$3;
			var attrValue		= RegExp.$4;

			if (!tagName) {
				tagName	= '*';
			};

			// Grab all of the tagName elements within current context
			var found		= new Array;
			var foundCount	= 0;
			var elements;

			for (var h = 0; h < currentContext.length; h++) {

				if (tagName == '*') {
					elements	= getAllChildren (currentContext [ h ]);
				} else {
					elements	= currentContext [ h ].getElementsByTagName (tagName);
				};

				for (var j = 0; j < elements.length; j++) {
					found [ foundCount++ ]	= elements [ j ];
				};
			};

			currentContext			= new Array;
			var currentContextIndex	= 0;

			var checkFunction; // This function will be used to filter the elements

			switch (attrOperator) {

				case '=': // Equality
					checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
					break;
				case '~': // Mach one of space seperated words
					checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
					break;
				case '|': // Match start with value followed by optional hyphen
					checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
					break;
				case '^': // Match starts with value
					checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
					break;
				case '$': // Match ends with value - fails with "Warning" in Opera 7
					checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
					break;
				case '*': // Match ends with value
					checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
					break;
				default :
					// Just test for existence of attribute
					checkFunction = function(e) { return e.getAttribute(attrName); };
			};

			currentContext		= new Array;
			var currentContextIndex	= 0;
			for (var k = 0; k < found.length; k++) {
				if (checkFunction (found [ k ])) {
					currentontext [ currentContextIndex++ ]	= found [ k ];
				};
			};
			continue; // Skip to next token
		};

		if (!currentContext [ 0 ]) {
			return;
		};

		// If we get here, token is JUST an element (not a class or ID selector)
		tagName			= token;
		var found		= new Array;
		var foundCount	= 0;

		for (var h = 0; h < currentContext.length; h++) {

			var elements	= currentContext [ h ].getElementsByTagName (tagName);

			for (var j = 0; j < elements.length; j++)	{
				found [ foundCount++ ]	= elements [ j ];
			};
		};

		currentContext	= found;
	};
	return currentContext;
};