/**
 * @fileOverview Banner Gadget Script File
 * @version 1.0
 * @since 2010-09-22
 */

 /*global console, Image, YAHOO, window, document, navigator*/

(function()
{
	var I, Banner, i, li, b, nodes, cur;


	/**
	 * widget YUI interface
	 * @author marco.l
	 * @since 2010-09-22
	 */
	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
		 * @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 I.addClass
		
		/**
		 * checks if the node has a class
		 * @author marco.l
		 * @version 1.0
		 * @param {String|HTMLElement} node node to be searched
		 * @param {String} className the classname to search for
		 * return the search result
		 * @type {Boolean}
		 */
		hasClass:	function(node, className)
					{
						return YAHOO.util.Dom.hasClass(node, className);
					}, // END OF I.hasClass
		
		
		/**
		 * removes the css class from a node
		 * @method removeClass
		 * @author marco.l
		 * @version 1.0
		 * @since 2008-08-20
		 * @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 I.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 I.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
	 * @param {String|HTMLElement} node dom node where that widget will be placed
	 */
	Banner = function(node)
	{
		//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 = {};
		this.nodes.domNode = I.byId(node);
		/**
		 * 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()
		{
			// 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
		
		/**
		 * image transitions
		 * 
		 * @author marco.l
		 * @since 2010-09-22
		 */
		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 i, li, thb = I.query("li", this.nodes.thumbnails);
								
								for(i = 0, li = thb.length; i < li; ++i)
								{
									if(i === index)
									{
										I.addClass(thb[i], "selected");
									}
									else
									{
										I.removeClass(thb[i], "selected");
									}
								}
							}, // END OF _updatePaginator
		
		/**
		 * add link
		 * @param {[type]} img [description]
		 */
		_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

	nodes = I.query(".gcb_container");

	for(i = 0, li = nodes.length; i < li; ++i)
	{
		cur = nodes[i];
		if(!I.hasClass(cur, "bannerImage"))
		{
			b = new Banner(cur);
		}
	}

}());

