/**
 * This file must be included to support chainability. When an element is made chainable, the given element supports a lot of
 * handy functions.
 * 
 * @version 2011-01-27
 * @author <a href="mailto:r.tennapel@griponservice.nl?SUBJECT=chainability.js">R. ten Napel, ing.</a>
 **/

/**
 * Wrap element(s) in a chainable class. You can parse arrays, elements and element ID's as parameters.
 * 
 * @param els				The element(s) (ID('s)) to make chainable.
 * @param ...				More elements to make chainable.
 * 
 * @return					The chainable element wrapper.
 **/
function _$(els) {
	this.elements = [];
	
	// Add all elements to the global element array:
	for (var i = 0; i < els.length; i++) {
		var element = els[i];
		
		// Check type of the element(s) and add to array:
		if (GlobalKit.isArray(element)) {
			for (var e = 0; e < element.length; e++) {
				this.addElement(element[e]);
			}
		} else if (typeof element == "string") {
			this.addElement(document.getElementById(element));
		} else {
			this.addElement(element);
		}
	}
	
	return this;
}

/**
 * Retrieve a single element from the elements list.
 * 
 * @param index				The index of the element to retrieve.
 * 
 * @return					The corresponding element.
 **/
_$.prototype.$ = function(index) {
	// Set to 0 if no index is given:
	if (index == null) {
		index = 0;
	}
	
	return this.elements[index];
};

/**
 * Add an element to the wrapper.
 * 
 * @param element			The element to add to the chainable wrapper.
 * 
 * @return					This wrapper.
 **/
_$.prototype.addElement = function(element) {
	if (element != null) {
		// Add tween array for storing animations internally:
		if (!element.tweens) {
			element.tweens = [];
		}
		
		this.elements.push(element);
	}
	
	return this;
};

/**
 * Apply a function to each element in this wrapper.
 * 
 * @param func				The function to apply.
 * 
 * @return					This wrapper.
 **/
_$.prototype.each = function(func) {
	for (var i = 0, len = this.elements.length; i < len; ++i) {
		func.call(this, this.elements[i]);
	}
	
	return this;
};

/**
 * Shows an alert message generated by this wrapper for each element.
 * 
 * @param message			The message to show.
 * 
 * @return					This wrapper.
 **/
_$.prototype.alert = function(message) {
	this.each(function(element) {
		alert("Element '" + element.id + "' alerts: " + message);
	});
	
	return this;
};

/**
 * Calls the debugger to show a debug message.
 * 
 * @param value				The value to debug.
 * @param ...				More values to debug.
 * 
 * @return					This wrapper.
 **/
_$.prototype.debug = function(value) {
	var args = arguments;
	
	// Iterate through each element:
	this.each(function(element) {
		var values = [];
		
		// Add text:
		values.push("<b>Element '<em>" + element.id + "</em>' debug:</b>");
		
		// When no value is given use the element:
		for (var i = 0; i < args.length; i++) {
			if (args[i] == null) {
				values.push(element);
			} else {
				values.push(args[i]);
			}
		}
		
		// Write to the debugger:
		try {
			Debugger.write.apply(Debugger, values).show();
		} catch(e) {
			$(element).alert("'" + e.name + "' in '_$.prototype.debug': " + e.message);
		}
	});
	
	return this;
};

/**
 * Remove the element's from the DOM.
 * 
 * @return					This wrapper.
 **/
_$.prototype.destroy = function() {
	this.each(function(element) {
		if (typeof element.destroy != "undefined") {
			element.destroy(element);
		} else {
			element.parentNode.removeChild(element);
		}
	});
};

/**
 * Change the inner HTML of the elements to the given HTML code.
 * 
 * @param html				The HTML to give each element.
 * 
 * @return					This wrapper.
 **/
_$.prototype.update = function(html) {
	this.each(function(element) {
		if (typeof element.update != "undefined") {
			element.update(html);
		} else {
			element.innerHTML = html;
		}
	});
	
	return this;
};

/**
 * Append new HTML code to the existing HTML of each element.
 * 
 * @param html				The HTML code to append to each element.
 * 
 * @return					This wrapper.
 **/
_$.prototype.append = function(html) {
	this.each(function(element) {
		if (typeof element.append != "undefined") {
			element.append(html);
		} else {
			element.innerHTML += html;
		}
	});
	
	return this;
};

/**
 * Prepend new HTML code to the existing HTML of each element.
 * 
 * @param html				The HTML code to prepend to each element.
 * 
 * @return					This wrapper.
 **/
_$.prototype.prepend = function(html) {
	this.each(function(element) {
		if (typeof element.prepend != "undefined") {
			element.prepend(html);
		} else {
			element.innerHTML = html + element.innerHTML;
		}
	});
	
	return this;
};

/**
 * Set the style of each element.
 * 
 * @param property			The property style to set.
 * @param value				The value of the property to set.
 * 
 * @return					This wrapper.
 **/
_$.prototype.setStyle = function(property, value) {
	//alert(value);
	this.each(function(element) {
		// Check if opacity or transparency:
		if (property == "opacity") {
			return this.setOpacity(value);
		} else if (property == "transparency") {
			return this.setTransparency(value);
		}
		
		// Set the style:
		try {
			element.style[property] = value;
		} catch(e) {
			this.debug("Error in '_$.prototype.setStyle': " + e.message, element);
			
			return "";
		}
	});
	
	return this;
};

/**
 * Set the title of each element.
 * 
 * @param title				The title to set.
 * 
 * @return					This wrapper.
 **/
_$.prototype.setTitle = function(title) {
	this.each(function(element) {
		// Use the function of the element if exists:
		if (typeof element.setTitle != "undefined") {
			element.setTitle(title);
		} else {
			element.title = title;
		}
	});
	
	return this;
};

/**
 * Retrieve all input values, defined by tag name, of each element in the mode that is set.
 * 
 * @param tagName			The tag name to search for.
 * @param mode				The mode to retrieve the values (object, URL or JSON).
 * @param values			The object to append the values to.
 * 
 * @return					The object with param / values or the string (if stringify is set).
 **/
_$.prototype.getValues = function(tagName, mode, values) {
	var values = {};
	
	this.each(function(element) {
		values = GlobalKit.getValues(element, tagName, "OBJ", values);
	});
	
	// Convert to the requested mode:
	var element = document.createElement("DIV");
	values = GlobalKit.getValues(element, tagName, mode, values);
	
	return values;
};

/**
 * Retrieve the position of the first element.
 * 
 * @return					The x & y value of the element's position.
 **/
_$.prototype.getPos = function() {
	var curLeft = curTop = 0;
	var obj = this.elements[0];
	
	// No pos when no object:
	if (obj == null) {
		return {x: 0, y: 0, x2: 0, y2: 0 };
	}
	
	// Iterate through all the element's parents:
	if (obj.offsetParent) {
		do {
			curLeft += obj.offsetLeft;
			curTop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	
	return { x: curLeft, y: curTop };
};

/**
 * Set the position of the elements. You may alternatively give an object with an X & Y coördinate instead of
 * especifying the coördinates seperately as arguments.
 * 
 * @param x					The X-coördinate (in pixels).
 * @param y					The Y-coördinate (in pixels).
 **/
_$.prototype.setPos = function(x, y) {
	var x = arguments[0];
	var y = arguments[1];
	
	// If the argument is a pos object, use it's coördinates:
	if (x && x.x) {
		y = x.y;
		x = x.x;
	}
	
	// Ensure null values if null:
	x = x ? x + "px" : null;
	y = y ? y + "px" : null;
	
	this.each(function(element) {
		this.setStyle("left", x).setStyle("top", y);
	});
	
	return this;
};

/**
 * Retrieve the 4 coördinates of the first element with the width & height included.
 * <b>Warning! This function ONLY works in IE when the CSS-position is set to absolute!</b>
 * 
 * @return					The x, y, x2, y2, width & height of the first element.
 **/
_$.prototype.getBox = function() {
	var curLeft = curTop = curWidth = curHeight = 0;
	var obj = this.elements[0];
	
	// Retrieve the element's dimensions:
	curWidth = obj.offsetWidth;
	curHeight = obj.offsetHeight;
	
	// Iterate through all the element's parents:
	if (obj.offsetParent) {
		do {
			curLeft += obj.offsetLeft;
			curTop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	
	return { x: curLeft, y: curTop, x2: curLeft + curWidth, y2: curTop + curHeight, w: curWidth, h: curHeight };
};

/**
 * Check if the elements are children of the given parent. If all are, true will be returned. If one ore all is not, false will be returned.
 * 
 * @param parent			The element to check if parent.
 * 
 * @return					If all elements are children of the given parent.
 **/
_$.prototype.childOf = function(parent) {
	var allFound = true;
	
	this.each(function(element) {
		var found = false;
		
		do {
			found = (element.parentNode == parent);
		} while (!found && (element = element.parentNode));
		
		// Check result with global result:
		allFound = allFound & found;
	});
	
	return allFound;
};

/**
 * Retrieve the style property value of the first element.
 * 
 * @param property			The property style to get.
 * 
 * @return					This wrapper.
 **/
_$.prototype.getStyle = function(property) {
	var style;
	
	// Try to get the property value:
	try {
		var style = this.elements[0].style[property];
	} catch(e) {
		this.debug("Error in '_$.prototype.setStyle': " + e.message, element);
		
		return "";
	}
	
	return style;
};

/**
 * Checks if all the elements have the given class name.
 * 
 * @param className			The class name to check for.
 * 
 * @return					This wrapper.
 **/
_$.prototype.hasClass = function(className) {
	var match = true;
	
	this.each(function(element) {
		if (!element.className.match(new RegExp("(\\s|^)" + className + "(\\s|$)"))) {
			match = false;
		}
	});
	
	return match;
};

/**
 * Add a class name to each element.
 * 
 * @param className			The class name to add.
 * 
 * @return					This wrapper.
 **/
_$.prototype.addClass = function(className) {
	this.each(function(element) {
		// Check if the class isn't already added to the element:
		if (!$(element).hasClass(className)) {
			element.className += " " + className;
		}
	});
	
	return this;
};

/**
 * Remove a class name from each element.
 * 
 * @param className			The class name to remove.
 * 
 * @return					This wrapper.
 **/
_$.prototype.removeClass = function(className) {
	this.each(function(element) {
		// Check if element contains the given class:
		if ($(element).hasClass(className)) {
			var reg = new RegExp("(\\s|^)" + className + "(\\s|$)");
			
			element.className = element.className.replace(reg, " ");
		}
	});
	
	return this;
};

/**
 * Toggle the given class of each element.
 * 
 * @param className			The class name to toggle.
 * 
 * @return					This wrapper.
 **/
_$.prototype.toggleClass = function(className) {
	this.each(function(element) {
		// Check if element contains the given class:
		if ($(element).hasClass(className)) {
			$(element).removeClass(className);
		} else {
			$(element).addClass(className);
		}
	});
	
	return this;
};

/**
 * Add an array of CSS properties with values to the elements (p.h. "$('id').css({left: '300px', top: '100px', backgroundColor: '#ff00ff'});
 * 
 * @param properties		An array of properties to set to the elements.
 * 
 * @return					This wrapper.
 **/
_$.prototype.css = function(properties) {
	var that = this;
	
	for (var property in properties) {
		that.setStyle(property, properties[property]);
	}
	
	return this;
};

/**
 * Set the font color of the elements.
 * 
 * @param color				The color to set.
 * 
 * @return					This wrapper.
 **/
_$.prototype.setColor = function(color) {
	return this.setStyle("color", color);
};

/**
 * Set the background color of the elements.
 * 
 * @param color				The color to set.
 * 
 * @return					This wrapper.
 **/
_$.prototype.setBColor = function(color) {
	return this.setStyle("backgroundColor", color);
};

/**
 * Set the visibility of each element to show. When an internal "show"-function exists, that one will be called instead.
 * 
 * @return					This wrapper.
 **/
_$.prototype.show = function() {
	this.each(function(element) {
		// Use the function of the element if exists:
		if (typeof element.show != "undefined") {
			element.show();
		} else {
			element.style["display"] = "block";
			element.style["visibility"] = "visible";
		}
	});
	
	return this;
};

/**
 * Set the visibility of each element to hide. When an internal "hide"-function exists, that one will be called instead.
 * 
 * @return					This wrapper.
 **/
_$.prototype.hide = function() {
	this.each(function(element) {
		// Use the function of the element if exists:
		if (typeof element.hide != "undefined") {
			element.hide();
		} else {
			element.style["display"] = "none";
			element.style["visibility"] = "hidden";
		}
	});
	
	return this;
};

/**
 * Toggle the visibility of each element.
 * 
 * @return					This wrapper.
 **/
_$.prototype.toggle = function() {
	this.each(function(element) {
		// Detect the current visibility state:
		if (element.style["display"] == "" && element.style["visibility"] == "") {
			$(element).hide();
		} else if (element.style["display"] == "none" || element.style["visibility"] == "hidden") {
			$(element).show();
		} else if (element.style["display"] == "block" || element.style["visibility"] == "visible") {
			$(element).hide();
		}
	});
	
	return this;
};


_$.prototype.slideOut = function() {
	this.each(function(element) {
		var iput = document.getElementById(element.id + 'offset').value;
		var height = ((iput.length >0)? iput : element.offsetHeight );
		if (iput.length == 0) { 		
			document.getElementById(element.id + 'offset').value = element.offsetHeight 
		}
		//alert (height);
		$(element).setStyle('height','0px');
		$(element).setStyle('visibility','visible');		
		var tween =  new Tween(document.getElementById(element.id), 'height', 0, height, 'px', 400,Tween.linair,40);
		tween.start();
		
		//tween.stop();
	
	});
	
}
_$.prototype.slideIn = function() {
	this.each(function(element) {
	
		var height = element.offsetHeight;
		//alert (height);			
		var tween =  new Tween(document.getElementById(element.id), 'height', height, 0, 'px', 400,Tween.linair,40);
		tween.start();
		
		setTimeout(function (e){ $(element).setStyle('visibility','hidden'); },500);	
		//tween.stop();
	
	});
	
}

_$.prototype.slideToggle = function() {
	this.each(function(element) {
	
		if (element.style.visibility != 'visible' ){
		
			$(element).slideOut();
			
		}
		else {
			$(element).slideIn();
			
			
		}
				
	});
	
}

/**
 * Add a handler to the elements.
 * 
 * @param type				The event type (mouseover, mouseout, mousedown, blur, submit, ...).
 * @param func				The handler to call for each event.
 * 
 * @return					This wrapper.
 **/
_$.prototype.on = function(type, func) {
	var listen = function(element) {
		if (window.addEventListener) {
			element.addEventListener(type, func, false);
		} else if (window.attachEvent) {
			element.attachEvent("on" + type, function() {
				func.call(element, window.event);
			});
		}
	};
	
	this.each(function(element) {
		listen(element);
	});
	
	return this;
};

/**
 * Alternative call to "on".
 * 
 * @param type				The event type (mouseover, mouseout, mousedown, blur, submit, ...).
 * @param func				The handler to call for each event.
 * 
 * @return					This wrapper.
 **/
_$.prototype.addEvent = function(type, func) {
	return this.on(type, func);
};

/**
 * Do an AJAX request for the elements.
 * 
 * @param url				The URL of the document to parse into the elements.
 * @param callBack			The callback function to process after the request has finished.
 * @param onLoad			Called before the actual request.
 * @param onSuccess			Called when the request was successfull.
 * @param onFailure			Called when the request has failed.
 * @param async				If the Ajax request should be asynchronous or not.
 * 
 * @return					This wrapper.
 **/
_$.prototype.request = function(url, callBack, onLoad, onSuccess, onFailure, async) {
	// Request all:
	this.each(function(element) {
		// Create the Ajax object:
		element.ajax = ajax = new Ajax(element, url, callBack, onLoad, onSuccess, onFailure, async);
		
		// Store the Ajax object in it's parent node:
		//element.ajax = ajax;
		
		// Do the request:
		element.ajax.request();
	});
	
	return this;
};

_$.prototype.refresh = function() {
	// Request all:
	this.each(function(element) {
		//if (element.parentNode.ajax) {
			element.ajax.request();
		//} else {
		//	$(element).alert("Cannot refresh element '" + element.id + "': No Ajax object stored in the element's parent node!");
		//}
	});
	
	return this;
};

/**
 * Set the opacity of the elements.
 * 
 * @param percentage		The opacity percentage.
 * 
 * @return					This wrapper.
 **/
_$.prototype.setOpacity = function(percentage) {
	// Set minimum to 0 %:
	if (percentage < 0) {
		percentage = 0;
	}
	
	// Set maximum to 100 %:
	if (percentage > 100) {
		percentage = 100;
	}
	
	// Set all:
	this.each(function(element) {
		// Set the transparency:
		if (percentage == 100) {
			element.style.opacity = "1.0";
		} else {
			// Add a 0 in front of the percentage when < 10:
			if (percentage < 10) {
				percentage = "0" + percentage;
			}
			
			element.style.opacity = "0." + percentage;
		}
		
		// Set the IE transparency:
		if (element.style) {
			element.style["filter"] = "alpha(opacity=" + percentage + ");";
		}
	});
	
	return this;
};

/**
 * Set the transparency of the elements.
 * 
 * @param percentage		The transparency percentage.
 * 
 * @return					This wrapper.
 **/
_$.prototype.setTransparency = function(percentage) {
	return this.setOpacity(100 - percentage);
};

/**
 * Stop all animations.
 * 
 * @return					This wrapper.
 **/
_$.prototype.stopTweens = function() {
	this.each(function(element) {
		// Stop all tweens:
		for (var i = 0; i < element.tweens.length; i++) {
			element.tweens[i].stop();
		}
		
		// Clear all tweens:
		element.tweens.clear();
	});
	
	return this;
};

/**
 * Move element(s) horizontally from 1 position to another.
 * 
 * @param from				The X-position to move from.
 * @param to				The X-position to move to.
 * @param duration			The duration in milliseconds for the move (total time it will take to move).
 * @param type				The animation type to use.
 * @param fps				The number of frames per second.
 * @param suffix			The suffix to use, default is in pixels.
 * 
 * @return					This wrapper.
 **/
_$.prototype.moveX = function(fromX, toX, duration, type, fps, suffix) {
	// Return if fromX or toX is not set:
	if (fromX == null || toX == null) {
		return this;
	// Ensure integers:
	} else {
		fromX = parseInt(fromX);
		toX = parseInt(toX);
		fps = parseInt(fps);
	}
	
	// Set time to 3s if null:
	if (duration == null) {
		duration = 3000;
	} else {
		duration = parseInt(duration);
	}
	
	// Set suffix to pixels if null:
	if (suffix == null) {
		suffix = "px";
	}
	
	// Move all:
	this.each(function(element) {
		// Create the animation and store it:
		var tween = new Tween(element, "left", fromX, toX, suffix, duration, type, fps);
		element.tweens.add(tween);
		
		// Start the animation:
		tween.start();
	});
	
	return this;
};

/**
 * Move this element vertically from 1 position to another.
 * 
 * @param from				The Y-position to move from.
 * @param to				The Y-position to move to.
 * @param duration			The duration in milliseconds for the move (total time it will take to move).
 * @param type				The animation type to use.
 * @param fps				The number of frames per second.
 * @param suffix			The suffix to use, default is in pixels.
 * 
 * @return					This wrapper.
 **/
_$.prototype.moveY = function(fromY, toY, duration, type, fps, suffix) {
	// Return if fromY or toY is not set:
	if (fromY == null || toY == null) {
		return this;
	// Ensure integers:
	} else {
		fromY = parseInt(fromY);
		toY = parseInt(toY);
		fps = parseInt(fps);
	}
	
	// Set time to 3s if null:
	if (duration == null) {
		duration = 3000;
	} else {
		duration = parseInt(duration);
	}
	
	// Set suffix to pixels if null:
	if (suffix == null) {
		suffix = "px";
	}
	
	// Move all:
	this.each(function(element) {
		// Create the animation and store it:
		var tween = new Tween(element, "top", fromY, toY, suffix, duration, type, fps);
		element.tweens.add(tween);
		
		// Start the animation:
		tween.start();
	});
	
	return this;
};

/**
 * Move this element from 1 position to another.
 * 
 * @param fromX				The X-position to move from.
 * @param fromY				The Y-position to move from.
 * @param toX				The X-position to move to.
 * @param toY				The Y-position to move to.
 * @param duration			The duration in milliseconds for the move (total time it will take to move).
 * @param type				The animation type to use.
 * @param fps				The number of frames per second.
 * @param suffix			The suffix to use, default is in pixels.
 * 
 * @return					This wrapper.
 **/
_$.prototype.move = function(fromX, fromY, toX, toY, duration, type, fps, suffix) {
	this.moveX(fromX, toX, duration, type, fps, suffix);
	this.moveY(fromY, toY, duration, type, fps, suffix);
	
	return this;
};

/**
 * Move this element from the current position to another.
 * 
 * @param toX				The X-position to move to.
 * @param toY				The Y-position to move to.
 * @param duration			The duration in milliseconds for the move (total time it will take to move).
 * @param type				The animation type to use.
 * @param fps				The number of frames per second.
 * 
 * @return					This wrapper.
 **/
_$.prototype.moveTo = function(toX, toY, duration, type, fps) {
	this.each(function(element) {
		// Retrieve the current position:
		var fromX = parseInt($(element).getStyle("left").replace("px", "").replace("%", ""));
		var fromY = parseInt($(element).getStyle("top").replace("px", "").replace("%", ""));
		
		// Retrieve the used suffixes:
		var suffixX = element.style["left"].contains("%") ? "%" : "px";
		var suffixY = element.style["top"].contains("%") ? "%" : "px";
		
		// Move this element:
		$(element).moveX(fromX, toX, duration, type, fps, suffixX);
		$(element).moveY(fromY, toY, duration, type, fps, suffixY);
	});
	
	return this;
};

/**
 * Fade an element from one transparency level to another.
 * 
 * @param from				The initiate transparency level.
 * @param to				The end transparency level.
 * @param duration			The duration in milliseconds for the fading (total time it will take to fade).
 * @param type				The animation type to use for fading.
 * @param fps				The number of frames per second.
 * 
 * @return					This wrapper.
 **/
_$.prototype.fade = function(from, to, duration, type, fps) {
	// Set from to 0 if null:
	if (from == null) {
		from = 0;
	} else {
		from = parseInt(from);
	}
	
	// Set to to 100 if null:
	if (to == null) {
		to = 100;
	} else {
		to = parseInt(to);
	}
	
	// Set duration to 3s if null:
	if (duration == null) {
		duration = 3000;
	} else {
		duration = parseInt(duration);
	}
	
	// Set the animation type if null:
	if (type == null) {
		type = Tween.linear;
	}
	
	// Ensure the FPS is an integer:
	fps = parseInt(fps);
	
	// Fade all:
	this.each(function(element) {
		// Create the animation and store it:
		var tween = new Tween(element, "transparency", from, to, null, duration, type, fps);
		element.tweens.add(tween);
		
		// Start the animation:
		tween.start();
	});
	
	return this;
};

/**
 * Fade an element to a transparency level.
 * 
 * @param to				The end transparency level.
 * @param duration			The duration in milliseconds for the fading (total time it will take to fade).
 * @param type				The animation type to use for fading.
 * @param fps				The number of frames per second.
 * 
 * @return					This wrapper.
 **/
_$.prototype.fadeTo = function(to, duration, type, fps) {
	return this.alert("function 'fadeTo' not yet implemented!");
};

/**
 * Fade an element from a color to a color.
 * 
 * @param from				The original color.
 * @param to				The destination color.
 * @param duration			The duration in milliseconds for the fading (total time it will take to fade).
 * @param type				The animation type to use for fading.
 * @param fps				The number of frames per second.
 * 
 * @return					This wrapper.
 **/
_$.prototype.colorFade = function(from, to, duration, type, fps) {
	// Remove the #-sign when exists:
	from = from.replace("#", "");
	to = to.replace("#", "");
	
	// Set duration to 3s if null:
	if (duration == null) {
		duration = 3000;
	} else {
		duration = parseInt(duration);
	}
	
	// Set the animation type if null:
	if (type == null) {
		type = Tween.linear;
	}
	
	// Ensure the FPS is an integer:
	fps = parseInt(fps);
	
	// Fade all:
	this.each(function(element) {
		// Create the animation and store it:
		var tween = new Tween(element, "backgroundColor", from, to, null, duration, type, fps);
		element.tweens.add(tween);
		
		// Start the animation:
		tween.start();
	});
	
	return this;
};

/**
 * Fade an elements background color to a new color.
 * 
 * @param to				The destination color.
 * @param duration			The duration in milliseconds for the fading (total time it will take to fade).
 * @param type				The animation type to use for fading.
 * @param fps				The number of frames per second.
 * 
 * @return					This wrapper.
 **/
_$.prototype.colorFadeTo = function(to, duration, type, fps) {
	this.each(function(element) {
		// Retrieve the current background color:
		var from = element.style["backgroundColor"];
		
		// Change the from value if necessary:
		if (from == "") {
			from = "#ffffff";
		// When using Chrome / FireFox the backgroundColor is in string format (p.h. "rgb(32, 23, 133)") and should be converted:
		} else if (from.indexOf("rgb") != -1) {
			from = GlobalKit.rgb2h(from);
		}
		
		$(element).colorFade(from, to, duration, type, fps);
	});
	
	return this;
};

/**
 * Resize an element to a certain size from a certain size.
 * 
 * @param fromWidth			The initial width of the element.
 * @param toWidth			The ending width of the element.
 * @param duration			The duration in milliseconds for resizing (total time the resize takes).
 * @param type				The animation type to use for resizing.
 * @param fps				The number of frames per second.
 * @param suffix			The suffix to use, default is in pixels.
 * 
 * @return					This wrapper.
 **/
_$.prototype.resizeWidth = function(fromWidth, toWidth, duration, type, fps, suffix) {
	// Ensure size is integer:
	fromWidth = parseInt(fromWidth);
	toWidth = parseInt(toWidth);
	
	// Set duration to 3s if null:
	if (duration == null) {
		duration = 3000;
	} else {
		duration = parseInt(duration);
	}
	
	// Set the animation type if null:
	if (type == null) {
		type = Tween.linear;
	}
	
	// Ensure the FPS is an integer:
	if (fps == null) {
		fps = 30;
	} else {
		fps = parseInt(fps);
	}
	
	// Set suffix to pixels if null:
	if (suffix == null) {
		suffix = "px";
	}
	
	// Fade all:
	this.each(function(element) {
		// Create the animation and store it:
		var tween = new Tween(element, "width", fromWidth, toWidth, suffix, duration, type, fps);
		element.tweens.add(tween);
		
		// Start the animation:
		tween.start();
	});
	
	return this;
};

/**
 * Resize an element to a certain size from a certain size.
 * 
 * @param fromHeight		The initial height of the element.
 * @param toHeight			The ending height of the element.
 * @param duration			The duration in milliseconds for resizing (total time the resize takes).
 * @param type				The animation type to use for resizing.
 * @param fps				The number of frames per second.
 * @param suffix			The suffix to use, default is in pixels.
 * 
 * @return					This wrapper.
 **/
_$.prototype.resizeHeight = function(fromHeight, toHeight, duration, type, fps, suffix) {
	// Ensure size is integer:
	fromHeight = parseInt(fromHeight);
	toHeight = parseInt(toHeight);
	
	// Set duration to 3s if null:
	if (duration == null) {
		duration = 3000;
	} else {
		duration = parseInt(duration);
	}
	
	// Set the animation type if null:
	if (type == null) {
		type = Tween.linear;
	}
	
	// Ensure the FPS is an integer:
	if (fps == null) {
		fps = 30;
	} else {
		fps = parseInt(fps);
	}
	
	// Set suffix to pixels if null:
	if (suffix == null) {
		suffix = "px";
	}
	
	// Fade all:
	this.each(function(element) {
		// Create the animation and store it:
		var tween = new Tween(element, "height", fromHeight, toHeight, suffix, duration, type, fps);
		element.tweens.add(tween);
		
		// Start the animation:
		tween.start();
	});
	
	return this;
};

/**
 * Resize an element to a certain size from a certain size.
 * 
 * @param fromWidth			The initial width of the element.
 * @param fromHeight		The initial height of the element.
 * @param toWidth			The ending width of the element.
 * @param toHeight			The ending height of the element.
 * @param duration			The duration in milliseconds for resizing (total time the resize takes).
 * @param type				The animation type to use for resizing.
 * @param fps				The number of frames per second.
 * @param suffix			The suffix to use, default is in pixels.
 * 
 * @return					This wrapper.
 **/
_$.prototype.resize = function(fromWidth, fromHeight, toWidth, toHeight, duration, type, fps, suffix) {
	this.resizeWidth(fromWidth, toWidth, duration, type, fps, suffix);
	this.resizeHeight(fromHeight, toHeight, duration, type, fps, suffix);
	
	return this;
};

/**
 * Resize an element to a certain size.
 * 
 * @param toWidth			The ending width of the element.
 * @param toHeight			The ending height of the element.
 * @param duration			The duration in milliseconds for resizing (total time the resize takes).
 * @param type				The animation type to use for resizing.
 * @param fps				The number of frames per second.
 * 
 * @return					This wrapper.
 **/
_$.prototype.resizeTo = function(toWidth, toHeight, duration, type, fps) {
	this.each(function(element) {
		// Retrieve the current size:
		var fromWidth = parseInt($(element).getStyle("width").replace("px", "").replace("%", ""));
		var fromHeight = parseInt($(element).getStyle("height").replace("px", "").replace("%", ""));
		
		// Retrieve the used suffixes:
		var suffixWidth = $(element).getStyle("width").contains("%") ? "%" : "px";
		var suffixHeight = $(element).getStyle("height").contains("%") ? "%" : "px";
		
		// Resize this element (if not NULL):
		if (toWidth != null) { $(element).resizeWidth(fromWidth, toWidth, duration, type, fps, suffixWidth); }
		if (toHeight != null) { $(element).resizeHeight(fromHeight, toHeight, duration, type, fps, suffixHeight); }
	});
	
	return this;
};

/**
 * Returns the tag values of all the tags below this element and submits them to the given URL in an AJAX request.
 * 
 * @param url				The URL of the document to parse into this element.
 * @param form				The form which holds the variables to send with the url.
 * @param callBack			The callback function to process after the request has finished.
 * @param onLoad			Called before the actual request.
 * @param onSuccess			Called when the request was successfull.
 * @param onFailure			Called when the request has failed.
 * @param async				If the Ajax request should be asynchronous or not.
 * 
 * @return					This wrapper.
 **/
_$.prototype.submit = function(url, form, callBack, onLoad, onSuccess, onFailure, async) {
	// Define the default form:
	if (form == null) {
		form = this.elements[0];
	}
	
	// Send the request:
	url += url.contains("?") ? "&" : "?";
	return this.request(url + GlobalKit.getValues(form, "ALL", "URL"), callBack, onLoad, onSuccess, onFailure, async);
};

/**
 * Load a widget into this element.
 * 
 * @param widgetName		The name of the widget to load.
 * @param parameters		The widget parameters.
 * @param callBack			The callBack function.
 * @param onLoad			The handler that handles stuff before the widget request.
 * @param onSuccess			The handler that handles stuff after the widget request.
 * @param onFailure			The handler that handles stuff when a widget request failes.
 * 
 * @return					This wrapper.
 **/
_$.prototype.loadWidget = function(widgetName, parameters, callBack, onLoad, onSuccess, onFailure) {
	this.each(function(element) {
		Widget.load(element, widgetName, parameters, callBack, onLoad, onSuccess, onFailure);
	});
	
	return this;
};

/**
 * Make element(s) draggable.
 * 
 * @param dropObjects		The drop object where the element(s) may be dropped in.
 * @param graspHandler		The handler that is called when the element(s) is / are clicked on for dragging.
 * @param dragHandler		The handler that is called when the element(s) is / are being dragged.
 * @param releaseHandler	The handler that is called when the dragged element(s) is / are being released.
 * 
 * @return					This wrapper.
 **/
_$.prototype.makeDraggable = function(dropObjects, graspHandler, dragHandler, releaseHandler) {
	this.each(function(element) {
		// Use the function of the element if exists:
		if (typeof element.makeDraggable != "undefined") {
			element.makeDraggable(dropObjects, graspHandler, dragHandler, releaseHandler);
		} else {
			Dragdropper.makeDraggable(element, dropObjects, graspHandler, dragHandler, releaseHandler);
		}
	});
	
	return this;
};

/**
 * Make element(s) droppable. You can drop draggable elements into these.
 * 
 * @param dragObjects		The drag object(s) which may be dropped into this element.
 * @param dropHandler		The handler that is called when the drag object(s) is / are dropped into this element.
 * 
 * @return					This wrapper.
 **/
_$.prototype.makeDroppable = function(dragObjects, dropHandler) {
	this.each(function(element) {
		Dragdropper.makeDroppable(element, dragObjects, dropHandler);
	});
	
	return this;
};

/**
 * Register drag objects for each element. You may give multiple parameters in the form: element ID, element, array of drag objects or a drag object.
 * 
 * @param dragObjects		A drag object (or array, ID, element).
 * @param ...				More drag objects.
 * 
 * @return					This wrapper.
 **/
_$.prototype.registerDragObject = function(dragObjects) {
	// Initiate the drag objects array:
	var draggables = [];
	
	// Check each argument:
	for (var i = 0; i < arguments.length; i++) {
		var arg = arguments[i];
		
		// Detect array (assume all drag objects:
		if (GlobalKit.isArray(arg)) {
			draggables.merge(arg);
		// Detect Drag Object:
		} else if (arg instanceof DragObject) {
			draggables.add(arg);
		// Detect String & assume element ID:
		} else if (typeof(arg) == "string") {
			var dragObject = Dragdropper.getDragObject(document.getElementById(arg));
			
			// Only if not NULL:
			if (dragObject != null) {
				draggables.add(dragObject);
			}
		// Else assume element:
		} else {
			var dragObject = Dragdropper.getDragObject(arg);
			
			// Only if not NULL:
			if (dragObject != null) {
				draggables.add(dragObject);
			}
		}
	}
	
	this.each(function(element) {
		// Retrieve the drop object:
		var dropper = Dragdropper.getDropObject(element);
		
		// Register all drag objects if not NULL or show debug message:
		if (dropper != null) {
			// Register each drag object:
			for (var i = 0; i < draggables.length; i++) {
				dropper.registerDragObject(draggables[i]);
			}
		} else {
			$(element).debug("This element cannot register drag object because it's not droppable!");
		}
	});
	
	return this;
};

/**
 * Make element(s) resizable.
 * 
 * @return					This wrapper.
 **/
_$.prototype.makeResizable = function() {
	this.each(function(element) {
		Dragdropper.makeResizable(element);
	});
	
	return this;
};

/**
 * Attach a menu to this element.
 * 
 * @param menu				The menu to attach.
 * 
 * @return					This wrapper.
 **/
_$.prototype.attachMenu = function(menu) {
	return this.alert("function 'attachMenu' not yet implemented!");
};

/**
 * Disable selection of an element.
 * 
 * @return					This wrapper.
 */
_$.prototype.noSelect = function() {
	this.each(function(element) {
		// IE route:
		if (typeof element.onselectstart != "undefined") {
			element.onselectstart = function() {
				return false;
			};
		// Firefox route:
		} else if (typeof element.style.MozUserSelect != "undefined") {
			element.style.MozUserSelect = "none";
		// All other route (ie: Opera):
		} else {
			element.onmousedown = function() {
				return false;
			};
			
			element.style.cursor = "default";
		}
	});
	
	return this;
};

/**
 * Add chainability to the given elements. The given arguments may be arrays, elements, ID's or a mix of them.
 * 
 * @param els			The element to make chainable.
 * @param ...			Additional elements, element ID('s) and array('s) to make chainable.
 * 
 * @return				The chainable element(s).
 **/
window.$ = function() {
	return new _$(arguments);
};

/**
 * Retrieve the element(s) by name(s).
 * 
 * @param ...			The name(s) of the element(s) to retrieve.
 * 
 * @return				The chainable element(s).
 **/
window.$$ = function() {
	var elements = [];
	
	// Get all elements by name:
	for (var i = 0; i < arguments.length; i++) {
		var name = arguments[i];
		
		elements.merge(document.getElementsByName(name));
	}
	
	return elements;
};

/**
 * Retrieve the element(s) by class name(s).
 * 
 * @param ...			The class name(s) of the element(s) to retrieve.
 * 
 * @return				The chainable element(s).
 **/
window.$$$ = function() {
	var elements = [];
	
	// Get all elements by class name:
	for (var i = 0; i < arguments.length; i++) {
		var className = arguments[i];
		
		elements.merge(document.getElementsByClassName(className));
	}
	
	return elements;
};
