/**
 * Utility methods
 *
 * @category	HTML
 * @package	Ajax
 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
 *
 * See Main.js for author/license details
 */
// {{{ HTML_AJAX_Util
/**
 * All the utilities we will be using thorough the classes
 */
var HTML_AJAX_Util = {
	// Set the element event
	registerEvent: function(element, event, handler) 
	{
		element = this.getElement(element);
		if (typeof element.addEventListener != "undefined") {   //Dom2
			element.addEventListener(event, handler, false);
		} else if (typeof element.attachEvent != "undefined") { //IE 5+
			element.attachEvent("on" + event, handler);
		} else {
			if (element["on" + event] != null) {
				var oldHandler = element["on" + event];
				element["on" + event] = function(e) {
					oldHander(e);
					handler(e);
				};
			} else {
				element["on" + event] = handler;
			}
		}
	},
	// get the target of an event, automatically checks window.event for ie
	eventTarget: function(event) 
	{
		if (!event) var event = window.event;
		if (event.target) return event.target; // w3c
		if (event.srcElement) return event.srcElement; // ie 5
	},
	// gets the type of a variable or its primitive equivalent as a string
	getType: function(inp) 
	{
		var type = typeof inp, match;
		if(type == 'object' && !inp)
		{
			return 'null';
		}
		if (type == "object") {
			if(!inp.constructor)
			{
				return 'object';
			}
			var cons = inp.constructor.toString();
			if (match = cons.match(/(\w+)\(/)) {
				cons = match[1].toLowerCase();
			}
			var types = ["boolean", "number", "string", "array"];
			for (key in types) {
				if (cons == types[key]) {
					type = types[key];
					break;
				}
			}
		}
		return type;
	},
	// repeats the input string the number of times given by multiplier. exactly like PHP's str_repeat()
	strRepeat: function(inp, multiplier) {
		var ret = "";
		while (--multiplier > 0) ret += inp;
		return ret;
	},
	// encode a string allowing it to be used in a query string of a url
	encodeUrl: function(input) {
		return encodeURIComponent(input);
	},
	// decode a url encoded string
	decodeUrl: function(input) {
		return decodeURIComponent(input);
	},
	// recursive variable dumper similar in output to PHP's var_dump(), the differences being: this function displays JS types and type names; JS doesn't provide an object number like PHP does
	varDump: function(inp, printFuncs, _indent, _recursionLevel)
	{
		if (!_recursionLevel) _recursionLevel = 0;
		if (!_indent) _indent = 1;
		var tab = this.strRepeat("  ", ++_indent);	
		var type = this.getType(inp), out = type;
		var consrx = /(\w+)\(/;
		consrx.compile();
		if (++_recursionLevel > 6) {
			return tab + inp + "Loop Detected\n";
		}
		switch (type) {
			case "boolean":
			case "number":
				out += "(" + inp.toString() + ")";
				break;
			case "string":
				out += "(" + inp.length + ") \"" + inp + "\"";
				break;
			case "function":
				if (printFuncs) {
					out += inp.toString().replace(/\n/g, "\n" + tab);
				}
				break;
			case "array":
			case "object":
				var atts = "", attc = 0;
				try {
					for (k in inp) {
						atts += tab + "[" + (/\D/.test(k) ? "\"" + k + "\"" : k)
							+ "]=>\n" + tab + this.varDump(inp[k], printFuncs, _indent, _recursionLevel);
						++attc;
					}
				} catch (e) {}
				if (type == "object") {
					var objname, objstr = inp.toString();
					if (objname = objstr.match(/^\[object (\w+)\]$/)) {
						objname = objname[1];
					} else {
						try {
							objname = inp.constructor.toString().match(consrx)[1];
						} catch (e) {
							objname = 'unknown';
						}
					}
					out += "(" + objname + ") ";
				}
				out += "(" + attc + ") {\n" + atts + this.strRepeat("  ", _indent - 1) +"}";
				break;
		}
		return out + "\n";
	},
	// non resursive simple debug printer
	quickPrint: function(input,sep) {
		if (!sep) {
			var sep = "\n";
		}
		var type = HTML_AJAX_Util.getType(input);
		switch (type) {
			case 'string':
				return input;
			case 'array':
				var ret = "";
				for(var i = 0; i < input.length; i++) {
					ret += i+':'+input[i]+sep;
				}
				return ret;
			default:
				var ret = "";
				for(var i in input) {
					ret += i+':'+input[i]+sep;
				}
				return ret;
		}
	},
	//compat function for stupid browsers in which getElementsByTag with a * dunna work
	getAllElements: function(parentElement)
	{
		//check for idiot browsers
		if( document.all)
		{
			if(!parentElement) {
				var allElements = document.all;
			}
			else
			{
				var allElements = [], rightName = new RegExp( parentElement, 'i' ), i;
				for( i=0; i<document.all.length; i++ ) {
					if( rightName.test( document.all[i].parentElement ) )
					allElements.push( document.all[i] );
				}
			}
			return allElements;
		}
		//real browsers just do this
		else
		{
			if (!parentElement) { parentElement = document.body; }
			return parentElement.getElementsByTagName('*');
		}
	},
	getElementsByProperty: function(property, regex, parentElement) {
		var allElements = HTML_AJAX_Util.getAllElements(parentElement);
		var items = [];
		for(var i=0,j=allElements.length; i<j; i++)
		{
			if(regex.test(allElements[i][property]))
			{
				items.push(allElements[i]);
			}
		}
		return items;
	},
	getElementsByClassName: function(className, parentElement) {
		return HTML_AJAX_Util.getElementsByProperty('className',new RegExp('(^| )' + className + '( |$)'),parentElement);
	},
	getElementsById: function(id, parentElement) {
		return HTML_AJAX_Util.getElementsByProperty('id',new RegExp(id),parentElement);
	},
	getElementsByCssSelector: function(selector,parentElement) {
		return cssQuery(selector,parentElement);
	},
	htmlEscape: function(inp) {
		var div = document.createElement('div');
		var text = document.createTextNode(inp);
		div.appendChild(text);
		return div.innerHTML;
	},
	// return the base of the given absolute url, or the filename if the second argument is true
	baseURL: function(absolute, filename) {
		var qPos = absolute.indexOf('?');
		if (qPos >= 0) {
			absolute = absolute.substr(0, qPos);
		}
		var slashPos = Math.max(absolute.lastIndexOf('/'), absolute.lastIndexOf('\\'));
		if (slashPos < 0) {
			return absolute;
		}
		return (filename ? absolute.substr(slashPos + 1) : absolute.substr(0, slashPos + 1));
	},
	// return the query string from a url
	queryString: function(url) {
		var qPos = url.indexOf('?');
		if (qPos >= 0) {
			return url.substr(qPos+1);
		}
	},
	// return the absolute path to the given relative url
	absoluteURL: function(rel, absolute) {
		if (/^https?:\/\//i.test(rel)) {
			return rel;
		}
		if (!absolute) {
			var bases = document.getElementsByTagName('base');
			for (i in bases) {
				if (bases[i].href) {
					absolute = bases[i].href;
					break;
				}
			}
			if (!absolute) {
				absolute = window.location.href;
			}
		}
		if (rel == '') {
			return absolute;
		}
		if (rel.substr(0, 2) == '//') {
			// starts with '//', replace everything but the protocol
			var slashesPos = absolute.indexOf('//');
			if (slashesPos < 0) {
				return 'http:' + rel;
			}
			return absolute.substr(0, slashesPos) + rel;
		}
		var base = this.baseURL(absolute);
		var absParts = base.substr(0, base.length - 1).split('/');
		var absHost = absParts.slice(0, 3).join('/') + '/';
		if (rel.substr(0, 1) == '/') {
			// starts with '/', append it to the host
			return absHost + rel;
		}
		if (rel.substr(0, 1) == '.' && rel.substr(1, 1) != '.') {
			// starts with '.', append it to the base
			return base + rel.substr(1);
		}
		// remove everything upto the path and beyond 
		absParts.splice(0, 3);
		var relParts = rel.split('/');
		var loopStart = relParts.length - 1;
		relParts = absParts.concat(relParts);
		for (i = loopStart; i < relParts.length;) {
			if (relParts[i] == '..') {
				if (i == 0) {
					return absolute;
				}
				relParts.splice(i - 1, 2);
				--i;
				continue;
			}
			i++;
		}
		return absHost + relParts.join('/');
	},
	// sets the innerHTML of an element. the third param decides how to write, it replaces by default, others are append|prepend
	setInnerHTML: function(node, innerHTML, type)
	{
		node = this.getElement(node);

		if (type != 'append') {
			if (type == 'prepend') {
				var oldHtml = node.innerHTML;
			}
			node.innerHTML = '';
		}
		var good_browser = (window.opera || navigator.product == 'Gecko');
		var regex = /^([\s\S]*?)<script([\s\S]*?)>([\s\S]*?)<\/script>([\s\S]*)$/i;
		var regex_src = /src=["'](.*?)["']/i;
		var matches, id, script, output = '', subject = innerHTML;
		var scripts = [];

		while (true) {
			matches = regex.exec(subject);
			if (matches && matches[0]) {
				subject = matches[4];
				id = 'ih_' + Math.round(Math.random()*9999) + '_' + Math.round(Math.random()*9999);

				var startLen = matches[3].length;
				script = matches[3].replace(/document\.write\(([\s\S]*?)\)/ig, 
					'document.getElementById("' + id + '").innerHTML+=$1');

				output += matches[1];
				if (startLen != script.length) {
						output += '<span id="' + id + '"></span>';
				}
				
				output += '<script' + matches[2] + '>' + script + '</script>';
				if (good_browser) {
					continue;
				}
				if (script) {
					scripts.push(script);
				}
				if (regex_src.test(matches[2])) {
					var script_el = document.createElement("SCRIPT");
					var atts_regex = /(\w+)=["'](.*?)["']([\s\S]*)$/;
					var atts = matches[2];
					for (var i = 0; i < 5; i++) { 
						var atts_matches = atts_regex.exec(atts);
						if (atts_matches && atts_matches[0]) {
							script_el.setAttribute(atts_matches[1], atts_matches[2]);
							atts = atts_matches[3];
						} else {
							break;
						}
					}
					scripts.push(script_el);
				}
			} else {
				output += subject;
				break;
			}
		}
		innerHTML = output;

		if (good_browser) {
			var el = document.createElement('span');
			el.innerHTML = innerHTML;

			for(var i = 0; i < el.childNodes.length; i++) {
				node.appendChild(el.childNodes[i].cloneNode(true));
			}
		}
		else {
			node.innerHTML += innerHTML;
		}

		if (oldHtml) {
			node.innerHTML += oldHtml;
		}

		if (!good_browser) {
			for(var i = 0; i < scripts.length; i++) {
				if (HTML_AJAX_Util.getType(scripts[i]) == 'string') {
					scripts[i] = scripts[i].replace(/^\s*<!(\[CDATA\[|--)|((\/\/)?--|\]\])>\s*$/g, '');
					window.eval(scripts[i]);
				}
				else {
					node.appendChild(scripts[i]);
				}
			}
		}
		return;
	},
	classSep: '(^|$| )',
	hasClass: function(o, className) {
		var o = this.getElement(o);
		var regex = new RegExp(this.classSep + className + this.classSep);
		return regex.test(o.className);
	},
	addClass: function(o, className) {
		var o = this.getElement(o);
		if(!this.hasClass(o, className)) {
			o.className += " " + className;
		}
	},
	removeClass: function(o, className) {
		var o = this.getElement(o);
		var regex = new RegExp(this.classSep + className + this.classSep);
		o.className = o.className.replace(regex, " ");
	},
	replaceClass: function(o, oldClass, newClass) {
		var o = this.getElement(o);
		var regex = new RegExp(this.classSep + oldClass + this.classSep);
		o.className = o.className.replace(regex, newClass);
	},
	getElement: function(el) {
		if (typeof el == 'string') {
			return document.getElementById(el);
		}
		return el;
	}
}
// }}}
