// JavaScript Document
(function($) { 


function ImageCube() {
	this._defaults = {
		direction: 'random', // Sens de la rotation: Aléatoire/Haut|Bas|Gauche|Droite
		randomSelection: ['up', 'down', 'left', 'right'], // Si la direction est aléatoire, 
		//la méthode random renvoie un élément du tabaleau ci-dessus. 
		speed: 2000, // Vitesse de transition entre chaque face (Exprimée en millième de secondes)
		easing: 'linear', // Effet utilisé pour la transition
		repeat: true, // Appelle une nouvelle transition après chaque pause
		pause: 2000, // Millièmes de secondes entre chaque transitions
		selection: 'forward', // Système de sélection de la prochaine transition
			// 'forward', 'backward', 'random'
		shading: true, // Optimisation de l'effect
		opacity: 0.8, // Transparence maximale pour les ombres
		imagePath: '', // Chemin des images sélectionnées
		full3D: true, // True pour l'ajout de perspective (Effet 3 D), false pour une "rotation à plat" (Effet 2D)
		segments: 20, // Nombre de segments composant chaque face du cube
		reduction: 30, // Le nombre de pixels à soustraire pour les bordures les plus éloignées du cube
		expansion: 10, // Le nombre de pixels à ajouter pour les bordures les plus proches du cube
		lineHeight: [0.0, 1.25], 
		letterSpacing: [-0.4, 0.0], 
		beforeRotate: null, // Evénement pour appel de fonction avant la rotation
		afterRotate: null // Evénement pour appel de fonction après la rotation
	};
};

//Variables de direction
var UP = 0;
var DOWN = 1;
var LEFT = 2;
var RIGHT = 3;

var PROP_NAME = 'imageCube';

$.extend(ImageCube.prototype, {
	/* Classe ajoutée aux élements du DOM utilisant la fonction. */
	markerClassName: 'hasImageCube',

	/* Permet le surclassement des options */
	setDefaults: function(options) {
		extendRemove(this._defaults, options || {});
	},

	/* Liaison des fonctionnalités à une DIV*/
	_attachImageCube: function(target, options) {
		target = $(target);
		if (target.hasClass(this.markerClassName)) {
			return;
		}
		var allOptions = $.extend({_position: target.css('position')},
			this._defaults, options || {});
		$.data(target[0], PROP_NAME, allOptions);
		target.addClass(this.markerClassName).css({position: 'relative'}).
			children().each(function() {
				var child = $(this);
				$.data(this, PROP_NAME,
					{width: child.css('width'), height: child.css('height'),
					position: child.css('position'), lineHeight: child.css('lineHeight'),
					letterSpacing: child.css('letterSpacing')});
				child.css({width: target.css('width'), height: target.css('height'),
					position: 'absolute', lineHeight: allOptions.lineHeight[1],
					letterSpacing: allOptions.letterSpacing[1]});
			}).not(':first').hide();
		this._prepareRotation(target[0]);
	},

	/* Enregistre la face courante du cube pour planifier la transition suivant
	les options directionnelles choisies */
	_prepareRotation: function(target) {
		target = $(target);
		target.children('.imageCubeShading,.imageCubeFrom,.imageCubeTo').remove();
		var options = $.data(target[0], PROP_NAME);
		options.current = target.children(':visible')[0];
		var randomSelection = function(collection) {
			return (!collection.length ? collection : collection.filter(
				':eq(' + Math.floor(Math.random() * collection.length) + ')'));
		};
		options.next = (options.selection == 'random' ?
			randomSelection(target.children(':hidden')) :
			(options.selection == 'backward' ? $(options.current).prev() :
			$(options.current).next()));
		options.next = (options.next.length ? options.next :
			(options.selection == 'random' ? options.current :
			(options.selection == 'backward' ? target.children(':last') :
			target.children(':first'))))[0]; 
		if (options.repeat && !options._timer) {
			options._timer = setTimeout(function() {
					$.imagecube._rotateImageCube(target[0]); },
				options.pause);
		}
		$.data(target[0], PROP_NAME, options);
	},

	/* Rotation du cube*/
	_rotateImageCube: function(target, next, callback) {
		if (typeof next == 'function') {
			callback = next;
			next = '';
		}
		target = $(target);
		this._stopImageCube(target[0], true);
		var options = $.data(target[0], PROP_NAME);
		if (next != null) {
			next = (typeof next == 'number' ? target.children(':eq(' + next + ')') : $(next));
			if (target.children().filter(function() { return this === next[0]; }).length > 0) {
				options.next = next;
			}
		}
		var callbackArgs = [options.current, options.next];
		if (options.beforeRotate) {
			options.beforeRotate.apply(target[0], callbackArgs);
		}
		var animTo = {};
		animTo[PROP_NAME] = 1.0;
		target.attr(PROP_NAME, 0.0).animate(animTo, options.speed, options.easing,
			function() {
				if (options.afterRotate) {
					options.afterRotate.apply(target[0], callbackArgs);
				}
				if (callback) {
					callback.apply(target[0]);
				}
			});
	},

	/* Récupère l'image visible courante*/
	_currentImageCube: function(target) {
		return ($(target).hasClass(this.markerClassName) ?
			$.data(target, PROP_NAME).current : null);
	},

	/* Récupère la prochaine image*/
	_nextImageCube: function(target) {
		return ($(target).hasClass(this.markerClassName) ?
			$.data(target, PROP_NAME).next : null);
	},

	/* Arrêt de la rotation*/
	_stopImageCube: function(target, timerOnly) {
		var options = $.data(target, PROP_NAME);
		if (options._timer) {
			clearTimeout(options._timer);
			options._timer = null;
		}
		if (!timerOnly) {
			options.repeat = false;
		}
		$.data(target, PROP_NAME, options);
	},

	
	_startImageCube: function(target) {
		this._changeImageCube(target, {repeat: true});
	},

	_changeImageCube: function(target, options, value) {
		if (typeof options == 'string') {
			var opts = {};
			opts[options] = value;
			options = opts;
		}
		var curOptions = $.data(target, PROP_NAME);
		extendRemove(curOptions || {}, options || {});
		$.data(target, PROP_NAME, curOptions);
		this._prepareRotation(target);
	},

	/* Détachement de la div. Celle-ci affiche alors les images telles qu'elles ont été positionnées à la création. */
	_destroyImageCube: function(target) {
		target = $(target);
		if (!target.hasClass(this.markerClassName)) {
			return;
		}
		this._stopImageCube(target[0]);
		var options = $.data(target[0], PROP_NAME);
		target.stop().css({position: options._position}).
			removeClass(this.markerClassName).
			children('.imageCubeShading,.imageCubeFrom,.imageCubeTo').remove();
		target.children().each(function() {
			$(this).css($.data(this, PROP_NAME)).show();
			$.removeData(this, PROP_NAME);
		});
		$.removeData(target[0], PROP_NAME);
	},

	/* Construction de l'animation*/
	_prepareAnimation: function(target) {
		var options = $.data(target, PROP_NAME);
		var target = $(target);
		var offset = {left: 0, top: 0};
		target.parents().each(function() { 
			var $this = $(this);
			if ($this.css('position') == 'fixed') {
				offset.left -= $this.offset().left;
				offset.top -= $this.offset().top;
				return false;
			}
		});
		var dims = {width: target.width(), height: target.height()};
		var direction = (options.direction != 'random' ? options.direction :
			options.randomSelection[Math.floor(Math.random() * options.randomSelection.length)]);
		direction = Math.max(0, $.inArray(direction, ['up', 'down', 'left', 'right']));
		options._curDirection = direction;
		var upDown = (direction == UP || direction == DOWN);
		var leftRight = (direction == LEFT || direction == RIGHT);
		var upLeft = (direction == UP || direction == LEFT);
		var firstOpacity = (upLeft ? 0 : options.opacity);
		var pFrom = $(options.current);
		var pTo = $(options.next);
		
		var border = [];
		var parseBorders = function(p) {
			var b = [0, 0, 0, 0];
			if (!$.browser.msie || p.css('border')) {
				for (var i = 0; i < 4; i++) {
					b[i] = p.css('border' + ['Left', 'Right', 'Top', 'Bottom'][i] + 'Width');
					var extra = ($.browser.msie ? 1 : 0);
					b[i] = parseFloat(
						{thin: 1 + extra, medium: 3 + extra, thick: 5 + extra}[b[i]] || b[i]);
				}
			}
			return b;
		};
		border[0] = parseBorders(pFrom);
		border[1] = parseBorders(pTo);
		var pad = [];
		pad[0] = [parseFloat(pFrom.css('padding-left')), parseFloat(pFrom.css('padding-right')),
			parseFloat(pFrom.css('padding-top')), parseFloat(pFrom.css('padding-bottom'))];
		pad[1] = [parseFloat(pTo.css('padding-left')), parseFloat(pTo.css('padding-right')),
			parseFloat(pTo.css('padding-top')), parseFloat(pTo.css('padding-bottom'))];
		var extras = [];
		extras[0] = [($.boxModel ? border[0][0] + border[0][1] + pad[0][0] + pad[0][1] : 0),
			($.boxModel ? border[0][2] + border[0][3] + pad[0][2] + pad[0][3] : 0)];
		extras[1] = [($.boxModel ? border[1][0] + border[1][1] + pad[1][0] + pad[1][1] : 0),
			($.boxModel ? border[1][2] + border[1][3] + pad[1][2] + pad[1][3] : 0)];
		var stepProps = [];
		stepProps[0] = {elem: pFrom[0], 
			props: {left: {start: offset.left,
				end: offset.left + (direction == RIGHT ? dims.width : 0), units: 'px'},
			width: {start: dims.width - extras[0][0],
				end: (upDown ? dims.width - extras[0][0] : 0), units: 'px'},
			top: {start: offset.top,
				end: offset.top + (direction == DOWN ? dims.height : 0), units: 'px'},
			height: {start: dims.height - extras[0][1],
				end: (upDown ? 0 : dims.height - extras[0][1]), units: 'px'},
			paddingLeft: {start: pad[0][0], end: (leftRight ? 0 : pad[0][0]), units: 'px'},
			paddingRight: {start: pad[0][1], end: (leftRight ? 0 : pad[0][1]), units: 'px'},
			paddingTop: {start: pad[0][2], end: (upDown ? 0 : pad[0][2]), units: 'px'},
			paddingBottom: {start: pad[0][3], end: (upDown ? 0 : pad[0][3]), units: 'px'},
			borderLeftWidth: {start: border[0][0], end: (leftRight ? 0 : border[0][0]), units: 'px'},
			borderRightWidth: {start: border[0][1], end: (leftRight ? 0 : border[0][1]), units: 'px'},
			borderTopWidth: {start: border[0][2], end: (upDown ? 0 : border[0][2]), units: 'px'},
			borderBottomWidth: {start: border[0][3], end: (upDown ? 0 : border[0][3]), units: 'px'},
			lineHeight: {start: options.lineHeight[1],
				end: (upDown ? options.lineHeight[0] : options.lineHeight[1]), units: 'em'},
			letterSpacing: {start: options.letterSpacing[1],
				end: (upDown ? options.letterSpacing[1] : options.letterSpacing[0]), units: 'em'}}};
		stepProps[1] = {elem: pTo[0], 
			props: {left: {start: offset.left + (direction == LEFT ? dims.width : 0),
				end: offset.left, units: 'px'},
			width: {start: (upDown ? dims.width - extras[1][0] : 0),
				end: dims.width - extras[1][0], units: 'px'},
			top: {start: offset.top + (direction == UP ? dims.height : 0),
				end: offset.top, units: 'px'},
			height: {start: (upDown ? ($.browser.msie ? 1 : 0) : dims.height - extras[1][1]),
				end : dims.height - extras[1][1], units: 'px'},
			paddingLeft: {start: (leftRight ? 0 : pad[1][0]), end: pad[1][0], units: 'px'},
			paddingRight: {start: (leftRight ? 0 : pad[1][1]), end: pad[1][1], units: 'px'},
			paddingTop: {start: (upDown ? 0 : pad[1][2]), end: pad[1][2], units: 'px'},
			paddingBottom: {start: (upDown ? 0 : pad[1][3]), end: pad[1][3], units: 'px'},
			borderLeftWidth: {start: (leftRight ? 0 : border[1][0]), end: border[1][0], units: 'px'},
			borderRightWidth: {start: (leftRight ? 0 : border[1][1]), end: border[1][1], units: 'px'},
			borderTopWidth: {start: (upDown ? 0 : border[1][2]), end: border[1][2], units: 'px'},
			borderBottomWidth: {start: (upDown ? 0 : border[1][3]), end: border[1][3], units: 'px'},
			lineHeight: {start: (upDown ? options.lineHeight[0] : options.lineHeight[1]),
				end: options.lineHeight[1], units: 'em'},
			letterSpacing: {start: (upDown ? options.letterSpacing[1] : options.letterSpacing[0]),
				end: options.letterSpacing[1], units: 'em'}}};
		if (options.shading) {
			
			var setHighShad = function(props, startOpacity, endOpacity) {
				return {left: {start: props.left.start, end: props.left.end, units: 'px'},
					width: {start: props.width.start, end: props.width.end, units: 'px'},
					top: {start: props.top.start, end: props.top.end, units: 'px'},
					height: {start: props.height.start, end: props.height.end, units: 'px'},
					paddingLeft: {start: props.paddingLeft.start + props.borderLeftWidth.start,
						end: props.paddingLeft.end + props.borderLeftWidth.end, units: 'px'},
					paddingRight: {start: props.paddingRight.start + props.borderRightWidth.start,
						end: props.paddingRight.end + props.borderRightWidth.end, units: 'px'},
					paddingTop: {start: props.paddingTop.start + props.borderTopWidth.start,
						end: props.paddingTop.end + props.borderTopWidth.end, units: 'px'},
					paddingBottom: {start: props.paddingBottom.start + props.borderBottomWidth.start,
						end: props.paddingBottom.end + props.borderBottomWidth.end, units: 'px'},
					opacity: {start: startOpacity, end: endOpacity, units: ''}};
			};
			stepProps[2] = {elem:
				$(($.browser.msie ? '<img src="' + options.imagePath + 'imageCubeHigh.png"' :
				'<div') + ' class="imageCubeShading" style="background-color: white; opacity: ' +
				firstOpacity + '; z-index: 10; position: absolute;"' +
				($.browser.msie ? '/>' : '></div>'))[0],
				props: setHighShad(stepProps[upLeft ? 0 : 1].props,
				firstOpacity, options.opacity - firstOpacity)};
			stepProps[3] = {elem:
				$(($.browser.msie ? '<img src="' + options.imagePath + 'imageCubeShad.png"' :
				'<div') + ' class="imageCubeShading" style="background-color: black; opacity: ' +
				(options.opacity - firstOpacity) + '; z-index: 10; position: absolute;"' +
				($.browser.msie ? '/>' : '></div>'))[0],
				props: setHighShad(stepProps[upLeft ? 1 : 0].props,
				options.opacity - firstOpacity, firstOpacity)};
		}
		if (options.full3D) {
			for (var i = 0; i < options.segments; i++) {
				target.append(pFrom.clone().addClass('imageCubeFrom').
					css({display: 'block', position: 'absolute', overflow: 'hidden'}));
				if (options.shading) {
					target.append($(stepProps[upLeft ? 2 : 3].elem).clone());
				}
			}
			for (var i = 0; i < options.segments; i++) {
				target.append(pTo.clone().addClass('imageCubeTo').
					css({display: 'block', position: 'absolute', width: 0, overflow: 'hidden'}));
				if (options.shading) {
					target.append($(stepProps[upLeft ? 3 : 2].elem).clone());
				}
			}
			pFrom.hide();
			pTo.css({width: dims.width - extras[1][0], height: dims.height - extras[1][1]});
		}
		else {
			var initCSS = function(props) {
				return {left: props.left.start + 'px', width: props.width.start + 'px',
					top: props.top.start + 'px', height: props.height.start + 'px',
					lineHeight: props.lineHeight.start + 'em',
					padding: props.paddingTop.start + 'px ' + props.paddingRight.start + 'px ' +
					props.paddingBottom.start + 'px ' + props.paddingLeft.start + 'px',
					borderLeftWidth: props.borderLeftWidth.start + 'px',
					borderRightWidth: props.borderRightWidth.start + 'px',
					borderTopWidth: props.borderTopWidth.start + 'px',
					borderBottomWidth: props.borderBottomWidth.start + 'px',
					letterSpacing: props.letterSpacing.start + 'em', overflow: 'hidden'};
			};
			pFrom.css(initCSS(stepProps[0].props));
			pTo.css(initCSS(stepProps[1].props)).show();
			if (options.shading) {
				target.append(stepProps[2].elem).append(stepProps[3].elem);
			}
		}
		for (var i = 0; i < stepProps.length; i++) {
			for (var name in stepProps[i].props) {
				var prop = stepProps[i].props[name];
				prop.diff = prop.end - prop.start;
			}
		}
		return stepProps;
	},

	_drawFull3D: function(target, pos, stepProps) {
		var options = $.data(target, PROP_NAME);
		if (!options.full3D) {
			return false;
		}
		var target = $(target);
		var direction = options._curDirection;
		var upDown = (direction == UP || direction == DOWN);
		var upLeft = (direction == UP || direction == LEFT);
		var width = target.width();
		var height = target.height();
		if (width == 0 || height == 0) {
			return true;
		}
		var current = (1 - pos) * (upDown ? height : width);
		var segments = options.segments;
		var maxExpand = options.expansion * (1 - Math.abs(2 * current - (upDown ? height : width)) /
			(upDown ? height : width));
		var maxReduce = options.reduction - (options.reduction * current / (upDown ? height : width));
		var update = function(className, al, at, bl, bt, cl, ct, dl, dt, opacity, props, attr) {
			var ws = [bl - al, cl - dl];
			var w = Math.max(ws[0], ws[1]);
			var hs = [dt - at, ct - bt];
			var h = Math.max(hs[0], hs[1]);
			var wStep = (upDown ? (ws[0] - ws[1]) / (segments - 1) / 2 : w / segments);
			var hStep = (upDown ? h / segments : (hs[0] - hs[1]) / (segments - 1) / 2);
			var pbw = props.paddingLeft[attr] + props.paddingRight[attr] +
				props.borderLeftWidth[attr] + props.borderRightWidth[attr];
			var pbh = props.paddingTop[attr] + props.paddingBottom[attr] +
				props.borderTopWidth[attr] + props.borderBottomWidth[attr];
			var ral = Math.round(al);
			var rat = Math.round(at);
			var thisLeft = ral;
			var thisTop = rat;
			var i = 0;
			for (var j = 0; j < target[0].childNodes.length; j++) {
				var child = target[0].childNodes[j];
				if (child.className != className) {
					continue;
				}
				var nextLeft = Math.round(al + (i + 1) * wStep);
				var nextTop = Math.round(at + (i + 1) * hStep);
				var wCur = ws[0] - (upDown ? 2 * i * wStep : 0);
				var hCur = hs[0] - (upDown ? 0 : 2 * i * hStep);
				child.style.left = (upDown ? thisLeft : al) + 'px';
				child.style.top = (upDown ? at : thisTop) + 'px';
				child.style.width = Math.max(0, wCur - pbw) + 'px';
				child.style.height = Math.max(0, hCur - pbh) + 'px';
				child.style.letterSpacing = (upDown ? wCur / w * (options.letterSpacing[1] -
					options.letterSpacing[0]) + options.letterSpacing[0] :
					pos * props.letterSpacing.diff + props.letterSpacing.start) +
					props.letterSpacing.units;
				child.style.lineHeight = (!upDown ? hCur / h * (options.lineHeight[1] -
					options.lineHeight[0]) + options.lineHeight[0] :
					pos * props.lineHeight.diff + props.lineHeight.start) +
					props.lineHeight.units;
				child.style.clip = 'rect(' + (!upDown ? 'auto' : (thisTop - rat) + 'px') + ',' +
					(upDown ? 'auto' : (nextLeft - ral) + 'px') + ',' +
					(!upDown ? 'auto' : (nextTop - rat) + 'px') + ',' +
					(upDown ? 'auto' : (thisLeft - ral) + 'px') + ')';
				if (options.shading) {
					var shading = child.nextSibling;
					shading.style.left = thisLeft + 'px';
					shading.style.top = thisTop + 'px';
					shading.style.width = (upDown ? ws[0] - 2 * i * wStep : nextLeft - thisLeft) + 'px';
					shading.style.height = (upDown ? nextTop - thisTop : hs[0] - 2 * i * hStep) + 'px';
					shading.style.opacity = opacity;
					if ($.browser.msie) {
						shading.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
					}
				}
				thisLeft = nextLeft;
				thisTop = nextTop;
				i++;
			}
		};
		update('imageCubeFrom',
			[maxReduce, -maxExpand, 0, width - current][direction], 
			[0, height - current, maxReduce, -maxExpand][direction],
			[width - maxReduce, width + maxExpand, current, width][direction], 
			[0, height - current, -maxExpand, maxReduce][direction],
			[width + maxExpand, width - maxReduce, current, width][direction], 
			[current, height, height + maxExpand, height - maxReduce][direction],
			[-maxExpand, maxReduce, 0, width - current][direction], 
			[current, height, height - maxReduce, height + maxExpand][direction],
			(!options.shading ? 0 : (upLeft ? pos : 1 - pos) *
			stepProps[2].props.opacity.diff + stepProps[2].props.opacity.start),
			stepProps[0].props, 'start');
		update('imageCubeTo',
			[-maxExpand, options.reduction - maxReduce, current, 0][direction], 
			[current, 0, -maxExpand, options.reduction - maxReduce][direction],
			[width + maxExpand, width - (options.reduction - maxReduce), width, width - current][direction], 
			[current, 0, options.reduction - maxReduce, -maxExpand][direction],
			[width - (options.reduction - maxReduce), width + maxExpand, width, width - current][direction], 
			[height, height - current, height - (options.reduction - maxReduce), height + maxExpand][direction],
			[options.reduction - maxReduce, -maxExpand, current, 0][direction], // bottom left
			[height, height - current, height + maxExpand, height - (options.reduction - maxReduce)][direction],
			(!options.shading ? 0 : (upLeft ? pos : 1 - pos) *
			stepProps[3].props.opacity.diff + stepProps[3].props.opacity.start),
			stepProps[1].props, 'end');
		return true;
	}
});


function extendRemove(target, props) {
	$.extend(target, props);
	for (var name in props) {
		if (props[name] == null) {
			target[name] = null;
		}
	}
	return target;
}

$.fn.imagecube = function(options) {
	var otherArgs = Array.prototype.slice.call(arguments, 1);
	if (options == 'current' || options == 'next') {
		return $.imagecube['_' + options + 'ImageCube'].
			apply($.imagecube, [this[0]].concat(otherArgs));
	}
	return this.each(function() {
		if (typeof options == 'string') {
			$.imagecube['_' + options + 'ImageCube'].
				apply($.imagecube, [this].concat(otherArgs));
		}
		else {
			$.imagecube._attachImageCube(this, options);
		}
	});
};

$.fx.step[PROP_NAME] = function(fx) {
	if (fx.state == 0 || !fx.stepProps) { // Initialisation
		fx.start = 0.0;
		fx.end = 1.0;
		fx.stepProps = $.imagecube._prepareAnimation(fx.elem);
		var elem = fx.stepProps[0].elem;
		fx.saveCSS = {borderLeftWidth: elem.style.borderLeftWidth,
			borderRightWidth: elem.style.borderRightWidth,
			borderTopWidth: elem.style.borderTopWidth,
			borderBottomWidth: elem.style.borderBottomWidth,
			padding: elem.style.padding};
	}

	if (!$.imagecube._drawFull3D(fx.elem, fx.pos, fx.stepProps)) {
		for (var i = 0; i < fx.stepProps.length; i++) { 
			var comp = fx.stepProps[i];
			for (var name in comp.props) { 
				var prop = comp.props[name];
				comp.elem.style[name] = (fx.pos * prop.diff + prop.start) + prop.units;
				if ($.browser.msie && name == 'opacity') {
					comp.elem.style.filter = 'alpha(opacity=' +
						((fx.pos * prop.diff + prop.start) * 100) + ')';
				}
			}
		}
	}

	if (fx.state == 1) { 
		$(fx.stepProps[0].elem).hide().css(fx.saveCSS);
		$(fx.stepProps[1].elem).show();
		$.imagecube._prepareRotation(fx.elem);
	}
};

/* Initialisation d'une nouvelle instance de la fonction */
$.imagecube = new ImageCube(); 

})(jQuery);

