// +---------------------------------------------------------------------------+
// | This file is part of a Sisali project.                                    |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * Extends the native element in order to add the container properties. The
 * container is basically the reference of the class which is holding an
 * element.
 * @package core
 * @subpackage element
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
Element.implement({

	/**
	 * Set the id of an element. This method is simply a shortcut to the common
	 * set property method allready in place.
	 * @param string The id.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	setId : function(id) {
		this.set('id', id);
	},

	/**
	 * Return the id of an element. This method is simply a shortcut to the common
	 * get property method allready in place.
	 * @return string The id.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getId : function() {
		return this.get('id');
	},
	
	/**
	 * Return the text of an element.
	 * @return string The text.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getText : function() {
		return this.get('text');
	},
	
	/**
	 * Return the inside html of an element.
	 * @return array The html.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getHtml : function() {
		return this.get('html');
	},

	/**
	 * Show teh current element.
	 * @param string The display mode.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	show : function(method) { 
		this.setStyle('display', method === undefined ? 'inline' : method); 
	},
	
	/**
	 * Hide teh current element.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	hide : function() { 
		this.setStyle('display', 'none'); 
	}
});// +---------------------------------------------------------------------------+
// | This file is part of a Sisali project.                                    |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * SisaliElement is a class which is used to handle an element inside another class.
 * This class will mostly be implemented inside other classes.
 * @package core
 * @subpackage element
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var SisaliElement = new Class({

	/**
	 * @var object The element object.
	 */
	el : null,
	
	/**
	 * Assign or retrieve the element of the class.
	 * @param object The element.
	 * @return object The element.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	element : function(el) {
		if (el == undefined) return this.el;
		this.el = $(el);
	},

	/**
	 * Gets the first descendant element whose tag name matches the tag 
	 * provided. If Selectors is included, CSS selectors may also be passed.
	 * @param string Tag name of the element to find.
	 * @return object The element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getElement : function(tag) {
		return this.el.getElement(tag);
	},
	
	/**
	 * Collects all decedent elements whose tag name matches the tag provided. 
	 * If Selectors is included, CSS selectors may also be passed.
	 * @param string Tag name of the element to find.
	 * @return array An Elements array of all matched Elements.	
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getElements : function(tag) {
		return this.el.getElements(tag);
	},
	
	/**
	 * Gets the element with the specified id found inside the current Element.
	 * @param string The ID of the Element to find.
	 * @return mixed If a match is found, returns that Element otherwise null.	
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getElementById : function(id) {
		return this.el.getElementById(id);
	},
	
	/**
	 * This is a "dynamic arguments" method. Properties passed in can be any of 
	 * the 'set' properties in the Element.Properties Hash.
	 * @param mixed Two Arguments (property, value)
	 * @return object Thsi element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	set : function(property, value) {
		return this.el.set(property, value);
	},
	
	/**
	 * This is a dynamic arguments method. Properties passed in can be any of 
	 * the 'get' properties in the Element.Properties Hash.
	 * @param string The string key representing the property to get.
	 * @return mixed The result of calling the corresponding 'get'.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	get : function(property) {
		return this.el.get(property);
	},
	
	/**
	 * This is a dynamic arguments method. Properties passed in can be any of 
	 * the 'erase' properties in the Element.Properties Hash.
	 * @param string The string key representing the property to erase.
	 * @return mixed The result of calling the corresponding 'erase' function.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	erase : function(property) {
		return this.el.earse(property);
	},
	
	/**
	 * Tests this Element to see if its tag name is the same as the tag passed 
	 * in. If Selectors is included, CSS selectors may also be passed.
	 * @param string The tag name to test against this element.
	 * @return bool If the element has the specified tag name otherwise false.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */ 
	match : function(tag) {
		return this.el.match(tag);
	},
	
	/**
	 * Injects, or inserts, the Element at a particular place relative to the 
	 * Element's children (specified by the second the argument).
	 * @param mixed El can be the id of an element or an element.
	 * @param string Can be top, bottom, after, or before.
	 * @return object This Element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */ 
	inject : function(el, where) {
		return this.el.inject(el, where);
	},
	
	/**
	 * Works as Element:inject, but in reverse. Appends the Element at a 
	 * particular place relative to the Element's children.
	 * @param object The element.
	 * @param string Can be top or bottom.
	 * @return object This Element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */ 
	grab : function(el, where) {
		return this.el.grab(el, where);
	},
	
	/**
	 * Works like Element:grab, but allows multiple elements to be adopted.
	 * @param object The element.
	 * @return object This Element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	adopt : function(el) {
		return this.el.adopt(el);
	},
	
	/**
	 * Works like Element:grab, but instead of moving the grabbed element from 
	 * its place, this method moves this Element around its target.
	 * @param object The element.
	 * @return object This Element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	wraps : function(el) {
		return this.el.wraps(el);
	},
	
	/**
	 * Works like Element:grab except it inject a text node.
	 * @param string The text to append.
     * @param string The position to inject the text to.
	 * @return object This elemenet.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	appendText : function(text, where) {
		return this.el.appendText(text, where);
	},
	
	/**
	 * Removes the Element from the DOM.
	 * @return object This Element useful to always grab the return.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	dispose : function() {
		return this.el.dispose();
	},
	
	/**
	 * Clones the Element and returns the cloned one.
	 * @param bool When true the Element is cloned with childNodes, default true.
	 * @return object The element clone.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	clone : function(contents) {
		return this.el.clone(contents);
	},
	
	/**
	 * Replaces the Element with an Element passed.
	 * @param mixed The element.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	replaces : function(el) {
		return this.el.replaces(el);
	},
	
	/**
	 * Tests the Element to see if it has the passed in className.
	 * @param string The class name to test.
	 * @return bool Returns true if the Element has the class, otherwise false.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	hasClass : function(className) {
		return this.el.hasClass(className);
	},
	
	/**
	 * Adds the passed in class if the element doesnt alreadyhave it.
	 * @param string The class name.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	addClass : function(className) {
		return this.el.addClass(className);
	},

	/**
	 * Works like SisaliElement.addClass, but removes the class from the element.
	 * @param string The class name.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	removeClass : function(className) {
		return this.el.removeClass(className);
	},
	
	/**
	 * Adds or removes the passed in class name to the element.
	 * @param string The class name.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	toggleClass : function(className) {
		return this.el.toggleClass(className);
	},
	
	/**
	 * Returns the previousSibling of the Element.
	 * @param string A tag name to match the the found element(s) with.
	 * @return object The previous sibling.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getPrevious : function(match) {
		return this.el.getPrevious(match);
	},
	
	/**
	 * Returns a collection of all the matched previousSiblings.
	 * @param string A tag name to match the the found element(s) with.
	 * @return array The previous siblings.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getAllPrevious : function(match) {
		return this.el.getAllPrevious(match);
	},
	
	/**
	 * Returns the nextSibling of the Element.
	 * @param string A tag name to match the the found element(s) with.
	 * @return object The next sibling.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getNext : function(match) {
		return this.el.getNext(match);
	},
	
	/**
	 * Returns a collection of all the matched nextSiblings.
	 * @param string A tag name to match the the found element(s) with.
	 * @return array The next siblings.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getAllNext : function(match) {
		return this.el.getAllNext(match);
	},
	
	/**
	 * Works as SisaliElement.getPrevious, but tries to find the firstChild.
	 * @param string A tag name to match the the found element(s) with.
	 * @return object The first child.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getFirst : function(match) {
		return this.el.getFirst(match);
	},
	
	/**
	 * Works as SisaliElement.getPrevious, but tries to find the lastChild.
	 * @param string A tag name to match the the found element(s) with.
	 * @return object The last child.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getLast : function(match) {
		return this.el.getLast(match);
	},
	
	/**
	 * Works as Element:getPrevious, but tries to find the parentNode.
	 * @param string A tag name to match the the found element(s) with.
	 * @return object The parent node.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getParent : function(match) {
		return this.el.getParent(match);
	},
	
	/**
	 * Returns a collection of all the matched parentNodes up the tree.
	 * @param string A tag name to match the the found element(s) with.
	 * @return object The parent node.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getParents : function(match) {
		return this.el.getParents(match);
	},
	
	/**
	 * Returns all the Element's children.
	 * @param string A tag name to match the the found element(s) with.
	 * @return array All the elements.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getChildren : function(match) {
		return this.el.getChildren(match);
	},
	
	/**
	 * Checks all descendants of this Element for a match.
	 * @param object Can be a Element reference or string id.
	 * @return bool True if the element has the child.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	hasChild : function(child) {
		return this.el.hasChild(child);
	},
	
	/**
	 * Empties an element of all its children.
	 * @return object This Element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	empty : function() {
		return this.el.empty();
	},
	
	/**
	 * Empties an Element of all its children, removes and garbages the Element. 
	 * Useful to clear memory before the pageUnload.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	destroy : function() {
		this.el.destroy();
	},
	
	/**
	 * Reads the children inputs of the Element and generates a query string 
	 * based on their values.
	 * @return string A string representation of a all the input.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	toQueryString : function() {
		return this.el.toQueryString();
	},
	
	/**
	 * Sets an attribute for the Element.
	 * @param string The property to assign the value passed in.
	 * @param string The value to assign to the property passed in.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	setProperty : function(property, value) {
		return this.el.setProperty(property, value);
	},
	
	/**
	 * Gets the an attribute of the Element.
	 * @param string The attribute to retrieve.
	 * @return string The property.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getProperty : function(property) {
		return this.el.getProperty(property);
	},
	
	/**
	 * Removes an attribute from the Element.
	 * @param strin The attribute to remove.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	removeProperty : function(property) {
		return this.el.removeProperty(property);
	},
	
	/**
	 * Sets numerous attributes for the Element.
	 * @param object The attributes.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	setProperties : function(source) {
		return this.el.setProperties(source);
	},
	
	/**
	 * Same as SisaliElement.getStyles, but for properties.
	 * @return object The properties.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getProperties : function() {
		return this.el.getProperties();
	},
	
	/**
	 * Sets a css property to the Element.
	 * @param string The style name.
	 * @param string The style value.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	setStyle : function(property, value) {
		return this.el.setStyle(property, value);
	},
	
	/**
	 * Returns the style of the Element given the property passed in.
	 * @param string The css style property you want to retrieve.
	 * @return string The style.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getStyle : function(property) {
		return this.el.getStyle();
	},
	
	/**
	 * Sets the opacity of the Element, and sets also visibility == "hidden" if 
	 * opacity == 0, and visibility = "visible" if opacity > 0.
	 * @param float Accepts values from 0 to 1.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	setOpacity : function(opacity) {
		return this.el.setOpacity(opacity);
	},
	
	/**
	 * Applies a collection of styles to the Element.
	 * @param object The different styles.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	setStyles : function(source) {
		return this.el.setStyles(source);
	},
	
	/**
	 * Returns an object of styles of the Element for each argument passed in.
	 * @return object The styles.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getStyles : function() {
		return this.el.getStyles();
	},
	
	/**
	 * Sets the innerHTML of the Element.
	 * @param string The html.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	setHtml : function(html) {
		return this.set('html', html);
	},
	
	/**
	 * Return the innerHTML of the Element.
	 * @return object The html.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getHtml : function() {
		this.get('html');
	},
		
	/**
	 * Sets the inner text of the Element
	 * @param string The inner text.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	setText : function(text) {
		return this.set('text', text);
	},
	
	/**
	 * Gets the inner text of the Element
	 * @return string The inner text.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	getText : function() {
		return this.get('text');
	},
	
	/**
	 * Returns the tagName of the element in lower case.
	 * @return string The tag name.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getTag : function() {
		return this.get('tag');
	},
	
	/**
	 * Attaches an event listener to a DOM element
	 * @param string The event to monitor.
	 * @param function The function.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	addEvent : function(type, fn) {
		return this.el.addEvent(type, fn);
	},

	/**
	 * Works as Element.addEvent, but instead removes the previously added event listener.
	 * @param string The event to monitor.
	 * @param function The function.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	removeEvent : function(type, fn) {
		return this.el.removeEvent(type, fn);
	},

	/**
	 * As addEvent, but accepts an object and add multiple events at once.
	 * @param string The event to monitor.
	 * @param function The function.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	addEvents : function(source) {
		return this.el.addEvents(source);
	},

	/**
	 * Removes all events of a certain type from an element.
	 * @param string The event to remove.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	removeEvents : function(type) {
		return this.removeEvents(type);
	},
	
	/**
	 * Executes all events of the specified type present in the element.
	 * @param string The event name.
	 * @param mixed	Arguments to pass to the function.
	 * @param int Delay in ms to wait to execute the event.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	fireEvent : function(type, args, delay) {
		return this.el.fireEvent(type, args, delay);
	},
	
	/**
	 * Clones all events from an element to this element.
	 * @param object Copy all events from this element.
	 * @param string optional, copies only events of this type
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	cloneEvents : function(from, type) {
		return this.el.cloneEvents(from, type);
	},
	
	/**
	 * Show the element by setting the display style.
	 * @param string The display mode.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	show : function(as) {
		return this.el.show(as);
	},
	
	/**
	 * Hide the element by setting the display style.
	 * @return object This element.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	hide : function() {
		return this.el.hide();
	}
});// +---------------------------------------------------------------------------+
// | This file is part of a Sisali project.                                    |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * SisaliSelector is a mootools implementation of the original event selector.
 * This been ported to mootools by rossco.
 * @package core
 * @subpackage selector
 * @author Ross Lawley
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Ross Lawley
 * @since 1.0.0
 * @version 1.0.0
 */
var SisaliSelector = new Class({

	/**
	 * Apply the selector rules when the dom ready event is called. This event
	 * is similar to the load event except it does not wait until the image are
	 * fully loaded. This is much faster.
	 * @param object The rules.
	 * @return object This class.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	start : function(rules) {
		window.addEvent('domready', function() {
			this.assign(rules);
		}.bind(this));
		return this;
	},

	/**
	 * Assign the selector rules when the dom ready event is called. This event
	 * is similar to the load event except it does not wait until the image are
	 * fully loaded. This is much faster.
	 * @param object The rules.
	 * @return object This class.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	assign : function(rules) {
		for (var key in rules) {
			var rule = rules[key];
			key.clean().split(',').each(function(selector) {
				var pair = selector.split('::');
				$$(pair[0]).each(function(elem) {
					if (pair.length == 1) return rule(elem);
					// attach the event on the selector
					elem.addEvent(pair[1], rule.pass(elem));
				});
			});
		}
	}
});// +---------------------------------------------------------------------------+
// | This file is part of a Sisali project.                                    |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * SisaliElementFinder is a class used to find an element using a selector from
 * a given context. The context can be a dom tree or a text tree given by an
 * ajax response.
 * @package core
 * @subpackage finder
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var SisaliElementFinder = new Class({

	/**
	 * @var object The context to search in.
	 */
	context : null,

	/**
	 * Constructor. Set the context used to search in. The context may be a
	 * simple dom object or an ajax response object. This object will search
	 * in both type.
	 * @param object The context.
	 * @return object This class.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initialize : function(context) {
		this.context = context;
		return this;
	},

	/**
	 * Set the context used to search in. The context may be a simple dom object
	 * or an ajax response object. This object will search in both type.
	 * @param object The context.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	setContext : function(context) {
		this.context = context;
	},

	/**
	 * Return the context used to search in. The context may be a simple dom object
	 * or an ajax response object. This object will search in both type.
	 * @return object The context.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	getContext : function() {
		return this.context;
	},

	/**
	 * Try to find an element in the current context. It's important to specify
	 * both the element id and tag so the search will be successfully in a
	 * ajax response type of context.
	 * @param string The search id.
	 * @param string The search type.
	 * @return object The result.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	find : function(id, tag) {
		// the context can have several different type. the most common will be
		// a dom document but it's also possible, whith an ajax response, that
		// the element will simply be a common string
		if (this.context === undefined) {
			return $(id);
		}
		// at this point we have a context to search from. the last thing to
		// check up is whether the context is a string, mostly from
		// responseText or a common dom tree
		if (typeof this.context == 'object') return this.context.getElementById(id);
		if (typeof this.context == 'string') {
			// create a function to filter the results. in this case it's
			// important to specify a tag to search with the id to minimise
			// the results therefore making it more efficient
			function filter(elem, index, array) {
				var searchType = id.substr(0, 1);
				var searchString = id.substr(1);
				switch (searchType) {
					case '.' : if (elem.hasClass(searchString)) return elem;
					case '#' : if (elem.getProperty('id') == searchString) return elem;
					default  : if (elem.getProperty('id') == searchString) return elem;
				}
			}
			return $A(new Element('div').setHtml(this.context).getElements(tag)).filter(filter.bind(this)).pop();
		}
	}
});// +---------------------------------------------------------------------------+
// | This file is part of a Sisali project.                                    |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * SisaliNavElement handle the client side effect of a given tab which means 
 * highlighting it on a mouse over event and selecting it while the current tab 
* in the group will be unselected.
 * @package core
 * @subpackage navigation
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
 var SisaliNavigationElement = new Class({

	/**
	 * @implements SisaliElement The basic element methods.
	 */
	Implements : [Events, Options, SisaliElement],

	/**
	 * @var object The options.
	 */
	options : {
		// onEmphasize : $empty
		// onNormalize : $empty
	},

	/**
	 * Constructor. Set the tab id or object and the group object used to handle
	 * the whole tabs mostly when one gets selected.
	 * @param object The tab element.
	 * @param object The tab options.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initialize : function(element, options) {
		this.element(element);
		this.addEvent('mouseenter', this.emphasize.bind(this));
		this.addEvent('mouseleave', this.normalize.bind(this));
		this.setOptions(options);
		return this;
	},

	/**
	 * This event is called when the mouse moves over the tab for the first
	 * time. This method will basically highlight the tab.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	emphasize : function() {
		if (this.isCurrent() == false) {
			this.addClass('highlight');
			this.fireEvent('onEmphasize');
		}
	},

	/**
	 * This event is called when the mouse moves out the tab for the first
	 * time. This method will basically unhighlight the tab.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	normalize : function() {
		if (this.isCurrent() == false) {
			this.removeClass('highlight');
			this.fireEvent('onNormalize');
		}
	},

	/**
	 * Indicate wheter or not the tab is considered has the current tab. This
	 * is given by the class named current.
	 * @return bool True if the tab is a current one.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	isCurrent : function() {
		return this.hasClass('current');
	}
 });// +---------------------------------------------------------------------------+
// | This file is part of a Sisali project.                                    |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * SisaliTab handle the client side effect of a given tab which means highlighting
 * it on a mouse over event and selecting it while the current tab in the group
 * will be unselected.
 * @package core
 * @subpackage navigation
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
 var SisaliTab = new Class({

	/**
	 * @implements SisaliElement The basic element methods.
	 */
	Implements : [Events, Options, SisaliElement],

	/**
	 * @var object The optionnal tab group.
	 */
	group : null,

	/**
	 * @var object The options.
	 */
	options : {
		// onEmphasize : $empty
		// onNormalize : $empty
		// onSelect : $empty
		// onDeselect : $empty
	},

	/**
	 * Constructor. Set the tab id or object and the group object used to handle
	 * the whole tabs mostly when one gets selected.
	 * @param object The tab element.
	 * @param object The tab group.
	 * @param object The tab options.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initialize : function(element, group, options) {
		this.group = group;
		this.element(element);
		this.addEvent('mouseenter', this.emphasize.bind(this));
		this.addEvent('mouseleave', this.normalize.bind(this));
		this.addEvent('click', this.select.bind(this));
		this.setOptions(options);
		return this;
	},

	/**
	 * Select the tab by changing the class of the element to current. If this
	 * tab is in a group, this will also deselect the previously selected tab.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	select : function() {
		if (this.isCurrent() == false) {
			this.addClass('current');
			this.fireEvent('onSelect');
			if (this.group) this.group.setCurrent(this);
		}
	},

	/**
	 * Deselect the tab by simply calling the select event of the class. This
	 * method is just an accessor for the selection event.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	deselect : function() {
		if (this.isCurrent()) {
			this.removeClass('current');
			this.removeClass('highlight');
			this.fireEvent('onDeselect');
			if (this.group) this.group.setCurrent(null);
		}
	},

	/**
	 * This event is called when the mouse moves over the tab for the first
	 * time. This method will basically highlight the tab.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	emphasize : function() {
		if (this.isCurrent() == false) {
			this.addClass('highlight');
			this.fireEvent('onEmphasize');
		}
	},

	/**
	 * This event is called when the mouse moves out the tab for the first
	 * time. This method will basically unhighlight the tab.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	normalize : function() {
		if (this.isCurrent() == false) {
			this.removeClass('highlight');
			this.fireEvent('onNormalize');
		}
	},

	/**
	 * Indicate wheter or not the tab is considered has the current tab. This
	 * is given by the class named current.
	 * @return bool True if the tab is a current one.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	isCurrent : function() {
		return this.hasClass('current');
	}
 });// +---------------------------------------------------------------------------+
// | This file is part of a Sisali project.                                    |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * SisaliTabImage handle the client side effect of a given tab which means highlighting
 * it on a mouse over event and selecting it while the current tab in the group
 * will be unselected.
 * @package core
 * @subpackage navigation
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var SisaliTabImage = new Class({

	Extends : SisaliTab,

	/**
	 * @var object The image container.
	 */
	img : null,

	/**
	 * @var object The image for the general tab.
	 */
	gen : null,

	/**
	 * @var object The image for the alternate tab.
	 */
	alt : null,

	/**
	 * Constructor. Set the tab id or object and the group object used to handle
	 * the whole tabs mostly when one gets selected.
	 * @param object The tab.
	 * @param object The tab group.
	 * @param object The tab options.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe_dery@hotmail.com)
	 * @since 1.0.0
	 */
	initialize : function(tab, group, gen, alt, options) {
		this.parent(tab, group, options);
		this.img = $E('img', this.element);
		this.gen = new Image();
		this.alt = new Image();
		this.gen.src = gen;
		this.alt.src = alt;
	},

	/**
	 * Change the original element image source to the general pre-loaded image.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe_dery@hotmail.com)
	 * @since 1.0.0
	 */
	setGenImage : function() {
		this.image.src = this.gen.src;
	},

	/**
	 * Change the original element image source to the alternate pre-loaded image.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe_dery@hotmail.com)
	 * @since 1.0.0
	 */
	setAltImage : function() {
		this.image.src = this.alt.src;
	},

	/**
	 * This event is called when the mouse moves over the tab for the first
	 * time. This method will basically highlight the tab.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	emphasize : function() {
		if (this.isCurrent() == false) this.setAltImage();
		this.parent();
	},

	/**
	 * This event is called when the mouse moves out the tab for the first
	 * time. This method will basically unhighlight the tab.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	normalize : function() {
		if (this.isCurrent() == false) this.setGenImage();
		this.parent();
	},

	/**
	 * Select the tab by changing the class of the element to current. If this
	 * tab is in a group, this will also deselect the previously selected tab.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	select : function() {
		if (this.isCurrent() == false) this.setAltImage();
		this.parent();
	},

	/**
	 * Deselect the tab by simply calling the select event of the class. This
	 * method is just an accessor for the selection event.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	deselect : function() {
		if (this.isCurrent()) this.setGenImage();
		this.parent();
	}
});// +---------------------------------------------------------------------------+
// | This file is part of a Sisali project.                                    |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 *  SisaliTab.Group handle a group of tabs. This class is mostly used to make sure
 * there is only one selected tab within a group.
 * @package core
 * @subpackage navigation
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
 var SisaliTabGroup = new Class({

 	/**
 	 * @var object The currently selected tab.
 	 */
 	curr : null,

 	/**
 	 * @var array The tabs in the group.
 	 */
 	tabs : null,

	/**
	 * Constructor. Initialize the members of this class.
	 * @param object The tab options.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initialize : function() {
	 	this.tabs = [];
	 	this.curr = null;
	 	return this;
	},

 	/**
 	 * Add a tab in this group. The tab can be a simple id which will create a
 	 * new tab object or you can give an a tab object.
 	 * @param object The tab object.
 	 * @param object The tab options.
  	 * @return object The added tab object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
 	 */
 	addTab : function(tab, options) {
 		var object = null;
 		switch (typeof tab) {
 			// create a new tab based on the default tab class. The options are
 			// automatically passed to this class
 			case 'string' : object = new SisaliTab(tab, this, options); break;
 			case 'object' : object = tab; break;
 		}
 		// indicate to the group that this tab is the current one
 		if (object.isCurrent()) this.setCurrent(object);
 		this.tabs.push(object);
 		return tab;
 	},

  	/**
  	 * Set the current tab in the group. This method will automatically deselect
  	 * the previous current tab.
  	 * @param object The current tab.
  	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
 	 */
 	setCurrent : function(current) {
 		if (this.curr) this.curr.deselect();
 		this.curr = current;
 	},

  	/**
  	 * Return the current tab in the group.
  	 * @return object The current tab.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
 	 */
 	getCurrent : function() {
 		return this.curr;
 	}
 });// +---------------------------------------------------------------------------+
// | This file is part of a KT Western Farm project.                            |
// | Copyright (C) Jean-Philippe Dery (jeanphilippe.dery@gmail.com)            |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * KTSlideShow is a class to display a slide show.
 * @package core
 * @subpackage navigation
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
 var KTSlideShow = new Class({

	/**
	 * @implements SisaliElement The basic element methods.
	 */
	Implements : [Events, SisaliElement],
	
	/**
	 * @var array A list of slides.
	 */
	slides : null,

	/**
	 * @var int The current slide index.
	 */
	slide : -1,
		
	/**
	 * Constructor. Set the slideshow object id.
	 * @param object The tab element.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initialize : function(element) {
		this.element(element);
		this.slides = new Array();
		return this;
	},
	
	/**
	 * Add a new image to the list of slides.
	 * @param string The path to the image.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	addSlide : function(src) {
		var slide = new Element('div');
		slide.addClass('slide');
		slide.setStyle('background-image', 'url(' + src + ')');
		slide.setStyle('background-repeat', 'no-repeat');
		slide.fade('hide');		
		slide.inject(this.element(), 'inside');
		this.slides.push(slide);
	},

	/**
	 * Update the slideshow to the next image.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	update : function() {
		if (this.slide == -1) {
			// the first image is the background image so we only show the
			// next image in the list
			this.slides[++this.slide].fade('in');			
		} else if (this.slide < this.slides.length - 1) {
			// we are in the middle of the slideshow so we show the next image
			// and hide the previous one
			this.slides[this.slide].fade('out');
			this.slides[this.slide + 1].fade('in');			
			this.slide++;
		} else if (this.slide == this.slides.length - 1) {
			// this is the end of the slideshow. all we have to do is hide
			// the last image and display the background image back
			this.slides[this.slide].fade('out');
			this.slide = -1;			
		}
		return this;
	},
	
	/**
	 * Start the slide show.
	 * @param int The interval.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	start : function(interval) {
		setInterval(this.update.bind(this), interval);
	}
});
