// Thumbnails module for Slider Pro.
// 
// Adds the possibility to create a thumbnail scroller, each thumbnail
// corresponding to a slide.
;(function( window, $ ) {

	"use strict";

	var NS = 'Thumbnails.' + $.SliderPro.namespace;

	var Thumbnails = {

		// Reference to the thumbnail scroller 
		$thumbnails: null,

		// Reference to the container of the thumbnail scroller
		$thumbnailsContainer: null,

		// List of Thumbnail objects
		thumbnails: null,

		// Index of the selected thumbnail
		selectedThumbnailIndex: 0,

		// Total size (width or height, depending on the orientation) of the thumbnails
		thumbnailsSize: 0,

		// Size of the thumbnail's container
		thumbnailsContainerSize: 0,

		// The position of the thumbnail scroller inside its container
		thumbnailsPosition: 0,

		// Orientation of the thumbnails
		thumbnailsOrientation: null,

		// Indicates the 'left' or 'top' position based on the orientation of the thumbnails
		thumbnailsPositionProperty: null,

		// Indicates if there are thumbnails in the slider
		isThumbnailScroller: false,

		initThumbnails: function() {
			var that = this;

			this.thumbnails = [];

			this.on( 'update.' + NS, $.proxy( this._thumbnailsOnUpdate, this ) );
			this.on( 'sliderResize.' + NS, $.proxy( this._thumbnailsOnResize, this ) );
			this.on( 'gotoSlide.' + NS, function( event ) {
				that._gotoThumbnail( event.index );
			});
		},

		// Called when the slider is updated
		_thumbnailsOnUpdate: function() {
			var that = this;

			if ( this.$slider.find( '.sp-thumbnail' ).length === 0 && this.thumbnails.length === 0 ) {
				this.isThumbnailScroller = false;
				return;
			}

			this.isThumbnailScroller = true;

			// Create the container of the thumbnail scroller, if it wasn't created yet
			if ( this.$thumbnailsContainer === null ) {
				this.$thumbnailsContainer = $( '<div class="sp-thumbnails-container"></div>' ).insertAfter( this.$slidesContainer );
			}

			// If the thumbnails' main container doesn't exist, create it, and get a reference to it
			if ( this.$thumbnails === null ) {
				if ( this.$slider.find( '.sp-thumbnails' ).length !== 0 ) {
					this.$thumbnails = this.$slider.find( '.sp-thumbnails' ).appendTo( this.$thumbnailsContainer );

					// Shuffle/randomize the thumbnails
					if ( this.settings.shuffle === true ) {
						var thumbnails = this.$thumbnails.find( '.sp-thumbnail' ),
							shuffledThumbnails = [];

						// Reposition the thumbnails based on the order of the indexes in the
						// 'shuffledIndexes' array
						$.each( this.shuffledIndexes, function( index, element ) {
							var $thumbnail = $( thumbnails[ element ] );

							if ( $thumbnail.parent( 'a' ).length !== 0 ) {
								$thumbnail = $thumbnail.parent( 'a' );
							}

							shuffledThumbnails.push( $thumbnail );
						});
						
						// Append the sorted thumbnails to the thumbnail scroller
						this.$thumbnails.empty().append( shuffledThumbnails ) ;
					}
				} else {
					this.$thumbnails = $( '<div class="sp-thumbnails"></div>' ).appendTo( this.$thumbnailsContainer );
				}
			}

			// Check if there are thumbnails inside the slides and move them in the thumbnails container
			this.$slides.find( '.sp-thumbnail' ).each( function( index ) {
				var $thumbnail = $( this ),
					thumbnailIndex = $thumbnail.parents( '.sp-slide' ).index(),
					lastThumbnailIndex = that.$thumbnails.find( '.sp-thumbnail' ).length - 1;

				if ( $thumbnail.parent( 'a' ).length !== 0 ) {
					$thumbnail = $thumbnail.parent( 'a' );
				}

				// If the index of the slide that contains the thumbnail is greater than the total number
				// of thumbnails from the thumbnails container, position the thumbnail at the end.
				// Otherwise, add the thumbnails at the corresponding position.
				if ( thumbnailIndex > lastThumbnailIndex ) {
					$thumbnail.appendTo( that.$thumbnails );
				} else {
					$thumbnail.insertBefore( that.$thumbnails.find( '.sp-thumbnail' ).eq( thumbnailIndex ) );
				}
			});

			// Loop through the Thumbnail objects and if a corresponding element is not found in the DOM,
			// it means that the thumbnail might have been removed. In this case, destroy that Thumbnail instance.
			for ( var i = this.thumbnails.length - 1; i >= 0; i-- ) {
				if ( this.$thumbnails.find( '.sp-thumbnail[data-index="' + i + '"]' ).length === 0 ) {
					var thumbnail = this.thumbnails[ i ];

					thumbnail.destroy();
					this.thumbnails.splice( i, 1 );
				}
			}

			// Loop through the thumbnails and if there is any uninitialized thumbnail,
			// initialize it, else update the thumbnail's index.
			this.$thumbnails.find( '.sp-thumbnail' ).each(function( index ) {
				var $thumbnail = $( this );

				if ( typeof $thumbnail.attr( 'data-init' ) === 'undefined' ) {
					that._createThumbnail( $thumbnail, index );
				} else {
					that.thumbnails[ index ].setIndex( index );
				}
			});

			// Remove the previous class that corresponds to the position of the thumbnail scroller
			this.$thumbnailsContainer.removeClass( 'sp-top-thumbnails sp-bottom-thumbnails sp-left-thumbnails sp-right-thumbnails' );

			// Check the position of the thumbnail scroller and assign it the appropriate class and styling
			if ( this.settings.thumbnailsPosition === 'top' ) {
				this.$thumbnailsContainer.addClass( 'sp-top-thumbnails' );
				this.thumbnailsOrientation = 'horizontal';
			} else if ( this.settings.thumbnailsPosition === 'bottom' ) {
				this.$thumbnailsContainer.addClass( 'sp-bottom-thumbnails' );
				this.thumbnailsOrientation = 'horizontal';
			} else if ( this.settings.thumbnailsPosition === 'left' ) {
				this.$thumbnailsContainer.addClass( 'sp-left-thumbnails' );
				this.thumbnailsOrientation = 'vertical';
			} else if ( this.settings.thumbnailsPosition === 'right' ) {
				this.$thumbnailsContainer.addClass( 'sp-right-thumbnails' );
				this.thumbnailsOrientation = 'vertical';
			}

			// Check if the pointer needs to be created
			if ( this.settings.thumbnailPointer === true ) {
				this.$thumbnailsContainer.addClass( 'sp-has-pointer' );
			} else {
				this.$thumbnailsContainer.removeClass( 'sp-has-pointer' );
			}

			// Mark the thumbnail that corresponds to the selected slide
			this.selectedThumbnailIndex = this.selectedSlideIndex;
			this.$thumbnails.find( '.sp-thumbnail-container' ).eq( this.selectedThumbnailIndex ).addClass( 'sp-selected-thumbnail' );
			
			// Calculate the total size of the thumbnails
			this.thumbnailsSize = 0;

			$.each( this.thumbnails, function( index, thumbnail ) {
				thumbnail.setSize( that.settings.thumbnailWidth, that.settings.thumbnailHeight );
				that.thumbnailsSize += that.thumbnailsOrientation === 'horizontal' ? thumbnail.getSize().width : thumbnail.getSize().height;
			});

			// Set the size of the thumbnails
			if ( this.thumbnailsOrientation === 'horizontal' ) {
				this.$thumbnails.css({ 'width': this.thumbnailsSize, 'height': this.settings.thumbnailHeight });
				this.$thumbnailsContainer.css( 'height', '' );
				this.thumbnailsPositionProperty = 'left';
			} else {
				this.$thumbnails.css({ 'width': this.settings.thumbnailWidth, 'height': this.thumbnailsSize });
				this.$thumbnailsContainer.css( 'width', '' );
				this.thumbnailsPositionProperty = 'top';
			}

			// Fire the 'thumbnailsUpdate' event
			this.trigger({ type: 'thumbnailsUpdate' });
			if ( $.isFunction( this.settings.thumbnailsUpdate ) ) {
				this.settings.thumbnailsUpdate.call( this, { type: 'thumbnailsUpdate' } );
			}
		},

		// Create an individual thumbnail
		_createThumbnail: function( element, index ) {
			var that = this,
				thumbnail = new Thumbnail( element, this.$thumbnails, index );

			// When the thumbnail is clicked, navigate to the corresponding slide
			thumbnail.on( 'thumbnailClick.' + NS, function( event ) {
				that.gotoSlide( event.index );
			});

			// Add the thumbnail at the specified index
			this.thumbnails.splice( index, 0, thumbnail );
		},

		// Called when the slider is resized.
		// Resets the size and position of the thumbnail scroller container.
		_thumbnailsOnResize: function() {
			if ( this.isThumbnailScroller === false ) {
				return;
			}

			var that = this,
				newThumbnailsPosition;

			if ( this.thumbnailsOrientation === 'horizontal' ) {
				this.thumbnailsContainerSize = Math.min( this.$slidesMask.width(), this.thumbnailsSize );
				this.$thumbnailsContainer.css( 'width', this.thumbnailsContainerSize );

				// Reduce the slide mask's height, to make room for the thumbnails
				if ( this.settings.forceSize === 'fullWindow' ) {
					this.$slidesMask.css( 'height', this.$slidesMask.height() - this.$thumbnailsContainer.outerHeight( true ) );

					// Resize the slides
					this.slideHeight = this.$slidesMask.height();
					this._resizeSlides();

					// Re-arrange the slides
					this._resetSlidesPosition();
				}
			} else if ( this.thumbnailsOrientation === 'vertical' ) {

				// Check if the width of the slide mask plus the width of the thumbnail scroller is greater than
				// the width of the slider's container and if that's the case, reduce the slides container width
				// in order to make the entire slider fit inside the slider's container.
				if ( this.$slidesMask.width() + this.$thumbnailsContainer.outerWidth( true ) > this.$slider.parent().width() ) {
					// Reduce the slider's width, to make room for the thumbnails
					if ( this.settings.forceSize === 'fullWidth' || this.settings.forceSize === 'fullWindow' ) {
						this.$slider.css( 'max-width', $( window ).width() - this.$thumbnailsContainer.outerWidth( true ) );
					} else {
						this.$slider.css( 'max-width', this.$slider.parent().width() - this.$thumbnailsContainer.outerWidth( true ) );
					}
					
					this.$slidesMask.css( 'width', this.$slider.width() );

					// If the slides are vertically oriented, update the width and height (to maintain the aspect ratio)
					// of the slides.
					if ( this.settings.orientation === 'vertical' ) {
						this.slideWidth = this.$slider.width();

						this._resizeSlides();
					}

					// Re-arrange the slides
					this._resetSlidesPosition();
				}

				this.thumbnailsContainerSize = Math.min( this.$slidesMask.height(), this.thumbnailsSize );
				this.$thumbnailsContainer.css( 'height', this.thumbnailsContainerSize );
			}

			// If the total size of the thumbnails is smaller than the thumbnail scroller' container (which has
			// the same size as the slides container), it means that all the thumbnails will be visible, so set
			// the position of the thumbnail scroller to 0.
			// 
			// If that's not the case, the thumbnail scroller will be positioned based on which thumbnail is selected.
			if ( this.thumbnailsSize <= this.thumbnailsContainerSize || this.$thumbnails.find( '.sp-selected-thumbnail' ).length === 0 ) {
				newThumbnailsPosition = 0;
			} else {
				newThumbnailsPosition = Math.max( - this.thumbnails[ this.selectedThumbnailIndex ].getPosition()[ this.thumbnailsPositionProperty ], this.thumbnailsContainerSize - this.thumbnailsSize );
			}

			// Add a padding to the slider, based on the thumbnail scroller's orientation, to make room
			// for the thumbnails.
			if ( this.settings.thumbnailsPosition === 'top' ) {
				this.$slider.css({ 'paddingTop': this.$thumbnailsContainer.outerHeight( true ), 'paddingLeft': '', 'paddingRight': '' });
			} else if ( this.settings.thumbnailsPosition === 'bottom' ) {
				this.$slider.css({ 'paddingTop': '', 'paddingLeft': '', 'paddingRight': '' });
			} else if ( this.settings.thumbnailsPosition === 'left' ) {
				this.$slider.css({ 'paddingTop': '', 'paddingLeft': this.$thumbnailsContainer.outerWidth( true ), 'paddingRight': '' });
			} else if ( this.settings.thumbnailsPosition === 'right' ) {
				this.$slider.css({ 'paddingTop': '', 'paddingLeft': '', 'paddingRight': this.$thumbnailsContainer.outerWidth( true ) });
			}

			this._moveThumbnailsTo( newThumbnailsPosition, true );
		},

		// Selects the thumbnail at the indicated index and moves the thumbnail scroller
		// accordingly.
		_gotoThumbnail: function( index ) {
			if ( this.isThumbnailScroller === false || typeof this.thumbnails[ index ] === 'undefined' ) {
				return;
			}

			var previousIndex = this.selectedThumbnailIndex,
				newThumbnailsPosition = this.thumbnailsPosition;

			this.selectedThumbnailIndex = index;

			// Set the 'selected' class to the appropriate thumbnail
			this.$thumbnails.find( '.sp-selected-thumbnail' ).removeClass( 'sp-selected-thumbnail' );
			this.$thumbnails.find( '.sp-thumbnail-container' ).eq( this.selectedThumbnailIndex ).addClass( 'sp-selected-thumbnail' );

			// Calculate the new position that the thumbnail scroller needs to go to.
			// 
			// If the selected thumbnail has a higher index than the previous one, make sure that the thumbnail
			// that comes after the selected thumbnail will be visible, if the selected thumbnail is not the
			// last thumbnail in the list.
			// 
			// If the selected thumbnail has a lower index than the previous one, make sure that the thumbnail
			// that's before the selected thumbnail will be visible, if the selected thumbnail is not the
			// first thumbnail in the list.
			if ( this.settings.rightToLeft === true && this.thumbnailsOrientation === 'horizontal' ) {
				if ( this.selectedThumbnailIndex >= previousIndex ) {
					var rtlNextThumbnailIndex = this.selectedThumbnailIndex === this.thumbnails.length - 1 ? this.selectedThumbnailIndex : this.selectedThumbnailIndex + 1,
						rtlNextThumbnail = this.thumbnails[ rtlNextThumbnailIndex ];

					if ( rtlNextThumbnail.getPosition().left < - this.thumbnailsPosition ) {
						newThumbnailsPosition = - rtlNextThumbnail.getPosition().left;
					}
				} else if ( this.selectedThumbnailIndex < previousIndex ) {
					var rtlPreviousThumbnailIndex = this.selectedThumbnailIndex === 0 ? this.selectedThumbnailIndex : this.selectedThumbnailIndex - 1,
						rtlPreviousThumbnail = this.thumbnails[ rtlPreviousThumbnailIndex ],
						rtlThumbnailsRightPosition = - this.thumbnailsPosition + this.thumbnailsContainerSize;

					if ( rtlPreviousThumbnail.getPosition().right > rtlThumbnailsRightPosition ) {
						newThumbnailsPosition = this.thumbnailsPosition - ( rtlPreviousThumbnail.getPosition().right - rtlThumbnailsRightPosition );
					}
				}
			} else {
				if ( this.selectedThumbnailIndex >= previousIndex ) {
					var nextThumbnailIndex = this.selectedThumbnailIndex === this.thumbnails.length - 1 ? this.selectedThumbnailIndex : this.selectedThumbnailIndex + 1,
						nextThumbnail = this.thumbnails[ nextThumbnailIndex ],
						nextThumbnailPosition = this.thumbnailsOrientation === 'horizontal' ? nextThumbnail.getPosition().right : nextThumbnail.getPosition().bottom,
						thumbnailsRightPosition = - this.thumbnailsPosition + this.thumbnailsContainerSize;

					if ( nextThumbnailPosition > thumbnailsRightPosition ) {
						newThumbnailsPosition = this.thumbnailsPosition - ( nextThumbnailPosition - thumbnailsRightPosition );
					}
				} else if ( this.selectedThumbnailIndex < previousIndex ) {
					var previousThumbnailIndex = this.selectedThumbnailIndex === 0 ? this.selectedThumbnailIndex : this.selectedThumbnailIndex - 1,
						previousThumbnail = this.thumbnails[ previousThumbnailIndex ],
						previousThumbnailPosition = this.thumbnailsOrientation === 'horizontal' ? previousThumbnail.getPosition().left : previousThumbnail.getPosition().top;

					if ( previousThumbnailPosition < - this.thumbnailsPosition ) {
						newThumbnailsPosition = - previousThumbnailPosition;
					}
				}
			}

			// Move the thumbnail scroller to the calculated position
			this._moveThumbnailsTo( newThumbnailsPosition );

			// Fire the 'gotoThumbnail' event
			this.trigger({ type: 'gotoThumbnail' });
			if ( $.isFunction( this.settings.gotoThumbnail ) ) {
				this.settings.gotoThumbnail.call( this, { type: 'gotoThumbnail' });
			}
		},

		// Move the thumbnail scroller to the indicated position
		_moveThumbnailsTo: function( position, instant, callback ) {
			var that = this,
				css = {};

			// Return if the position hasn't changed
			if ( position === this.thumbnailsPosition ) {
				return;
			}

			this.thumbnailsPosition = position;

			// Use CSS transitions if they are supported. If not, use JavaScript animation
			if ( this.supportedAnimation === 'css-3d' || this.supportedAnimation === 'css-2d' ) {
				var transition,
					left = this.thumbnailsOrientation === 'horizontal' ? position : 0,
					top = this.thumbnailsOrientation === 'horizontal' ? 0 : position;

				if ( this.supportedAnimation === 'css-3d' ) {
					css[ this.vendorPrefix + 'transform' ] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
				} else {
					css[ this.vendorPrefix + 'transform' ] = 'translate(' + left + 'px, ' + top + 'px)';
				}

				if ( typeof instant !== 'undefined' && instant === true ) {
					transition = '';
				} else {
					this.$thumbnails.addClass( 'sp-animated' );
					transition = this.vendorPrefix + 'transform ' + 700 / 1000 + 's';

					this.$thumbnails.on( this.transitionEvent, function( event ) {
						if ( event.target !== event.currentTarget ) {
							return;
						}

						that.$thumbnails.off( that.transitionEvent );
						that.$thumbnails.removeClass( 'sp-animated' );

						if ( typeof callback === 'function' ) {
							callback();
						}

						// Fire the 'thumbnailsMoveComplete' event
						that.trigger({ type: 'thumbnailsMoveComplete' });
						if ( $.isFunction( that.settings.thumbnailsMoveComplete ) ) {
							that.settings.thumbnailsMoveComplete.call( that, { type: 'thumbnailsMoveComplete' });
						}
					});
				}

				css[ this.vendorPrefix + 'transition' ] = transition;

				this.$thumbnails.css( css );
			} else {
				css[ 'margin-' + this.thumbnailsPositionProperty ] = position;

				if ( typeof instant !== 'undefined' && instant === true ) {
					this.$thumbnails.css( css );
				} else {
					this.$thumbnails
						.addClass( 'sp-animated' )
						.animate( css, 700, function() {
							that.$thumbnails.removeClass( 'sp-animated' );

							if ( typeof callback === 'function' ) {
								callback();
							}

							// Fire the 'thumbnailsMoveComplete' event
							that.trigger({ type: 'thumbnailsMoveComplete' });
							if ( $.isFunction( that.settings.thumbnailsMoveComplete ) ) {
								that.settings.thumbnailsMoveComplete.call( that, { type: 'thumbnailsMoveComplete' });
							}
						});
				}
			}
		},

		// Stop the movement of the thumbnail scroller
		_stopThumbnailsMovement: function() {
			var css = {};

			if ( this.supportedAnimation === 'css-3d' || this.supportedAnimation === 'css-2d' ) {
				var	matrixString = this.$thumbnails.css( this.vendorPrefix + 'transform' ),
					matrixType = matrixString.indexOf( 'matrix3d' ) !== -1 ? 'matrix3d' : 'matrix',
					matrixArray = matrixString.replace( matrixType, '' ).match( /-?[0-9\.]+/g ),
					left = matrixType === 'matrix3d' ? parseInt( matrixArray[ 12 ], 10 ) : parseInt( matrixArray[ 4 ], 10 ),
					top = matrixType === 'matrix3d' ? parseInt( matrixArray[ 13 ], 10 ) : parseInt( matrixArray[ 5 ], 10 );

				if ( this.supportedAnimation === 'css-3d' ) {
					css[ this.vendorPrefix + 'transform' ] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
				} else {
					css[ this.vendorPrefix + 'transform' ] = 'translate(' + left + 'px, ' + top + 'px)';
				}

				css[ this.vendorPrefix + 'transition' ] = '';

				this.$thumbnails.css( css );
				this.$thumbnails.off( this.transitionEvent );
				this.thumbnailsPosition = this.thumbnailsOrientation === 'horizontal' ? parseInt( matrixArray[ 4 ] , 10 ) : parseInt( matrixArray[ 5 ] , 10 );
			} else {
				this.$thumbnails.stop();
				this.thumbnailsPosition = parseInt( this.$thumbnails.css( 'margin-' + this.thumbnailsPositionProperty ), 10 );
			}

			this.$thumbnails.removeClass( 'sp-animated' );
		},

		// Destroy the module
		destroyThumbnails: function() {
			var that = this;

			// Remove event listeners
			this.off( 'update.' + NS );

			if ( this.isThumbnailScroller === false ) {
				return;
			}
			
			this.off( 'sliderResize.' + NS );
			this.off( 'gotoSlide.' + NS );
			$( window ).off( 'resize.' + this.uniqueId + '.' + NS );

			// Destroy the individual thumbnails
			this.$thumbnails.find( '.sp-thumbnail' ).each( function() {
				var $thumbnail = $( this ),
					index = parseInt( $thumbnail.attr( 'data-index' ), 10 ),
					thumbnail = that.thumbnails[ index ];

				thumbnail.off( 'thumbnailClick.' + NS );
				thumbnail.destroy();
			});

			this.thumbnails.length = 0;

			// Add the thumbnail scroller directly in the slider and
			// remove the thumbnail scroller container
			this.$thumbnails.appendTo( this.$slider );
			this.$thumbnailsContainer.remove();
			
			// Remove any created padding
			this.$slider.css({ 'paddingTop': '', 'paddingLeft': '', 'paddingRight': '' });
		},

		thumbnailsDefaults: {

			// Sets the width of the thumbnail
			thumbnailWidth: 100,

			// Sets the height of the thumbnail
			thumbnailHeight: 80,

			// Sets the position of the thumbnail scroller (top, bottom, right, left)
			thumbnailsPosition: 'bottom',

			// Indicates if a pointer will be displayed for the selected thumbnail
			thumbnailPointer: false,

			// Called when the thumbnails are updated
			thumbnailsUpdate: function() {},

			// Called when a new thumbnail is selected
			gotoThumbnail: function() {},

			// Called when the thumbnail scroller has moved
			thumbnailsMoveComplete: function() {}
		}
	};

	var Thumbnail = function( thumbnail, thumbnails, index ) {

		// Reference to the thumbnail jQuery element
		this.$thumbnail = thumbnail;

		// Reference to the thumbnail scroller
		this.$thumbnails = thumbnails;

		// Reference to the thumbnail's container, which will be 
		// created dynamically.
		this.$thumbnailContainer = null;

		// The width and height of the thumbnail
		this.width = 0;
		this.height = 0;

		// Indicates whether the thumbnail's image is loaded
		this.isImageLoaded = false;

		// Set the index of the slide
		this.setIndex( index );

		// Initialize the thumbnail
		this._init();
	};

	Thumbnail.prototype = {

		_init: function() {
			var that = this;

			// Mark the thumbnail as initialized
			this.$thumbnail.attr( 'data-init', true );

			// Create a container for the thumbnail and add the original thumbnail to this container.
			// Having a container will help crop the thumbnail image if it's too large.
			this.$thumbnailContainer = $( '<div class="sp-thumbnail-container"></div>' ).appendTo( this.$thumbnails );

			if ( this.$thumbnail.parent( 'a' ).length !== 0 ) {
				this.$thumbnail.parent( 'a' ).appendTo( this.$thumbnailContainer );
			} else {
				this.$thumbnail.appendTo( this.$thumbnailContainer );
			}

			// When the thumbnail container is clicked, fire an event
			this.$thumbnailContainer.on( 'click.' + NS, function() {
				that.trigger({ type: 'thumbnailClick.' + NS, index: that.index });
			});
		},

		// Set the width and height of the thumbnail
		setSize: function( width, height ) {
			this.width = width;
			this.height = height;

			// Apply the width and height to the thumbnail's container
			this.$thumbnailContainer.css({ 'width': this.width, 'height': this.height });

			// If there is an image, resize it to fit the thumbnail container
			if ( this.$thumbnail.is( 'img' ) && typeof this.$thumbnail.attr( 'data-src' ) === 'undefined' ) {
				this.resizeImage();
			}
		},

		// Return the width and height of the thumbnail
		getSize: function() {
			return {
				width: this.$thumbnailContainer.outerWidth( true ),
				height: this.$thumbnailContainer.outerHeight( true )
			};
		},

		// Return the top, bottom, left and right position of the thumbnail
		getPosition: function() {
			return {
				left: this.$thumbnailContainer.position().left + parseInt( this.$thumbnailContainer.css( 'marginLeft' ) , 10 ),
				right: this.$thumbnailContainer.position().left + parseInt( this.$thumbnailContainer.css( 'marginLeft' ) , 10 ) + this.$thumbnailContainer.outerWidth(),
				top: this.$thumbnailContainer.position().top + parseInt( this.$thumbnailContainer.css( 'marginTop' ) , 10 ),
				bottom: this.$thumbnailContainer.position().top + parseInt( this.$thumbnailContainer.css( 'marginTop' ) , 10 ) + this.$thumbnailContainer.outerHeight()
			};
		},

		// Set the index of the thumbnail
		setIndex: function( index ) {
			this.index = index;
			this.$thumbnail.attr( 'data-index', this.index );
		},

		// Resize the thumbnail's image
		resizeImage: function() {
			var that = this;

			// If the image is not loaded yet, load it
			if ( this.isImageLoaded === false ) {
				SliderProUtils.checkImagesComplete( this.$thumbnailContainer , function() {
					that.isImageLoaded = true;
					that.resizeImage();
				});

				return;
			}

			// Get the reference to the thumbnail image again because it was replaced by
			// another img element during the loading process
			this.$thumbnail = this.$thumbnailContainer.find( '.sp-thumbnail' );

			// Calculate whether the image should stretch horizontally or vertically
			var imageWidth = this.$thumbnail.width(),
				imageHeight = this.$thumbnail.height();

			if ( imageWidth / imageHeight <= this.width / this.height ) {
				this.$thumbnail.css({ width: '100%', height: 'auto' });
			} else {
				this.$thumbnail.css({ width: 'auto', height: '100%' });
			}

			this.$thumbnail.css({ 'marginLeft': ( this.$thumbnailContainer.width() - this.$thumbnail.width() ) * 0.5, 'marginTop': ( this.$thumbnailContainer.height() - this.$thumbnail.height() ) * 0.5 });
		},

		// Destroy the thumbnail
		destroy: function() {
			this.$thumbnailContainer.off( 'click.' + NS );

			// Remove added attributes
			this.$thumbnail.removeAttr( 'data-init' );
			this.$thumbnail.removeAttr( 'data-index' );

			// Remove the thumbnail's container and add the thumbnail
			// back to the thumbnail scroller container
			if ( this.$thumbnail.parent( 'a' ).length !== 0 ) {
				this.$thumbnail.parent( 'a' ).insertBefore( this.$thumbnailContainer );
			} else {
				this.$thumbnail.insertBefore( this.$thumbnailContainer );
			}
			
			this.$thumbnailContainer.remove();
		},

		// Attach an event handler to the slide
		on: function( type, callback ) {
			return this.$thumbnailContainer.on( type, callback );
		},

		// Detach an event handler to the slide
		off: function( type ) {
			return this.$thumbnailContainer.off( type );
		},

		// Trigger an event on the slide
		trigger: function( data ) {
			return this.$thumbnailContainer.triggerHandler( data );
		}
	};

	$.SliderPro.addModule( 'Thumbnails', Thumbnails );

})( window, jQuery );