/**
 * Webstores.js - Webstores javascript library
 * 
 * v1.2 - Added bind to try function binding
 * v1.1 - Added getChild, various tweaks
 * v1.0 - Initial version
 * 
 * @author  Webstores <info at webstores dot nl>
 *           Copyright (c) Webstores internet totaalbureau <http://www.webstores.nl/>
 */

/**
 * Returns an element
 * 
 * @param {Mixed} el The ID of or reference to an element
 * @return The reference to the element
 */
function $(el) {
	return (typeof el == 'string') ?
		document.getElementById(el) : el;
}

/**
 * Returns a child node at an arbitary depth
 * 
 * @param {Mixed} el The ID of or reference to an element
 * @param {Number} depth The depth of the child node to retrieve
 */
function getChild(el, depth) {
	var child = $(el).childNodes[depth-1];
	while(child.nodeType != 1)
		child = child.nextSibling;
	return child;
}

/**
 * Hides an element
 * 
 * @param {Mixed} el The ID of or reference to an element
 */
function hide(el) {
	var el = $(el);
	el.style.display = 'none';
}

/**
 * Shows a hidden element
 * 
 * @param {Mixed} el The ID of or reference to an element
 */
function show(el) {
	el = $(el);
	el.style.display = '';
}

/**
 * Toggles an element's display property
 * 
 * @param {Mixed} el The ID of or reference to an element
 */
function toggle(el) {
	el = $(el);
	el.style.display == '' ?
		hide(el) : show(el);
}

/**
 * Set the text of an element
 * 
 * @param {Mixed} el The ID of or reference to an element
 * @param {String} text The element's new text
 */
function setText(el, text) {
	el = $(el);
	el.innerHTML = text;
}

/**
 * Creates a toggler/container pair
 * 
 * @param {String} id The ID of the elements
 */
function createToggle(id) {
	var t = $(id + '-toggle');
	var c = $(id);
	
	addEvent(t, 'click', function(e) {
		stopEvent(e);
		toggle(c);
		activeOptCt = c;
	});
}

/**
 * Check if an element has a class name
 * 
 * @param {Mixed} el The ID of or reference to an element
 * @param {String} cls The class name to check
 */
function hasClass(el, cls) {
	el = $(el);
	return el.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}

/**
 * Add a class name to an element
 * 
 * @param {Mixed} el The ID of or reference to an element
 * @param {String} cls The class name to add
 */
function addClass(el, cls) {
	el = $(el);
	if(!hasClass(el, cls))
		el.className += (' ' + cls);
}

/**
 * Remove a class name from an element
 * 
 * @param {Mixed} el The ID of or reference to an element
 * @param {String} cls The class name to remove
 */
function removeClass(el, cls) {
	el = $(el);
	if(hasClass(el, cls)) {
		var regex = new RegExp('(\\s|^)'+cls+'(\\s|$)');
		el.className = el.className.replace(regex, ' ');
	}
}

/**
 * Toggle between a class name
 * 
 * @param {Mixed} el The ID of or reference to an element
 * @param {String} cls The class name to toggle
 */
function toggleClass(el, cls) {
	if(hasClass(el, cls))
		removeClass(el, cls);
	else
		addClass(el, cls);
}

/**
 * Cross browser function to ADD an event listener to an element
 * 
 * @param {Mixed} el The ID of or reference to an element to add the event to
 * @param {String} type The event type, eg. 'click' or 'focus'
 * @param {Function} listener The function to execute when the event fires
 * @param {Boolean} useCapture (optional) Whether to use event capturing, or event bubbling (default).
 */
function addEvent(el, type, listener, useCapture) {
	var el = $(el);
	var self = this;
	useCapture = useCapture || false;
	
	if(el.addEventListener) {
		el.addEventListener(type, listener, useCapture);
	}
	else if(el.attachEvent) {
		var r = el.attachEvent('on' + type, function() {
			listener.call(el, window.event);
		});
		return r;
	}
}

/**
 * Cross browser function to REMOVE an event listener from an element
 * 
 * @param {Mixed} el The ID of or reference to an element to remove the event from
 * @param {String} type The event type being removed, eg. 'click' or 'focus'
 * @param {Function} listener The EventListener function to be removed
 * @param {Boolean} useCapture (optional)
 */
function removeEvent(el, type, listener, useCapture) {
	useCapture = useCapture || false;
	
	if(el.removeEventListener) {
		el.removeEventListener(type, listener, useCapture);
	}
	else if(el.detachEvent) {
		var r = el.detachEvent('on' + type, listener);
	}
}

/**
 * Cross browser function to stop the default event behavior
 * 
 * @param {Object} e The event object to stop
 */
function stopEvent(e) {
	e = e || window.event;
	
	if(e.preventDefault)
		e.preventDefault();
	else
		e.returnValue = false;
}

/**
 * Hides and reveals default input value
 * 
 * @param {String} id The ID of the search input
 * @param {String} fCls The input focus class
 */
function toggleValue(id, fCls) {
	var el = document.getElementById(id);
	var v = el.value;
	
	el.onfocus = function() {
		if(this.value == v)
			this.value = '';
		this.className = fCls;
	}
	el.onblur = function() {
		if(this.value == '')
			this.value = v;
		this.className = '';
	}
}

function collectionToArray(c) {
	var a = [];
	for(var i = 0; i < c.length; i++) {
		a.push(c.item(i));
	}
	return a;
}

if(!Array.indexOf){Array.prototype.indexOf=function(obj){for(var i=0;i<this.length;i++){if(this[i]==obj){return i;}}return-1;};}
Array.prototype.first=function(){return this[0];};
Array.prototype.last=function(){return this[this.length-1];};


/**
 * THIRD PARTY FUNCTIONS
 * ---------------------
 */

/**
 * Dustin Diaz's implementation of getElementsByClass
 * 
 * @param {String} searchClass Class name as a string
 * @param {Object} node (optional) Supply a node (default: document)
 * @param {Object} tag (optional) Limit the results by adding a tagName (default: *)
 * 
 * @see http://www.dustindiaz.com/getelementsbyclass/
 */
function getElementsByClass(searchClass, node, tag) {
	var classElements = new Array();
	if(node == null)
		node = document;
	if(tag == null)
		tag = '*';
	var els = node.getElementsByTagName(tag);
	var elsLen = els.length;
	var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	for(i = 0, j = 0; i < elsLen; i++) {
		if(pattern.test(els[i].className)) {
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
}

/**
 * Binds a function call to a specific scope
 */
Function.prototype.bind = function() {
	var handler = this, args = Array.slice(arguments, 0), obj = args.shift();
	
	return function() {
		return handler.apply(obj, args.concat(Array.slice(arguments, 0)));
	}
}
