//The world's smallest jquery plugin
jQuery.fn.reverse = [].reverse;

(function($){  
	$.fn.gallery = function(options) {  

		var defaults = {
			displayDuration:    3000,
			initialState:       'play',
			showControls:       2,
			showThumbnails:     2,
			transitionType:     1,
			transitionDuration: 1000,
			autoStart:          true
		};
		var options = $.extend(defaults, options);

		return this.each(function() {
			var firstImage = $(this).find('img:first');
			var h          = firstImage.height();
			var w          = firstImage.width();

			galleryTransition($(this), options, firstImage.height(), firstImage.width());
		});  

		//Petit bricolage pour que ça fonctionne aussi dans IE7
		function absIE7(src) {
			var a = $('<a href="' + src + '" />');
			return a.attr('href');
		};

		function galleryTransition(gallery, options, h, w) {
			var transitionType = options.transitionType;
			var t;

			//Création d'un objet Transition du bon type en fonction des options
			var ie6 = $.browser.msie && $.browser.version == 6;
			var ie7 = $.browser.msie && $.browser.version == 7;
			var ie8 = $.browser.msie && $.browser.version == 8;
			/*
			 * Blacklist des transitions avec IE:
			 * Simple        OK
			 * UpDown        IE6 et IE7 marche pas > DownUp
			 * DownUp        OK
			 * Fade          IE6 clignotements bizarres mais OK
			 * LeftRight     OK
			 * RightLeft     OK
			 * Crush         IE6 marche pas > Simple
			 * Zoom          IE6 marche pas > Simple, IE7 et IE8 zoom bizarre mais OK
			 * Flash         OK
			 * FastRightLeft IE6 clignotements bizarres mais OK
			 * PhotoStack    IE6, IE7 et IE8 marchent pas > Simple
			 */
			if (transitionType == 0)
				t = new TransitionSimple(gallery, options, h, w);
			else if (transitionType == 1) {
				if (ie6 || ie7)
					t = new TransitionDownUp(gallery, options, h, w);
				else
					t = new TransitionUpDown(gallery, options, h, w);        
			} else if (transitionType == 2)
				t = new TransitionDownUp(gallery, options, h, w);
			else if (transitionType == 3)
				t = new TransitionFade(gallery, options, h, w);
			else if (transitionType == 4)
				t = new TransitionLeftRight(gallery, options, h, w);
			else if (transitionType == 5)
				t = new TransitionRightLeft(gallery, options, h, w);
			else if (transitionType == 6) {
				if (ie6)
					t = new TransitionSimple(gallery, options, h, w);
				else
					t = new TransitionCrush(gallery, options, h, w);
			} else if (transitionType == 7) {
				if (ie6)
					t = new TransitionSimple(gallery, options, h, w);
				else
					t = new TransitionZoom(gallery, options, h, w);
			} else if (transitionType == 8)
				t = new TransitionFlash(gallery, options, h, w);
			else if (transitionType == 9)
				t = new TransitionFastRightLeft(gallery, options, h, w);
			else if (transitionType == 10) {
				if (ie6 || ie7 || ie8)
					t = new TransitionSimple(gallery, options, h, w);
				else
					t = new TransitionPhotoStack(gallery, options, h, w);
			} else
				t = new TransitionSimple(gallery, options, h, w);
		};

		function Transition(gallery, options, h, w) {
			this.gallery            = gallery;
			this.galleryFrame       = gallery.parent();
			this.galleryIn          = gallery.find('.gallery-in');
			this.displayDuration    = options.displayDuration;
			this.transitionDuration = options.transitionDuration;
			this.state              = options.initialState;
			this.timer              = 0;
			this.isTransitionning   = false;

			this.currentSrc = ''; //src de l'image affichée pour le moment
			this.showControls = options.showControls;
			this.showThumbnails = options.showThumbnails;

			/*
			 * Zoom des galeries trop grandes au redimensionnement de la fenêtre
			 */
			this.zoomGallery = function(transition) {
				var galWidth  = transition.galleryFrame.width();
				var galHeight = transition.gallery.height();
				var parent    = transition.galleryFrame.parent();
				var parWidth  = parent.width();

				var display = transition.galleryFrame.css('display');
				if (galWidth >= parent.width()) {
					transition.galleryFrame.css('display', 'none');
					var maxWidth = parent.width();
					var zoom = (maxWidth-4)/galWidth;
					transition.gallery.css('-moz-transform', 'scale(' + zoom + ')');
					console.log(transition.gallery.height() * zoom);
					transition.galleryFrame.css('height', galHeight*zoom);
					transition.gallery.css('margin-bottom', '-' + galHeight*zoom);
					transition.galleryIn.css('margin-bottom', '-' + galHeight*zoom);
					transition.galleryIn.find('img').css('margin-bottom', '-' + galHeight*zoom);
				} else {
					transition.gallery.css('-moz-transform', 'scale(1)');
				}
				transition.galleryFrame.css('display', display);
			};

			/*
			 * Ajoute la barre de miniatures.
			 * Ajoute le SPAN avec les miniatures dedans, et met, en fonction du paramètre
			 * display, les évènements corrects pour afficher ou non la barre de
			 * miniatures au survol de la galerie par la souris.
			 */
			this.addThumbnails = function(display) {
				var width  = this.gallery.width();
				var height = this.gallery.height();
				var thumbHeight = 60;
				var thumbWidth  = Math.floor(thumbHeight/height * width);
				var thumbsHeight = thumbHeight;
				var thumbsWidth; //Calculé plus bas
				var thumbsMargin = 10;

				var that = this;

				//Ajout d'un SPAN pour les miniatures
				var thumbsSpan = $('<span class="gallery-thumbnails"><span class="gallery-thumbnails-mark" /></span>');
				if (display == 2)
					thumbsSpan.css('opacity', '0');
				this.gallery.append(thumbsSpan);

				//Ajout de miniatures dans ce SPAN,
				//Redimensionnement du SPAN et
				//Centrage du SPAN dans la galerie.
				thumbsWidth = 0;
				this.galleryIn.find('img').each(function(){
					var src = $(this).attr('src');
					var thumb = '<img src="' + src + '" height="' + thumbHeight + '" width="' + thumbWidth + '"/>';
					thumbsSpan.append(thumb);
					thumbsWidth++;
				});
				thumbsWidth *= thumbWidth;
				thumbsSpan.css('width', thumbsWidth+'px');
				var left = Math.round(width/2 - thumbsWidth/2);
				thumbsSpan.css('left', left+'px');

				//Ajout d'un évènement pour afficher les miniatures au survol
				if (display == 2) {
					this.gallery.hoverDelay(function(){
						thumbsSpan.animate({
							bottom: thumbsMargin + 'px',
							opacity: 1
						}, 'slow');
					}, function() {
						thumbsSpan.animate({
							bottom: '-' + (thumbsHeight + thumbsMargin) + 'px',
							opacity: 0
						}, 'slow');
					}, {inDelay: 250, outDelay: 250});
					//Ajout d'un évènement pour aligner les miniatures
					if ((width + 2*thumbsMargin) < thumbsWidth) {
						this.gallery.mousemove(function(e) {
							var mouseX = Math.round(e.clientX - $(this).offset().left);
							var delta = (mouseX - width / 2) / width;
							var left = thumbsMargin + Math.ceil((width - (thumbsWidth + 2*thumbsMargin))/2 - delta*Math.abs((thumbsWidth + 2*thumbsMargin) - width));
							thumbsSpan.css('left', left+'px');
						});
					}
				} else if (display == 1) {
					if ((width + 2*thumbsMargin) < thumbsWidth) {
						thumbsSpan.css('left', thumbsMargin);
						thumbsSpan.css('width', 'auto');
						var nbThumbs = thumbsSpan.find('img').size();
						thumbWidth = Math.floor((width - 2*thumbsMargin)/nbThumbs);
						thumbsSpan.find('img').css('width', thumbWidth);
						thumbHeight = (height/width)*thumbWidth;
						thumbsSpan.find('img').css('height', thumbHeight);
						thumbsSpan.css('height', thumbHeight);
					}
					thumbsSpan.animate({
						bottom: thumbsMargin + 'px'
					}, 'slow');
				}

				this.gallery.find('.gallery-thumbnails img').click(function() {
					if (!that.isTransitionning) {
						var src = $(this).attr('src');
						that.goToImage(src);
					}
				});
			};

			/*
			 * Ajoute la barre de contrôle.
			 * Ajoute le SPAN avec les contrôles dedans, et met, en fonction du paramètre
			 * display, les évènements corrects pour afficher ou non la barre de
			 * contrôle au survol de la galerie par la souris.
			 */
			this.addControls = function(display) {
				var controlsHeight = 20;
				var controlsMargin = 10;

				var that = this;

				//Ajout d'un SPAN pour les contrôles
				var controlsSpan = $('<span class="gallery-controls">'
				                  + '<span class="gallery-prev"></span>'
				                  + '<span class="gallery-play-pause"></span>'
				                  + '<span class="gallery-next"></span>'
				                  + '</span>');
				controlsSpan.css('opacity', '0');
				this.gallery.append(controlsSpan);

				//Ajout d'un évènement pour afficher les contrôles au survol
				if (display == 2) {
					this.gallery.hoverDelay(function(){
						controlsSpan.animate({
							top: controlsMargin + 'px',
							opacity: 1
						}, 'slow');
					}, function() {
						controlsSpan.animate({
							top: '-' + (controlsHeight + controlsMargin) + 'px',
							opacity: 0
						}, 'slow');
					}, {inDelay: 250, outDelay: 250});
				} else if (display == 1) {
					controlsSpan.animate({
						top: controlsMargin + 'px'
					}, 'slow');
				}

				//Évènements au clic sur les boutons
				this.gallery.find('.gallery-play-pause').click(function() {
					if (that.state == 'play') {
						that.pause();
					} else if (that.state == 'pause') {
						that.play();
					}
				});
				this.gallery.find('.gallery-prev').click(function() {
					if (!that.isTransitionning) {
						var oldState = that.state;
						that.pause();
						that.prev();
						if (oldState == 'play')
							that.play();
					}
				});
				this.gallery.find('.gallery-next').click(function() {
					if (!that.isTransitionning) {
						var oldState = that.state;
						that.pause();
						that.next();
						if (oldState == 'play')
							that.play();
					}
				});
			};

			/*
			 * Démarrage du défilement automatique des images
			 */
			this.play = function(){
				this.state = 'play';
				this.gallery.find('.gallery-play-pause').css('background-position', '-20px 0px');
				var that = this;
				this.timer = setInterval(function(){
					that.next();
				}, that.displayDuration + that.transitionDuration);
			};

			/*
			 * Arrêt du défilement automatique des images
			 */
			this.pause = function(){
				this.state = 'pause';
				this.gallery.find('.gallery-play-pause').css('background-position', '0px 0px');
				clearInterval(this.timer);
			};

			/*
			 * Va directement à une image déterminée par sa source
			 */
			this.goToImage = function(src){
				var oldState = this.state;
				if (src != this.currentSrc) {
					this.pause();
					this.change(src);
					this.currentSrc = src;
				}
				if (oldState == 'play')
					this.play();
			};

			this.next = function() {
				//Recherche de l'image suivante
				var nbImages = this.galleryIn.find('img').size();
				
				if (nbImages > 1) {
					var currentImage = this.galleryIn.find('img[src$="' + this.currentSrc + '"]');
					var nextImage = currentImage.next();
					if (nextImage.length == 0)
						nextImage = this.galleryIn.find('img').filter(':first');
					else
						nextImage = $(nextImage[0]);
				}

				this.change(nextImage.attr('src'));
				this.currentSrc = nextImage.attr('src');
			};

			this.prev = function() {
				//Recherche de l'image précédente
				var nbImages = this.galleryIn.find('img').size();

				if (nbImages > 1) {
					var currentImage = this.galleryIn.find('img[src$="' + this.currentSrc + '"]');
					var prevImage = currentImage.prev();
					if (prevImage.length == 0)
						prevImage = this.galleryIn.find('img').filter(':last');
					else
						prevImage = $(prevImage[0]);
				}

				this.change(prevImage.attr('src'));
				this.currentSrc = prevImage.attr('src');
			};

			/*
			 * Passe de la première image à la deuxième avec une transition.
			 * C'est la fonction à surcharger dans les sous-classes.
			 * @param toImageSrc src de l'image vers laquelle faire la transition
			 */
			this.change = function(toImageSrc) {};


			/*
			 * Met en valeur la miniature de l'image actuellement affichée
			 */  
			this.highLightThumb = function(thumbSrc) {
				if (this.showThumbnails) {
					var left = 0;
					thumbSrc = absIE7(thumbSrc);
					this.gallery.find('.gallery-thumbnails img').each(function() {
						var src = $(this).attr('src');
						if (src == thumbSrc) {
							$(this).addClass("active-thumb");
							left = $(this).position().left + $(this).width()/2 - 5;
						} else {
							$(this).removeClass("active-thumb");
						}
					});
					this.gallery.find('.gallery-thumbnails-mark').stop().animate({
						left: left
					}, Number(this.transitionDuration));
				}
			};

			/*
			 * Ajout des évènements onclick sur les images pour les actions
			 */
			this.addActions = function() {
				var that = this;
				this.gallery.find('img').each(function() {
					if ($(this).attr('rel') == 'next') {
						$(this).click(function() {
							if (!that.isTransitionning) {
								var oldState = that.state;
								that.pause();
								that.next();
								if (oldState == 'play')
									that.play();
							}
						});
					}
				});
			};

			var that = this;
			this.transitionBegins = function(toImageSrc) {
				this.isTransitionning = true;
				this.highLightThumb(toImageSrc);
				//that.galleryIn.find('img').css('image-rendering', 'optimizeSpeed');
			};
			this.transitionEnds = function() {
				this.isTransitionning = false;
				//that.galleryIn.find('img').css('image-rendering', 'optimizeQuality');
			};

			/*
			 * Constructeur.
			 * Placé à la fin pour que toutes les variables et méthodes aient bien été
			 * définies avant.
			 */  
			this.construct = function() {
				var that = this;
				
				if (this.showControls != '0')
					this.addControls(this.showControls);

				if (this.showThumbnails != '0')
					this.addThumbnails(this.showThumbnails);
				
				this.addActions();

				var firstImage = this.galleryIn.find('img:first');
				firstImage.css('display', 'inline-block');
				this.currentSrc = firstImage.attr('src');
				this.highLightThumb(this.currentSrc);
				if (this.state == 'play')
					this.play();
				else
					this.pause();

				this.zoomGallery(this);
				var that = this;
				$(window).resize(function() {
					that.zoomGallery(that)
				});
			};
			this.construct();
		}

		/*
		 * *** Définition des transitions ***
		 */

		function TransitionSimple(gallery, options, h, w) {
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display', 'none')
			                          .css('left', '0'); //IE < 8
			this.galleryIn.find('img:first').css('display', 'block');

			this.change = function(toImageSrc) {
				this.transitionBegins(toImageSrc);
				this.galleryIn.find('img').css('display', 'none');
				var imageToDisplay = this.galleryIn.find('img[src$="' + toImageSrc + '"]');
				imageToDisplay.css('display', 'block');
				this.transitionEnds();
			}
		}

		function TransitionFade(gallery, options, h, w) {
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display', 'none')
			                          .css('left', '0'); //IE < 8
			this.galleryIn.find('img:first').css('display', 'block');

			this.change = function(toImageSrc) {
				var that = this;
				var temp = $('<img src="' + this.currentSrc + '"/>');
				temp.css('position', 'absolute')
				    .css('display',  'block')
				    .css('left',     '0'); //IE < 8
				temp.appendTo(this.galleryIn).load(function() {
					var nbImages = that.galleryIn.find('img').size() - 1;
					var second   = that.galleryIn.find('img:first');
					var i = 0;
					while((absIE7(second.attr('src')) != toImageSrc) && i < nbImages) {
						var oldSecond = second;
						second = oldSecond.next();
						oldSecond.css('display', 'none');
						oldSecond.appendTo(that.galleryIn);
						i++;
					}
					second.css('position', 'absolute')
					      .css('opacity',  '1')
					      .css('display', 'block');

					that.transitionBegins(toImageSrc);

					temp.animate({
						opacity: 0
					}, {
						easing:   'easeInOutCubic',
						duration: Number(that.transitionDuration),
						complete: function(){
							temp.remove();
							that.transitionEnds();
						}
					});
				});
			}
		}

		function TransitionDownUp(gallery, options, h, w) {
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display',  'block')
			                          .css('position', 'relative')
			                          .css('margin',   '0')
			                          .css('padding',  '0');
			this.galleryIn.css('position', 'absolute')
			              .css('left', '0'); //IE < 8

			this.change = function(toImageSrc) {
				var nbImages = this.galleryIn.find('img').size();
				var imageToDisplay = this.galleryIn.find('img[src$="' + toImageSrc + '"]');
				var imageIndex = imageToDisplay.index();
				var topOffset = imageIndex*this.gallery.height();

				this.transitionBegins(toImageSrc);
				var that = this;

				this.galleryIn.animate({
					top: '-' + topOffset + 'px'
				}, {
					easing:   'easeInOutQuad',
					duration: Number(this.transitionDuration),
					complete: that.transitionEnds()
				});
			}
		}

		function TransitionUpDown(gallery, options, h, w) {
			this.inheritFrom = TransitionDownUp;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display',  'block')
			                          .css('position', 'relative')
			                          .css('margin',   '0')
			                          .css('padding',  '0');

			var that = this;
			this.galleryIn.find('img').each(function() {
				$(this).prependTo(that.galleryIn);
			});
			var next_ = this.next;
			this.next = this.prev;
			this.prev = next_;
			var nbImages = this.galleryIn.find('img').size();
			var topOffset = this.gallery.height()*(nbImages - 1);
			this.galleryIn.css('position', 'absolute');
			this.galleryIn.css('top', '-' + topOffset + 'px');
		}

		function TransitionRightLeft(gallery, options, h, w) {
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display',  'inline-block')
			                          .css('position', 'relative')
			                          .css('float',    'left')
			                          .css('margin',   '0')
			                          .css('padding',  '0');
			var nbImages = this.galleryIn.find('img').size();
			var width    = this.gallery.width()*(nbImages);
			this.galleryIn.css('position', 'absolute')
			              .css('width', width + 'px')
			              .css('left', '0'); //IE < 8

			this.change = function(toImageSrc) {
				var nbImages       = this.galleryIn.find('img').size();
				var imageToDisplay = this.galleryIn.find('img[src$="' + toImageSrc + '"]');
				var imageIndex     = imageToDisplay.index();
				var leftOffset     = imageIndex*this.gallery.width();

				this.transitionBegins(toImageSrc);
				var that = this;

				this.galleryIn.animate({
					left: '-' + leftOffset + 'px'
				}, {
					easing:   'easeInOutQuad',
					duration: Number(this.transitionDuration),
					complete: that.transitionEnds()
				});
			}
		}

		function TransitionLeftRight(gallery, options, h, w) {
			this.inheritFrom = TransitionRightLeft;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display',  'inline-block')
			                          .css('position', 'relative')
			                          .css('float',    'left')
			                          .css('margin',   '0')
			                          .css('padding',  '0');
			var that = this;
			this.galleryIn.find('img').each(function() {
				$(this).prependTo(that.galleryIn);
			});
			var next_ = this.next;
			this.next = this.prev;
			this.prev = next_;
			var nbImages = this.galleryIn.find('img').size();
			var width = this.gallery.width()*(nbImages);
			var leftOffset = this.gallery.width()*(nbImages - 1);
			this.galleryIn.css('position', 'absolute');
			this.galleryIn.css('width', width + 'px');
			this.galleryIn.css('left', '-' + leftOffset + 'px');
		}

		function TransitionCrush(gallery, options, h, w) {
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display', 'none')
			                          .css('left', '0'); //IE < 8
			this.galleryIn.find('img:first').css('display', 'inline-block');

			this.change = function(toImageSrc) {
				var that = this;
				var temp = $('<img src="' + this.currentSrc + '"/>');
				temp.css('position', 'absolute')
				    .css('display',  'inline-block')
				    .css('left', '0'); //IE < 8
				temp.appendTo(this.galleryIn).load(function() {
					var nbImages = that.galleryIn.find('img').size() - 1;
					var second   = that.galleryIn.find('img:first');
					var i = 0;
					while((absIE7(second.attr('src')) != toImageSrc) && i < nbImages) {
						var oldSecond = second;
						second = oldSecond.next();
						oldSecond.appendTo(that.galleryIn);
						oldSecond.css('display', 'none');
						i++;
					}
					second.css('position', 'absolute');
					second.css('top',      '0');
					second.css('height',   '0');
					second.css('display',  'inline-block');

					that.transitionBegins(toImageSrc);

					temp.animate({
						height: 0,
						width: w + 'px',
						top: h + 'px'
					}, {
						duration: Number(that.transitionDuration),
						complete: function(){
							temp.remove();
							that.transitionEnds();
						}
					});
					second.animate({
						height: h + 'px'
					}, {
						duration: Number(that.transitionDuration)
					});
				});
			}
		}

		function TransitionZoom(gallery, options, h, w) {
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display', 'none')
			                          .css('left', '0'); //IE < 8
			this.galleryIn.find('img:first').css('display', 'inline-block');

			this.change = function(toImageSrc) {
				var temp = $('<img src="' + this.currentSrc + '"/>');
				temp.css('position', 'absolute')
				    .css('display',  'inline-block');

				var that = this;
				temp.appendTo(this.galleryIn)
				    .css('position', 'absolute')
				    .css('display',  'inline-block')
				    .css('rotate',   '0deg')
				    .css('width',    w + 'px')
				    .css('height',   h + 'px');
				temp.load(function() {
					var nbImages = that.galleryIn.find('img').size() - 1;
					var second   = that.galleryIn.find('img:first');
					var i = 0;
					while((absIE7(second.attr('src')) != toImageSrc) && i < nbImages) {
						var oldSecond = second;
						second = oldSecond.next();
						oldSecond.appendTo(that.galleryIn);
						oldSecond.css('display', 'none');
						i++;
					}
					second.css('position', 'absolute')
								.css('display', 'inline-block')
								.css('left', '-' + w/2 + 'px')
								.css('top', '-' + h/2 + 'px')
								.css('width', w*2 + 'px')
								.css('height', h*2 + 'px');
					var r = '0deg';
					if (!$.browser.msie || $.browser.version > 8) {
						second.css('rotate', '-45deg');
						r = '45deg';
					}

					that.transitionBegins(toImageSrc);

					temp.animate({
						opacity: 0,
						width: 2*w,
						height: 2*h,
						left: '-' + w/2 + 'px',
						top: '-' + h/2 + 'px',
						rotate: r
					}, {
						easing:   'easeInOutCirc',
						duration: Number(that.transitionDuration),
						complete: function(){
							temp.remove();
							that.transitionEnds();
						}
					});
					second.animate({
						height: h + 'px',
						width: w + 'px',
						top: 0,
						left: 0,
						rotate: '0deg'
					}, {
						easing:   'easeInOutCirc',
						duration: Number(that.transitionDuration)
					});
				});
			}
		}

		function TransitionFlash(gallery, options, h, w) {
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display', 'none')
			                          .css('left', '0'); //IE < 8
			this.galleryIn.find('img:first').css('display', 'inline-block');

			this.change = function(toImageSrc) {
				var flash = $('<span>&nbsp;</span>');
				flash.appendTo(this.galleryIn);
				flash.css('background', 'white')
				     .css('position', 'absolute')
				     .css('display', 'inline-block')
				     .css('width', w + 'px')
				     .css('height', h + 'px')
				     .css('left', '0'); //IE < 8

				var nbImages = this.galleryIn.find('img').size() - 1;
				var second   = this.galleryIn.find('img:first');
				var i = 0;
				while((absIE7(second.attr('src')) != toImageSrc) && i < nbImages) {
					var oldSecond = second;
					second = oldSecond.next();
					oldSecond.appendTo(this.galleryIn);
					oldSecond.css('display', 'none');
					i++;
				}
				second.css('position', 'absolute');
				second.css('display',  'inline-block');

				this.transitionBegins(toImageSrc);
				var that = this;

				flash.animate({
					opacity: 0
				}, {
					easing:   'easeInOutCubic',
					duration: Number(this.transitionDuration),
					complete: function(){
						flash.remove();
						that.transitionEnds();
					}
				});
			}
		}

		function TransitionFastRightLeft(gallery, options, h, w) {
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('overflow', 'hidden');
			this.galleryIn.find('img').css('display', 'none')
			                          .css('left',    '0'); //IE < 8
			this.galleryIn.find('img:first').css('display', 'inline-block');

			this.change = function(toImageSrc) {
				var temp = $('<img src="' + this.currentSrc + '"/>');
				temp.css('position', 'absolute')
				    .css('display',  'inline-block')
				    .css('left', '0');
				var that = this;
				temp.appendTo(this.galleryIn) .load(function() {
					var nbImages = that.galleryIn.find('img').size() - 1;
					var second   = that.galleryIn.find('img:first');
					var i = 0;
					while((absIE7(second.attr('src')) != toImageSrc) && i < nbImages) {
						var oldSecond = second;
						second = oldSecond.next();
						oldSecond.appendTo(that.galleryIn);
						oldSecond.css('display', 'none');
						i++;
					}
					second.css('position', 'absolute');
					second.css('display', 'inline-block');
					second.css('left', w/10 + 'px');
					second.css('opacity', '1');

					that.transitionBegins(toImageSrc);

					temp.animate({
						left: '-' + w/20
					}, {
						easing:   'easeInQuad',
						duration: Number(that.transitionDuration) / 2,
						complete: function() {
							temp.animate({
								left:    '-' + w/10,
								opacity: 0
							}, {
								easing:   'easeInQuad',
								duration: Number(that.transitionDuration) / 2,
								complete: function() {
									temp.remove();
									that.transitionEnds();
								}
							});
						}
					});
					second.animate({
						left: w/20 + 'px'
					}, {
						easing:   'easeInQuad',
						duration: Number(that.transitionDuration) / 2,
						complete: function() {
							second.animate({
								left: 0
							}, {
								easing:   'easeInQuad',
								duration: Number(that.transitionDuration) / 2
							});
						}
					});
				});
			}
		}

		function TransitionPhotoStack(gallery, options, h, w) {
			var that = this;
			this.inheritFrom = Transition;
			this.inheritFrom(gallery, options, h, w);
			this.gallery.css('background', 'none');
			this.galleryIn.find('img').css('position', 'absolute')
			                          .css('display', 'inline-block');

			var next_ = this.next;
			this.next = this.prev;
			this.prev = next_;

			this.galleryIn.find('img').each(function() {
				var rotation = Math.floor(Math.random()*(20)) - 10;
				$(this).css('rotate', rotation + 'deg');
				$(this).prependTo(that.galleryIn);
			});

			this.change = function(toImageSrc) {
				var that = this;
				var nbImages = this.galleryIn.find('img').size();
				var imageToDisplay = this.galleryIn.find('img[src$="' + toImageSrc + '"]');
				var imageIndex = imageToDisplay.index();
				var invert = false;
				if (imageIndex > nbImages / 2)
					invert = true;

				var nbImagesToAnimate = 0;
				if (invert) {
					nbImagesToAnimate = nbImages - imageIndex - 1;
				} else {
					nbImagesToAnimate = imageIndex + 1;
				}

				this.transitionBegins(toImageSrc);
				var transitionFinished = 0;

				var allImages = this.galleryIn.find('img');
				if (invert)
					allImages = allImages.reverse();  

				allImages.each(function() {
					if (($(this).index() <= imageIndex && !invert) ||
							($(this).index() > imageIndex && invert)) {
						transitionFinished++;
						var angle1 = Math.floor(Math.random()*(20)) - 10;
						var angle2 = Math.floor(Math.random()*(20)) - 10;
						var angle3 = Math.floor(Math.random()*(360)) - 180;
						var leftOffset = (Math.cos(angle3))*w*1.5;
						var topOffset = (Math.sin(angle3))*h*1.5;
						$(this).delay((that.transitionDuration / 3) / (nbImagesToAnimate - 1) * transitionFinished).animate({
							left: leftOffset + 'px',
							top: topOffset + 'px',
							rotate: angle1 + 'deg'
						}, {
							duration: that.transitionDuration / 3,
							easing:   'easeInOutQuad',
							complete: function(){
								if (invert)
									$(this).prependTo(that.galleryIn);
								else
									$(this).appendTo(that.galleryIn);
								
								$(this).animate({
									left: '0px',
									top: '0px',
									rotate: angle2 + 'deg'
								}, {
									easing:   'easeInOutQuad',
									duration: that.transitionDuration / 3,
									complete: function() {
										transitionFinished--;
										if (transitionFinished == 0)
											that.transitionEnds();
									}
								});
							}
						});
					}
				});
			}
		}
	};  
})(jQuery);

