/**
 * @fileOverview Banner Gadget Script File
 * @version 1.0
 * @since 2010-09-22
 */

/**
 * widget YUI interface
 * @author marco.l
 * @since 2010-09-22
 */
var I =
{
	/**
	 * gets a node by its id
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String} id the id to be searched for
	 * @return the node or false
	 * @type Node|Boolean
	 * @see YAHOO.util.Dom.get
	 */
	byId:	function(id)
			{
				return YAHOO.util.Dom.get(id);
			}, //END OF I.byId
	
	/**
	 * gets nodes by query
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String} query string
	 * @param {Boolean} return only the first element
	 * @return the nodes that match the query
	 * @type Node|Array
	 * @see YAHOO.util.Selector.query
	 * @example  I.query("li a", true);
	 */
	query: function()
			{
				return YAHOO.util.Selector.query.apply(window, arguments);
			}, //END OF I.query
	
	
	/**
	 * adds a css class
	 * @method addClass
	 * @author marco.l
	 * @version 1.0
	 * @since 2008-08-20
	 * @memberOf gco.dom
	 * @param {String|Object} node id or dom node
	 * @param {String} className css class name
	 * @return success or fail
	 * @type Boolean
	 * @example gco.dom.addClass("nav", "hover")
	 * @see YAHOO.util.Dom.addClass
	 */
	addClass:	function(node, className)
				{
					return YAHOO.util.Dom.addClass(node, className);
				}, //END OF gco.dom.addClass
	
	
	/**
	 * removes the css class from a node
	 * @method removeClass
	 * @author marco.l
	 * @version 1.0
	 * @since 2008-08-20
	 * @memberOf gco.dom
	 * @param {String|Object} node id or dom node
	 * @param {String} className css class name
	 * @return success or fail
	 * @type Boolean
	 * @example gco.dom.removeClass("nav", "hover")
	 * @see YAHOO.util.Dom.removeClass
	 */
	removeClass:	function(node, className)
					{
						return YAHOO.util.Dom.removeClass(node, className);
					}, //END OF gco.dom.removeClass
	
			
	/**
	 * sets a node inline css
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {Object|Object} node id or dom node
	 * @param {String} property css property
	 * @param {String} value property value
	 * @return success or fail
	 * @type Boolean
	 * @example I.setStyle("nav", "border", "1px solid #CCCCCC")
	 * @see YAHOO.util.Dom.setStyle
	 */
	setStyle:	function(node, property, value)
				{
					return YAHOO.util.Dom.setStyle(node, property, value);
				}, //END OF I.setStyle
	
	/**
	 * checks if value is null
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String|Object|Array|Number|Node} value value to be checked
	 * @return returns if a value is null
	 * @type Boolean
	 * @example I.isNull("something")
	 */
	isNull:	function(value)
			{
				return (value === null);
			}, //END OF I.isNull
	
	/**
	 * checks if value is an array
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String|Object|Array|Number|Node} value value to be checked
	 * @return returns if a value is an array
	 * @type Boolean
	 * @example I.isArray("something")
	 */
	isArray:	function(value)
				{
					return YAHOO.lang.isArray(value);
				}, //END OF I.isArray
				
	/**
	 * checks if value is an object
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String|Object|Array|Number|Node} value value to be checked
	 * @return returns if a value is an object
	 * @type Boolean
	 * @example I.isObject("something")
	 */
	isObject:	function(value)
				{
					return (typeof(value) === "object" && !I.isArray(value) && !I.isNull(value));
				}, //END OF I.isObject
				
	/**
	 * runs a timed set function inside a determined scope
	 * @author marco.l
	 * @since 2010-09-22
	 * @memberOf gco.lang
	 * @param {Int} time time in miliseconds
	 * @param {Object} scope scope where the function will run
	 * @param {Function} fn function to be called
	 * @param {Array} args function arguments passed as an array
	 * @param {Boolean} isInterval flag to set the function to be run in intervals
	 * @return time object
	 * @type Object
	 * @example I.later(100, window, function(text){alert(text);}, ["text"], false);
	 * @see YAHOO.lang.later
	 */		
	later:	function(time, scope, fn, args, isInterval)
			{
				return YAHOO.lang.later(time, scope, fn, args, isInterval);
			}, //END OF I.later
				
	/**
	 * encode a value to a json string
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {Object} value value to be encoded
	 * @return encoded value as string
	 * @type String
	 * @example I.encode({"a": 2, "b": 3})
	 * @see YAHOO.lang.JSON.stringify
	 */		
	jsonEncode:	function(value)
				{
					return YAHOO.lang.JSON.stringify(value);
				}, //END OF I.jsonEncode
			
	/**
	 * connects through XmlHttpRequest
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String} method xhr connection method (POST/GET)
	 * @param {String} uri connection uri
	 * @param {Object|Function} callback callback function
	 * @param {Object|String} postData post body
	 * @return connection object
	 * @type Object
	 * @see YAHOO.util.Connect.asyncRequest, http://developer.yahoo.com/yui/connection/
	 * @example gco.connect("POST", "text.php", {success: function(e) {console.log("PASS",e)}, failure: function(err){console.log("Fail", err)}}, "username=anonymous&userid=0");
	 */	
	connect:	function(method, uri, callback, postData)
				{
					var i, cur, string;
					
					//convert object to string
					if(I.isObject(postData))
					{
						for(i in postData)
						{
							if(postData.hasOwnProperty(i))
							{
								cur = postData[i];
								
								if(I.isObject(cur) || I.isArray(cur))
								{
									string += "&" + i + "=" + I.jsonEncode(cur);
								}
								else
								{
									string += "&" + i + "=" + cur;
								}
							}
						}
					}
					else
					{
						string = postData;
					}
					
					return YAHOO.util.Connect.asyncRequest(method, uri, callback, string);
				}, //END OF I.connect
				
	/**
	 * add event listener
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String|Object|Array} node target node
	 * @param {String} event type of event
	 * @param {Function} fn function to be called on event
	 * @param {Object} obj [optional] object to be passed to the function as argument
	 * @param {Boolean} override [optional] flag to indicate if the scope should be override by the argument object
	 * @return true if added
	 * @type Boolean
	 * @example I.addEvent("dashboard", "click", function() {console.log(this);}, {a: 1}, false)
	 * @see YAHOO.util.Event.addListener
	 */
	addEvent:	function(node, event, fn, obj, override)
			{
				return YAHOO.util.Event.addListener(node, event, fn, obj, override);
			}, //END OF I.addEvent
			
	/**
	 * remove an event listener
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String|Object|Array} node target node(s)
	 * @param {String} event type of event
	 * @param {Function} fn function to be removed from the event, if undefined it will remove all the functions associated with the event
	 * @return true if successfully removed
	 * @type Boolean
	 * @example I.removeEvent("dashboard", "click", hander)
	 * @see YAHOO.util.Event.removeListener
	 */
	removeEvent:	function(node, event, fn)
					{
						return YAHOO.util.Event.removeListener(node, event, fn);
					},  //END OF I.remove
					
	/**
	 * create custom event
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String} name event name
	 * @param {Object} scope event scope
	 * @return custom event object
	 * @type Object
	 * @example I.create("hide")
	 * @see YAHOO.util.CustomEvent
	 */				
	CreateEvent:	function(name, scope)
					{
						return new YAHOO.util.CustomEvent(name, scope);
					}, //END OF I.CreateEvent
	
	/**
	 * creates a dom node
	 * @author alexandre.m
	 * @version 1.0
	 * @since 2010-09-22
	 * @param {String} tag tag name
	 * @param {Object} properties dom node properties
	 * @param {String|Object} parent [optional] parent node id or dom node
	 * @return append result or dom node
	 * @type Boolean|Object
	 * @example I.createNode("div", {innerHTML: "text", className: "highlight"}, "parent");
	 */			
	createNode:	function(tag, properties, parent)
				{
					var p, node = document.createElement(tag);
					parent = I.byId(parent);
					
					for(p in properties)
					{
						if(properties.hasOwnProperty(p))
						{
							node[p] = properties[p];
						}
					}
					
					if(parent)
					{
						return parent.appendChild(node);
					}
					
					return node;
				}, // END OF createNode
		
	/**
	 * animation
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {Sring|Object} node animation target
	 * @param {Object} attributes animation attributes
	 * @param {Number} duration animation duration
	 * @param {Function} method easing method
	 * @return animation object
	 * @type Object
	 * @example I.Animation('test', { width: { to: 400 } }, 1, gco.anim.Easing.easeOut);
	 * @see http://developer.yahoo.com/yui/docs/YAHOO.util.Anim.html
	 */	
	Animation:	function(node, attributes, duration, method)
				{
					duration = duration || 1;
					if(!method)
					{
						method = null;
					}
					
					return new YAHOO.util.Anim(node, attributes, duration, method);
				}, //END OF I.Animation
	
	/**
	 * easing method
	 */
	Easing:	YAHOO.util.Easing, //END OF I.Easing
				
	/**
	 * xml get nodes method 
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String} tag tag name
	 * @param {Object} root root element
	 * @param {Boolean} isUnique check if it should return only one element
	 * @return the found elements
	 * @type Array|Boolean
	 */
	xmlGet:	function(tag, source, isUnique)
			{
				var els;
				
				//check root
				if(!source)
				{
					return false;
				}
				
				els = source.getElementsByTagName(tag);
				
				if(els.length === 0)
				{
					
					return false;
				}
				
				return (isUnique) ? els[0] : els;
				
			}, //END OF I.xmlGet
	
	/**
	 * xml get node text
	 * @author marco.l
	 * @since 2010-09-22
	 * @param {String} tag tag name
	 * @param {Object} root root element
	 * @return the found element value
	 * @type Array|Boolean|Number|String
	 */
	xmlGetText:	function(tag, root)
				{
					var node = I.xmlGet(tag, root, true);
					return (node) ? node.childNodes[0].nodeValue : null;
				}, //END OF xmlGetValue
	
	/**
	 * get the browser type
	 */
	getBrowser:	function()
				{
					var node = document.getElementsByTagName("html")[0],
						browsers = ["webkit", "firefox", "ie", "opera"],
						regexp, test, i, li, cssClass;
				
					//detect browser  
					for(i=0, li=browsers.length; i<li; ++i)   
					{   
						regexp = new RegExp( "(" + browsers[i] + ")\\/*\\s*(\\d+)");   
						test = regexp.exec(navigator.userAgent.toLowerCase());   
						if(test && test.length == 3)  
						{
							return test[1] + test[2];
						}
					}
					return false;
				}
			
}; //END OF I

/**
 * widget constructor
 * @author marco.l
 * @since 2010-09-22
 */
var Banner = function()
{
	//config
	this.cfg = {};
	
	//loading image path
	this.cfg.loadingImagePath = "/BannerGadget/css/bin/loading_images.png";
	
	//timer
	this.timer = null;
	
	//flags
	this.isRendered = false;
	
	//Banner images
	this.images = [];
	
	//Banner nodes
	this.nodes = {};
	
	/**
	 * widget custom events
	 */
	this.events =
	{
		onReadXML:	new I.CreateEvent("onReadXML"),
		onLoad:	new I.CreateEvent("onLoad"),
		onRender:	new I.CreateEvent("onRender"),
		onImageLoad: new I.CreateEvent("onImageLoad"),
		onTransitionStart:	new I.CreateEvent("onTransitionStart"),
		onTransitionEnd:	new I.CreateEvent("onTransitionEnd"),
		onImageShow:	new I.CreateEvent("onImageShow"),
		onLegendShow:	new I.CreateEvent("onLegendShow")
	};
	
	this._init();
	
}; //END OF Banner

/**
 * widget prototype
 * @author marco.l
 * @since 2010-09-22
 */
Banner.prototype =
{
	/**
	 * start methods
	 * @author marco.l
	 * @since 2010-09-22
	 * @return void
	 */
	_init:	function()
			{
				var scope = this;
				
				this.loadingImageLoaded = false;
				
				// Preload the loading image
				this.images.loadingImage = new Image();
				
				//add events
				this._addEvents();
				
				this.images.loadingImage.onreadystatechange = function(evt)
				{
					if (this.readyState === 'complete' || this.readyState === 'loaded')
					{
						//remove on ready state change
						this.onreadystatechange = function() {};
						
						//check if loading image has loaded
						if(scope.loadingImageLoaded === true)
						{
							return;
						}
						scope.loadingImageLoaded = true;						
						
						// Create the html code
						scope._build();
					}
				};
				
				
				I.addEvent(this.images.loadingImage, "load", function(event, scope)
				{
					// Remove the onLoad event
					I.removeEvent(this, "load");
					
					//check if loading image has loaded
					if(scope.loadingImageLoaded === true)
					{
						return;
					}
					scope.loadingImageLoaded = true;					
					
					// Create the html code
					scope._build();
					
				}, this, false);
				
				this.images.loadingImage.src = this.cfg.loadingImagePath;
				
				//check if image was loaded
				I.later(500, this, this._forceBuild, [], false);
				
				// Fire the onLoad event
				this.events.onLoad.fire(this);
				
			}, //END OF _init
	
	/**
	 * force build if loading image wasn't found
	 * @author marco.l
	 * @since 2010-12-02
	 */		
	_forceBuild:	function()
					{
						if(!this.loadingImageLoaded)
						{
							this.loadingImageLoaded = true;
							this._build();
						}
					}, //END OF _forceBuild
	
	/**
	 * build html
	 */
	_build:	function()
	{
		// Create the widget domNode
		this.nodes.domNode = I.query(".gcb_container", "", true);
		
		// Check if node exists
		if(!this.nodes.domNode)
		{
			return;
		}
		
		// Create the images node
		this.nodes.images = I.createNode("div", {className: "gcb_image"}, this.nodes.domNode);
		
		// Create the loading image node
		this.nodes.loadingImage = I.createNode("div", {className: "gcb_image_loading"}, this.nodes.images);
		this.nodes.loadingImage.appendChild(this.images.loadingImage);
		this.nodes.loadingImageOverlay = I.createNode("div", {className: "gcb_image_loading_overlay"}, this.nodes.loadingImage);
		
		// Create current image node
		this.nodes.firstImage = I.createNode("div", {className: "gcb_image_current"}, this.nodes.images);
		
		// Create second image node
		this.nodes.secondImage = I.createNode("div", {className: "gcb_image_next"}, this.nodes.images);
		
		// Create legend
		this.nodes.legend = I.createNode("div", {className: "gcb_image_legend"}, this.nodes.images);
		
		// Create link
		this.nodes.link = I.createNode("a", {className: "gcb_image_link"}, this.nodes.images);
		
		// Create the navigation node
		this.nodes.navigation = I.createNode("div", {className: "gcb_navigation"}, this.nodes.domNode);
		
		// Create previous arrow
		this.nodes.previousImage = I.createNode("div", {className: "gcb_navigation_arrow previous"}, this.nodes.navigation);
		
		// Create paginator
		this.nodes.paginator = I.createNode("div", {className: "gcb_navigation_paginator"}, this.nodes.navigation);
		
		// Create next arrow
		this.nodes.nextImage = I.createNode("div", {className: "gcb_navigation_arrow next"}, this.nodes.navigation);
		
		// Create thumbsnails
		this.nodes.thumbnails = I.createNode("ul", {className: "gcb_navigation_paginator_thumbs"}, this.nodes.paginator);
		
		// Fire onRender event
		this.isRendered = true;
		this.events.onRender.fire(this);
		
	}, //END OF _build
	
	/**
	 * adds widget events
	 */
	_addEvents:	function()
				{
					//get XML info
					this.events.onRender.subscribe(this._readXML, this, true);
					
					//subscribe events
					this.events.onRender.subscribe(this._createAnimations, this, true);
					this.events.onRender.subscribe(this._showLoading, this, true);
					this.events.onReadXML.subscribe(this._loadImages, this, true);
					this.events.onImageShow.subscribe(this._controller, this, true);
					this.events.onReadXML.subscribe(this._addPaginator, this, true);
					
				}, //END OF _addEvents
	
	/**
	 * removes widget events
	 */
	_removeEvents:	function()
					{
						I.removeEvent(window, "load", this._readXML);
					}, //END OF _removeEvents
	
	/**
	 * reads the image xml
	 * @author marco.l
	 * @since 2010-09-22
	 * @return void
	 */
	_readXML:	function()
				{
					var meta, path, callback;
					
					meta = I.query("meta[name=bannerXML]", "", true);
					
					if(!meta)
					{
						return;
					}
					
					path = meta.getAttribute("content");
					
					/**
					 * callback object
					 */
					callback =
					{
						scope: this,
						
						timeout: 3000,
						
						success:	this._parseXML,
									
						failure:	function() {}
					};
					
					I.connect("GET", path, callback, "");
				}, //END OF _readXML
	
	/**
	 * parses xml
	 * @author marco.l
	 * @since 2010-09-22
	 * @return void
	 */
	_parseXML:	function(data)
				{
					var xml, ximgs, i, li, cur, attributes, details,
						imgs = [], nimgs = [], start = 0;
					
					xml = data.responseXML;
					details = I.xmlGet("details", xml, true);
					
					if(!details || !details.getAttribute("expositiontime"))
					{
						this._hideGadget();
						return;
					}
					
					//check for dom Node
					this.nodes.domNode = this.nodes.domNode || I.query(".gcb_container", "", true);
					if(!this.nodes.domNode)
					{
						console.error("Dom node for banner gadget not found!");
						return;
					}
					
					//add sized node css class for the dom node
					this.nodes.domNode.className = (this.nodes.domNode.className) ? this.nodes.domNode.className + " gcb_container_sized" : "gcb_container_sized";
					
					//get config
					this.cfg.expositionTime = parseFloat(details.getAttribute("expositiontime"), 10);
					this.cfg.transitionTime = parseFloat(details.getAttribute("transitionTime"), 10);
					this.cfg.transitionType = details.getAttribute("transitionType");
					
					//get images
					ximgs = I.xmlGet("imagem", xml);
					
					//get default image
					for(i=0, li=ximgs.length; i<li; ++i)
					{
						cur = ximgs[i];
						if(cur.isdefault)
						{
							start = i;
						}
						nimgs.push(cur);
					}
					
					//set image order
					if(start !== 0)
					{
						imgs = nimgs.slice(start).concat(nimgs.slice(0, start));
					}
					else
					{
						imgs = nimgs;
					}
					
					//store
					for(i=0, li=imgs.length; i<li; ++i)
					{
						cur = imgs[i];
						attributes =
						{
							path: cur.getAttribute("img"),
							legend: cur.getAttribute("leg"),
							link: cur.getAttribute("picLink"),
							target: cur.getAttribute("linkTarget"),
							type: "image"
						};
						
						// NOTE: This is here for the flashbanner legacy
						// Check if legend is a link. If so use the legend as link
                        if(attributes.legend.match(/(http|https):\/\/?/g) && attributes.link == "")
                        {
                            attributes.link = attributes.legend;
                            attributes.legend = "";
                            attributes.target = "_self";
                        }
						
						this.images.push(attributes);
					}
					
					//trigger event
					this.events.onReadXML.fire();
				}, //END OF _parseXML
	
	/**
	 * loads the images
	 * @author marco.l
	 * @since 2010-09-22
	 */
	_loadImages:	function()
					{
						var i, li, cur, readystate, scope = this;
						
						readystate = function(evt)
						{
							if (this.readyState === "complete" || this.readyState === "loaded")
							{
								//remove on ready state change
								this.onreadystatechange = function() {};
								
								scope._controller();
							}
						};
						
						for(i=0, li=this.images.length; i<li; ++i)
						{
							cur = this.images[i];
							cur.file = new Image();
							cur.file.src = cur.path;
							cur.file.onreadystatechange = readystate;
							
							if(cur.file.readyState === "complete" || cur.file.readyState === "loaded")
							{
								this._controller();
							}
							
							if(!cur.file.readyState)
							{
								I.addEvent(cur.file, "load", this._controller, this, true);
							}
						}
						
						//this._controller();
					}, //END OF _loadImages
	
	/**
	 * run the transition
	 * @author marco.l
	 * @since 2010-09-22
	 */
	_runTransition:	function(img)
					{
						var browser = I.getBrowser();
						
						if(!this.cfg.transitionType || !this.transitions[this.cfg.transitionType])
						{
							this.cfg.transitionType = "dissolve";
						}
						
						//hide loading
						this._hideLoading();
						
						this.events.onTransitionStart.fire();
						this.isAnimated = true;
						
						//prepare legend
						if(browser.indexOf("ie") < 0)
						{
						    I.setStyle(this.nodes.legend, "opacity", 0);
						}
						else
						{
						    I.setStyle(this.nodes.legend, "visibility", "hidden");
						}
						
						this.nodes.legend.innerHTML = img.legend;
						
						this.transitions[this.cfg.transitionType].call(this, img);
					}, //END OF _runTransition
	
	/**
	 * creates animations for widget
	 * @author marco.l
	 * @since 2010-09-22
	 */
	_createAnimations:	function()
						{
							this.firstImageAnimation = new I.Animation(this.nodes.firstImage, {}, this.cfg.transitionTime * 1000, I.Easing.easeOut);
							this.secondImageAnimation = new I.Animation(this.nodes.secondImage, {}, this.cfg.transitionTime * 1000, I.Easing.easeOut);
							this.legendAnimation = new I.Animation(this.nodes.legend, {}, this.cfg.transitionTime * 1000, I.Easing.easeOut);
							
							this.firstImageAnimation.onComplete.subscribe(this._fireOnTransitionEnd, this, true);
							this.secondImageAnimation.onComplete.subscribe(this._fireOnTransitionEnd, this, true);
							
                            this.legendAnimation.onComplete.subscribe(function()
                            {
                                I.setStyle(this.nodes.legend, "visibility", "visible");
                            }, this, true);

						}, //END OF _createAnimations
	
	/**
	 * transitions
	 */
	transitions:	{
						/**
						 * dissolve transition
						 */
						dissolve:	function(img)
									{
										var	image;
										
										//check foreground layer
										this.foreground = I.query(".gcb_image_current", this.nodes.domNode, true);
										this.background = I.query(".gcb_image_next", this.nodes.domNode, true);
										
										image = img.path;
										
										// Add link to image
										this._addLink(img);
										
										//add image to background
										this.background.style.backgroundImage =   "url(" + image + ")";
										I.setStyle(this.background, "opacity", 1);
										
										//do animation
										if(!this.firstImageAnimation)
										{
											this._createAnimations();
										}
										
										if(this.foreground === this.firstImageAnimation.getEl())
										{
											this.firstImageAnimation.attributes = { opacity: { to: 0 } };
											this.firstImageAnimation.animate();
										}
										else
										{
											this.secondImageAnimation.attributes = { opacity: { to: 0 } };
											this.secondImageAnimation.animate();
										}
									} //END OF dissolve
	
					}, //END OF transitions
	
	/**
	 * exposing image
	 * @author marco.l
	 * @since 2010-09-22
	 */
	_exposing:	function()
				{
					this.timer = I.later(this.cfg.expositionTime * 1000, this, this._fireOnImageShow);
				}, //END OF _exposing
	
	/**
	 * fire on image show event 
	 * @author marco.l
	 * @since 2010-09-22
	 */
	_fireOnImageShow:	function()
						{
							this.isAnimated = false;
							this.events.onImageShow.fire();
						}, //END OF _fireOnImageShow
	
	/**
	 * show legend
	 */					
	_showLegend:	function()
					{
					    var browser = I.getBrowser();
					    
					    if(browser.indexOf("ie") < 0)
					    {
                            this.legendAnimation.attributes = { opacity: { to: 1 } };
					    }
					    
					    this.legendAnimation.animate();
					}, //END OF _showLegend
	
	/**
	 * fire onTransitionEnd event
	 */
	_fireOnTransitionEnd:	function()
							{
								//change classes
								this.foreground.className = "gcb_image_next";
								this.background.className = "gcb_image_current";
								
								//show legend
								this._showLegend();
								
								this.events.onTransitionEnd.fire();
								this._exposing();
							},
							
	/**
	 * flow control handler
	 * @author marco.l
	 * @since 2010-09-22
	 */
	_controller:	function()
					{
						var img;
						
						if(!this.nextImageIndex)
						{
							this.nextImageIndex = 0;
						}
						
						//get next image
						img = this.images[this.nextImageIndex];
						
						//avoid showing if image not rendered or file not completed or is animating
						if(!this.isRendered || this.isAnimated)
						{
							return;
						}
						
						//show image
						this._runTransition(img);
						this._updatePaginator(this.nextImageIndex);
						this.nextImageIndex = (this.nextImageIndex + 1) % this.images.length;
					}, //END OF _controller
	
	/**
	 * get next image
	 */
	next:	function(event, scope)
	{
		// cancel timer
		if(scope.timer && scope.timer.cancel)
		{
			scope.timer.cancel();
		}
		
		// Run controller
		scope._fireOnImageShow();
	},
	
	/**
	 * get previous image
	 */
	previous:	function(event, scope)
	{
		// cancel timer
		if(scope.timer && scope.timer.cancel)
		{
			scope.timer.cancel();
		}
		
		// Set the nextImageIndex
		if(scope.nextImageIndex - 2 >= 0)
		{
			scope.nextImageIndex = (scope.nextImageIndex - 2) % scope.images.length;
		}
		else
		{
			scope.nextImageIndex = scope.images.length + scope.nextImageIndex - 2;
		}
		
		// Run controller
		scope._fireOnImageShow();
	},
	
	/**
	 * go to image
	 */
	goTo:	function(event, params)
	{
		// cancel timer
		if(params.scope.timer && params.scope.timer.cancel)
		{
			params.scope.timer.cancel();
		}
		
		// Set the nextImageIndex
		params.scope.nextImageIndex = params.imageIndex % params.scope.images.length;
		
		// Run controller
		params.scope._fireOnImageShow();
		
	}, // END OF goTo
	
	/**
	 * show loading message
	 */
	_showLoading:	function()
	{
		this.nodes.loadingImage.style.display = "block";
	}, //END OF _showLoading
	
	/**
	 * hide loading message
	 */
	_hideLoading:	function()
	{
		this.nodes.loadingImage.style.display = "none";
	},
	
	/**
	 * add pagination
	 */
	_addPaginator:	function()
	{
		var i, li, className, thumbnail;
		
		// Add the paginator
		// go through all the images and add a thumbnail to each one
		for(i = 0, li = this.images.length; i < li; ++i)
		{
			className = "";
			
			if(i === 0)
			{
				className = "selected";
			}
			
			thumbnail = I.createNode("li", {className: className}, this.nodes.thumbnails);
			this.nodes.thumbnails.appendChild(thumbnail);
			
			I.addEvent(thumbnail, "click", this.goTo, {scope: this, imageIndex: i}, this, false);
		}
		
		// Add event to the arrows
		I.addEvent(this.nodes.nextImage, "click", this.next, this, false);
		I.addEvent(this.nodes.previousImage, "click", this.previous, this, false);
	},
	
	/**
	 * change pagination
	 */
	_updatePaginator:	function(index)
	{
		var bolinhasDoArtur = I.query("li", this.nodes.thumbnails);
		
		for(var i = 0, li = bolinhasDoArtur.length; i < li; ++i)
		{
			if(i === index)
			{
				I.addClass(bolinhasDoArtur[i], "selected");
			}
			else
			{
				I.removeClass(bolinhasDoArtur[i], "selected");
			}
		}
	}, // END OF _updatePaginator
	
	
	_addLink:	function(img)
	{
		if(img.link)
		{
			this.nodes.link.setAttribute("href", img.link);
			this.nodes.link.setAttribute("target", img.target);
            // Show the link node
            I.setStyle(this.nodes.link, "display", "block");
		}
		else
		{
			this.nodes.link.removeAttribute("href");
			this.nodes.link.removeAttribute("target");
			// Hide the link node
			I.setStyle(this.nodes.link, "display", "none");
		}
	}, // END OF _addLink
	
	_hideGadget:	function()
	{
		this.nodes.domNode.style.height = 0;
		this.nodes.domNode.style.overflow = "hidden";
		
	}, // END OF _hideGadget
	
	/**
	 * destroys the widget
	 * @author marco.l
	 * @since 2010-09-22
	 * @return void
	 * @example banner.destroy()
	 */
	destroy:	function()
				{
					this._removeEvents();
					
					//TODO destroy nodes
					
				} //END OF destroy
	
}; //END OF Banner.prototype


var Banner = new Banner();

