var Carrousel = function() {this.initialize.apply(this, arguments)}
Carrousel.prototype = {
	constructor : Carrousel.constructor,
	
	//options : 
	options : {
		parent : null, //element parent (peut être un id)
		depth : 4,
		toolbarClass : 'toolbar',
		nextButtonClass : 'next',
		prevButtonClass : 'prev',
		descriptionClass : 'text',
		itemsContainerClass : 'items',
		itemClass : 'item',
		props : [], //propriétés qui permettent de placer les images visibles correctement;
		centerProp : {w:226, y:5}, //z definira aussi le nombre d'elements qui seronts affichés
		itemDepth : 4, //nombre d'éléments qu'on affiche dans le fond à partir du premier element`
		startingItem : 3
	},
	
	
	//privates vars : On ne peut pas les declarer en private, mais on fait comme si c'etait des privates
	_parent : null, //parent de l'application
	_itemsContainer : null, //container des items
	_items : [], //liste des items (images) a afficher
	_currentIndex : -1, //item selectionne
	_firstStart : true,
	_animating : false, //booleen à true quand l'animation est lancee. Passe à false sur la callback de l'animation
	
	initialize : function(parentElement, options) {
		var z = this._z;
		options = options || {};
		this._setOptions(options);
		this.options.parent = z.$(parentElement);
		this._parent = this.options.parent;
		this._generateProps();
		this._itemsContainer = z.getNode(this._parent, '*', this.options.itemsContainerClass);
		this._parent.className+=' carrouselHasJS';
		this._toolbar = z.getNode(this._parent, 'div', 'toolbar');
		this._description = z.getNode(this._toolbar, 'div', this.options.descriptionClass);
		this._descriptionHTMLTemplate = this._description.innerHTML;
		this._initItems();
		this._initListeners();
		this.goto(this.options.startingItem);
		this._firstStart = false;
	},
	
	_initListeners : function() {
		var z = this._z;
		var toolbar = this._toolbar;
		var prevButton = z.getNode(toolbar, 'a', this.options.prevButtonClass);
		z.addEvent(prevButton, 'click', z.bind(this, this.prevButtonClickHandler));
		var nextButton = z.getNode(toolbar, 'a', this.options.nextButtonClass);
		z.addEvent(nextButton, 'click', z.bind(this, this.nextButtonClickHandler));
	},
	
	prevButtonClickHandler : function(e) {
		this._z.stopEvent(e);
		this.prev();
	},
	nextButtonClickHandler : function(e) {
		this._z.stopEvent(e);
		this.next();
	},
	itemClickHandler : function(e) {
		var clickedElement = this._z.getSrc(e);
	
		var item = clickedElement;
		while(!item.className.match(/item/))
			item = item.parentNode;
		
		if (item._index != this._currentIndex) {
			this.goto(item._index);
			this._z.stopEvent(e);
		} else {
			if (this._animating)
				this._z.stopEvent(e);
		}
		
	},
	
	_generateProps : function() {
		var props = [];
		var o = this.options;
		var depth = o.itemDepth;
		props[o.itemDepth*2] = null;
		var width = this._parent.offsetWidth;
		var height = this._parent.offsetHeight;
		var x = (width-o.centerProp.w)/2;
		var w = o.centerProp.w;
		var y = 5;
		props[o.itemDepth] = {
			w:o.centerProp.w,
			x:x,
			y:y,
			z:o.itemDepth+1
		}
		var l = o.itemDepth;
		
		while(l--) {
			var p = (depth-l);
			
			w = l==0 ? 0 : parseInt((w*0.7));
			x = parseInt((x-w/2)*0.8);
			props[l] = {
				w:w,
				x:x,
				z:l+1
			}
			props[props.length-1-l] = {};
			for (var i in props[l]) {
				props[props.length-1-l][i] = props[l][i];
			}
			props[props.length-1-l].x = width-props[l].w-props[l].x;
		}
	
		o.props = props;
	},
	
	
	// functions for changing current selected image
	next : function() {
		this.goto(this._currentIndex+1);
	},
	prev : function() {
		this.goto(this._currentIndex-1);
	},
	goto : function(index) {
		if(index<0)
			index=0;
		if(index>this._items.length-1)
			index=this._items.length-1;
		if(this._currentIndex==index)
			return;
		
		if (this._firstStart || Math.abs(this._currentIndex - index)==1) {
			if(this._firstStart) {
				for (var i=0; i<this._items.length; i++) {
					this._setItemProperties(this._items[i], i<this._currentIndex ? 0 : this.options.props.length-1);
				}
			} else 
				this._animating = true
			this._gotoOneStep(index);
		}
		else 
			this._gotoMultipleSteps(index);
	},
	
	_gotoOneStep : function(index) {
		this._currentIndex = index;
		this._drawItems();
		this._showCurrentItemDescription();
	},
	
	_gotoMultipleSteps : function(index) {
		var _this = this;
		var _multiplesStepNumber = Math.abs(this._currentIndex-index);
		var direction = index-this._currentIndex;
		var i=0;
		while(_multiplesStepNumber>i) {
			setTimeout(function() {
				direction>0 ? _this.next() : _this.prev();
			},100*i)
			i++;
		}
	},
	
	_drawItems : function() {
		var mid = parseInt(this.options.props.length/2);
		for (var i=0; i<this.options.props.length; i++) {
			var itemIndex = i+this._currentIndex-mid;
			if(itemIndex>=0 && itemIndex<this._items.length) {
				var item = this._items[itemIndex];
				this._setItemProperties(item, i);
			}
		}
	},
	
	_getItemImage : function(item) {
		return this._z.getNode(item, 'img');
	},
	
	_setItemProperties : function(item, propsIndex) {
		var _this = this;
		var props = this.options.props[propsIndex];
		var itemH = props.w/item._ratio;
	//	var itemY = (this._itemsContainer.offsetHeight-itemH);
		
		
		if (this._firstStart) {
			item.style.width = props.w + 'px';
			item.style.zIndex = props.z;
			item.style.top = (this._itemsContainer.offsetHeight-item._image.offsetHeight)/2+5 + 'px';
			item.style.left = props.x + 'px';
			if(item._reflect) item._reflect.style.height = item.offsetWidth/item._reflectRatio + 'px';
			item.style.height = itemH + 'px';
		} else {
			item.style.zIndex = props.z;
			bytefx.move(
				item,
				{x:props.x},
				10
			)
			bytefx.size(item,{width:props.w},10, function() {
				_this._animating = false;
			}, function(el) {
				if (el._reflect) el._reflect.style.height = el.offsetWidth/el._reflectRatio + 'px';
				el.style.height = el.offsetWidth/el._ratio + 'px';
				el.style.top = (_this._itemsContainer.offsetHeight-el._image.offsetHeight)/2+5 + 'px';
			});
		}
	},
	_removeItems : function() {
		while(this._itemsContainer.childNodes.length>0)
			this._itemsContainer.removeChild(this._itemsContainer.firstChild);
	},
	_initItems : function() {
		this._items = this._getItems(this._itemsContainer);
		var centerWidth = this.options.props
		for (var i=0; i<this._items.length; i++) {
			var it = this._items[i];
			it._index = i;
			this._itemsContainer.appendChild(it);
			it.style.width = this.options.centerProp.w;
			var img = this._getItemImage(it);
			var canvasHeight = 0.3;
			it._image = this._getItemImage(it);
			it._reflect = Reflection.add(this._getItemImage(it), { height: canvasHeight, opacity:0.3});
			if (it._reflect) it._reflectRatio = it._reflect.offsetWidth/it._reflect.offsetHeight;
			it.style.height = img.offsetHeight + img.offsetHeight*canvasHeight + 'px';
			it.style.overflow = 'hidden';
			it._ratio = it.offsetWidth/it.offsetHeight;
			this._setItemProperties(it, 0);
			this._z.addEvent(it, 'click', this._z.bind(this, this.itemClickHandler), true);
		}
	},
	_getItems : function(itemsContainer) {
		var aReturn = [];
		while(itemsContainer.childNodes.length>0) {
			var item = itemsContainer.removeChild(itemsContainer.firstChild);
			if (item.nodeType==1) {
				var str = this._descriptionHTMLTemplate;
				var templateClassNames = str.match(/__([a-z0-9]+)__/gi);
				for (var c=0; c<templateClassNames.length; c++) {
					var tmpNode = this._z.getNode(item, '*', templateClassNames[c].replace(/__/g,''));
					var str = str.replace(new RegExp(templateClassNames[c],'g'), tmpNode ? tmpNode.innerHTML : '');
				}
				//this._description.innerHTML = str;
				item._description = str;
				aReturn.push(item);
			}
		}
		return aReturn;
	},
	
	_showCurrentItemDescription : function() {
		this._description.innerHTML = this._items[this._currentIndex]._description;
	},
	
	_setOptions : function(options){
		for (var i in options)
			this.options[i] = options[i];
	},
	
	_z : {
		$:function(el) {
			return typeof el=='string' ? document.getElementById(el) : el;
		},
		addEvent : function(obj, type, fn, bubble) {
		  if ( obj.attachEvent ) {
		    obj['e'+type+fn] = fn;
		    obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
		    obj.attachEvent( 'on'+type, obj[type+fn] );
		  } else
		    obj.addEventListener( type, fn, true );
		},
		stopEvent : function(e) {
			if(e && e.stopPropagation && e.preventDefault) {
				e.stopPropagation();
				e.preventDefault();
			}
			else if(e && window.event) {
				window.event.cancelBubble = true;
				window.event.returnValue = false;
			}
		},
		getSrc: function(e) {
			return (e.target || e.srcElement);
		},
		getRelTarget: function(e) {
			switch(e.type) {
				case 'mouseover': // Retourne l'element precedent le survol de l'element source de l'evenement
					return FW.Node.get((e.relatedTarget || e.fromElement)).fireEvent('relTargetRegister');
				case 'mouseout': // Retourne l'element sur lequel on entre une fois qu'on a quitte l'element source de l'evenement
					return FW.Node.get((e.relatedTarget || e.toElement)).fireEvent('relTargetRegister');
			}
		},
		bind : function(objectToBind, method) {
			return function() {
				method.apply(objectToBind,arguments);
			}
		},
		
		getNode : function(parentEl, nodeName, className) {
			return this.getNodes(parentEl, nodeName, className)[0];
		},
		
		getNodes : function(parentEl, nodeName, className) {
			var aReturnEl = [];
			var elements = parentEl.getElementsByTagName(nodeName);
			if (className && !className.match(/^\s+$/))
			{
				className = " "+className+" ";
				for (var i=0; i<elements.length; i++) {
					var el = elements[i];
					var c = " "+el.className+" ";
					if(c.indexOf(className)!=-1) {
						aReturnEl.push(el);
					}
				}
			}
			else 
			{
				for (var i=0; i<elements.length; i++) 
					aReturnEl.push(elements[i]);
			}
			return aReturnEl;
		}
	}
	
}

Carrousel.addOnLoad = function(func) {
	Carrousel.prototype._z.addEvent(window, 'load', func);
}



//bytefx 0.4 patched 
/* this version of byte fx is patched for using onMotion event, and move and size are patched, color, alpha are removed */
bytefx = new function(){

	// public methods
	this.clear = function(element){
		var	interval = ["size", "scroll", "move", "fade", "color"],
			index = interval.length;
		while(index--)
			clearInterval($element(element).bytefx[interval[index]]);
	};

	this.move = function(element, position, speed, callback, onMotion){
		var	start = bytefx.$position($element(element));
		$setInterval(element, "move", speed / 100, start, position, ["x", "y"], "position", callback, onMotion);
	};

	this.position = function(element, position){
		var	style = $element(element).style;
		style.position = "absolute";
		if(!isNaN(position.x)) style.left = position.x + "px";
		if(!isNaN(position.y)) style.top = position.y + "px";
	};

	this.size = function(element, size, speed, callback, onMotion){
		var	start = bytefx.$size($element(element)),
			tmp = w.opera;
		if(!/msie/i.test(navigator.userAgent) || (tmp && parseInt(tmp.version()) >= 9)){
			if(size.$width)
				start.width -= size.$width;
			if(size.$height)
				start.height -= size.$height;
			if(size.width$)
				size.width -= size.width$;
			if(size.height$)
				size.height -= size.height$;
		};
		element.style.overflow = "hidden";
		$setInterval(element, "size", speed / 100, start, size, ["width", "height"], "size$", callback, onMotion);
	};


	// extra public methods, used by bytefx but maybe useful for other scripts too

	this.$event = function(element, tmp, callback){
		var	value = element[tmp];
		element[tmp] = function(evt){
			if(!evt)
				evt = w.event;
			if(value)
				value.call(this, evt);
			return callback.call(this, evt);
		};
	};


	this.$position = function(element){
		var	position = {x:element.offsetLeft, y:element.offsetTop};
		while(element = element.offsetParent){
			position.x += element.offsetLeft;
			position.y += element.offsetTop;
		};
		return position;
	};

	this.$size = function(element){
		return {width:element.offsetWidth, height:element.offsetHeight};
	};


	this.size$ = function(element, size){
		var	style = element.style;
		if(!isNaN(size.width)) style.width = size.width + "px";
		if(!isNaN(size.height)) style.height = size.height + "px";
	};


	// private methods, used inside other public methods
	function $callback(element, interval, callback){
		clearInterval(element.bytefx[interval]);
		if(callback)
			callback.call(element);
	};

	function $element(element){
		if(!element.bytefx)
			element.bytefx = {color:0, drag:{}, fade:0, move:0, scroll:0, size:0};
		return element;
	};


	function $end(x, y, speed){
		return x < y ? min(x + speed, y) : max(x - speed, y);
	};

	/**
	 * private method,
         * 	[virtual scope]$setInterval(element:Object, intervalName:String, speed:Number, startValues:Object, endValues:Object, propertiesName:Array, methodName:String[, finalCallback:Function]):Void
	 */
	function $setInterval(element, interval, speed, start, position, style, tmp, callback, onMotion){
		clearInterval(element.bytefx[interval]);
		onMotion = onMotion!=null ? onMotion : function(){};
		element.bytefx[interval] = setInterval(function(){
			start[style[0]] += (position[style[0]] - start[style[0]]) * speed;
			start[style[1]] += (position[style[1]] - start[style[1]]) * speed;
			bytefx[tmp](element, start);
			onMotion(element);
			if(round(start[style[0]]) == position[style[0]]){
				bytefx[tmp](element, position);
				$callback(element, interval, callback);
			}
		}, 1);
	};
	
	var	w = window,
		d = document,
		max = Math.max,
		min = Math.min,
		round = Math.round;
};


/**
 * reflection.js v2.0
 * http://cow.neondragon.net/stuff/reflection/
 * Freely distributable under MIT-style license.
 */
 

var Reflection = {
	defaultHeight : 0.5,
	defaultOpacity: 0.5,
	
	add: function(image, options) {
		Reflection.remove(image);
		
		var doptions = { "height" : Reflection.defaultHeight, "opacity" : Reflection.defaultOpacity }
		if (options) {
			for (var i in doptions) {
				if (!options[i]) {
					options[i] = doptions[i];
				}
			}
		} else {
			options = doptions;
		}
	
		try {
			var d = document.createElement('div');
			var p = image;
			
			var classes = p.className.split(' ');
			var newClasses = '';
			for (var j=0;j<classes.length;j++) {
				if (classes[j] != "reflect") {
					if (newClasses) {
						newClasses += ' '
					}
					newClasses += classes[j];
				}
			}

			var reflectionHeight = Math.floor(p.height*options['height']);
			var divHeight = Math.floor(p.height*(1+options['height']));
			
			var reflectionWidth = p.width;
			
			if (document.all && !window.opera) {
				// Fix hyperlinks 
                if(p.parentElement.tagName == 'A') {
	                var d = document.createElement('a');
	                d.href = p.parentElement.href;
			 	} 
				/* Copy original image's classes & styles to div */
				d.className = newClasses;
			//	alert(d.style.he)
				p.className += ' reflected';
				
				d.style.cssText = p.style.cssText;
				p.style.cssText = 'vertical-align: bottom';
			
				var reflection = document.createElement('img');
				reflection.src = p.src;
				reflection.style.width = '100%'; //reflectionWidth+'px';
				reflection.style.display = 'block';
				reflection.style.height = p.clientHeight+"px";
				
			
				reflection.style.marginBottom = "-"+(p.height-reflectionHeight)+'px';
				reflection.style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity='+(options['opacity']*100)+', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+(options['height']*100)+')';
				
				d.style.width = '100%'; //reflectionWidth+'px';
				d.style.height = divHeight+'px';
				p.parentNode.replaceChild(d, p);
				d.style.height = '';
				d.appendChild(p);
				d.appendChild(reflection);
				
				return reflection;
			} else {
				var canvas = document.createElement('canvas');
				if (canvas.getContext) {
					/* Copy original image's classes & styles to div */
					d.className = newClasses;
					p.className += ' reflected';
					
					d.style.cssText = p.style.cssText;
					p.style.cssText = 'vertical-align: bottom';
			
					var context = canvas.getContext("2d");
					canvas.style.height = reflectionHeight+'px';
					canvas.style.width = reflectionWidth+'px';
					canvas.height = reflectionHeight;
					canvas.width = reflectionWidth;
					
					d.style.width = '100%'; //reflectionWidth+'px';
					//d.style.height = divHeight+'px';
					p.parentNode.replaceChild(d, p);
					
					d.appendChild(p);
					d.appendChild(canvas);
					
					context.save();
					
					context.translate(0,image.height-1);
					context.scale(1,-1);
					
					context.drawImage(image, 0, 0, reflectionWidth, image.height);
	
					context.restore();
					
					context.globalCompositeOperation = "destination-out";
					var gradient = context.createLinearGradient(0, 0, 0, reflectionHeight);
					
					gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
					gradient.addColorStop(0, "rgba(255, 255, 255, "+(1-options['opacity'])+")");
		
					context.fillStyle = gradient;
					context.rect(0, 0, reflectionWidth, reflectionHeight*2);
					context.fill();
					canvas.style.width = '100%';
					//canvas.style.height = '10%';
					
					return canvas;
				}
			}
			
			
		} catch (e) {
	    }
	},
	
	remove : function(image) {
		if (image.className == "reflected") {
			image.className = image.parentNode.className;
			image.parentNode.parentNode.replaceChild(image, image.parentNode);
		}
	}
}

function trace(){
	if(window.console)
		console.log.apply(console, arguments);
} 
