/*
	jQuery Scroll Gallery (jQuery 1.2.6 - 1.4.2)
	Version: 1.4
	Author:	Serega Tolmachyov (Fuse8 Online)
*/

(function($){
	$.fn.scrollGallery = function(options){
		var defaults = {
			rotatingSpeed: 600, // скорость вращения айтемов

			autoRotating: false, // включение автопрокрутки
			rotatingInterval: 8000, // интервал между автопрокруткой айтемов, если таковая включена

			loop: true, // можно ли прокручивать галерею к примеру на начало, если вы докрутили до конца и пытаетесь крутить далее

			containerClass: 'scroll-gallery',	// основной класс контейнера галереи
			additionalClass: '',

			createMainShadows: false, // создавать ли элементы для основной тени
			createClipShadows: false, // создавать ли элементы для тени clip'а
			mainShadowsClass: 's_gal_cont_sh', // класс для основной тени
			clipShadowsClass: 's_gal_clip_sh', // класс для тени clip'а

			buttonPrevClass: 'button-prev', // класс для кнопки Prev
			buttonNextClass: 'button-next', // класс для кнопки Next
			buttonPrevHTML: '<a href="#" onclick="return false"><span/></a>', // html для кнопки Prev
			buttonNextHTML: '<a href="#" onclick="return false"><span/></a>', // html для кнопки Next

			startItem: 1, // будем показывать галерею с этого айтема

			onComplete: null, // функция завершения создания галереи

			onRotationPrevCompleted: null, // функция завершения прокрутки галереи влево
			onRotationNextCompleted: null, // функция завершения прокрутки галереи вправо
			
			rewritingCloneLinkClass: null
		};


		// создаем галерею и заполняем ее свойствами
		var gallery = this;
		gallery.options = $.extend( {}, defaults, options );


		// говорим, что галерею можно вращать
		gallery.canAnimate = true;


		// делаем проверку, была ли уже создана галерея
		if (!gallery.hasClass(gallery.options.containerClass + '-completed'))
		{

			// проставляем дополнительный класс для галереи
			gallery.addClass(gallery.options.containerClass + '-completed');


			// выбираем все айтемы галереи и применяем к ним стили
			gallery.items = gallery.find('>li').css({
				listStyleType: 'none',
				float: 'left',
				margin: 0,
				border: 0
			});


			// задаем стили для картинок айтемов
			gallery.items.find('img').css({display: 'block'});


			// создаем буферный элемент, который будет проверять ширину дива Clip, который удаляется после вычисления ширины
			var bufferDiv = $('<div class="' + gallery.options.containerClass + '-clip"/>');
			gallery.before($('<div class="' + gallery.options.additionalClass + '" style="position:absolute;z-index:-1;left:0;top:-100px;width:0;height:0;overflow:hidden;"/>').append(bufferDiv));


			// задаем паузу, чтобы броузер успел нормально отрисовать элементы с примененными нами стилями
			setTimeout(function(){
				// функция вычисляет ширину галереи
				gallery.getGalleryWidth = function(){
					var width = 0;
					for (var i = 0; i < gallery.items.length; i++) width += gallery.items.eq(i).innerWidth();
					return width
				};

				// вычисляем ширину галереи
				var totalWidth = gallery.getGalleryWidth();

				// делаем проверку: если ширина всех айтемов галереи больше ширины Clip'a, то создаем галерею
				if (bufferDiv.width() < totalWidth)
				{
					// создаем таймер, по которому будут вращаться айтемы галереи
					gallery.timerRotating = null;
					// переменная, определяющая, находится ли курсор над галереей в данный момент
					gallery.hoverOnGallery = false;

					// добавляем внутренние методы
					$.extend(gallery,{
						getGalleryPosition: function(){
							return Math.abs(parseInt(this.css('marginLeft'),10))
						},
						getItemPosition: function(items, itemIndex){
							var itemPosition = 0;
							for (var i = 0; i < itemIndex; i++) itemPosition += items.eq(i).innerWidth();
							return itemPosition
						},
						showItem: function(itemNumber){
							var gallery = this;
							var items = gallery.find('>li');

							// проверка на минимальное/максимальное число. Делается, чтоб пользователь не ошибся в номере проставленного им айтема
							itemNumber = Math.max( Math.min(itemNumber, items.length) - 1, 0);

							// вычисляем айтем
							var item = items.eq(itemNumber);
							// вычисляем клон айтема
							var cloneItem = item[0].cloneItem;

							// функция проверяет, виден ли заданный айтем
							function itemVisibile(item)
							{
								var itemLeft = gallery.getItemPosition(items, items.index(item));
								var itemRight = itemLeft + item.innerWidth();

								var galleryLeft = gallery.getGalleryPosition();
								var galleryRight = galleryLeft + gallery.clip.innerWidth();

								if (itemLeft >= galleryLeft && itemRight <= galleryRight) return true;

								return false
							}

							function getItemParameters(item)
							{
								var galleryLeft = gallery.getGalleryPosition();

								var itemOptions = {};
								var itemLeft = gallery.getItemPosition(items, items.index(item));
								var itemRight = itemLeft + item.innerWidth();

								if (itemLeft < galleryLeft)
								{
									itemOptions.left = itemLeft;
									itemOptions.difference = Math.abs(itemOptions.left - galleryLeft)
								} else if (itemRight > galleryLeft + gallery.clip.width())
								{
									itemOptions.left = itemRight - gallery.clip.width();
									itemOptions.difference = Math.abs(itemRight - galleryLeft - gallery.clip.width())
								}

								return itemOptions
							}

							// если у данного айтема есть клон и этот клон не последний (вдруг у клипа есть паддинг), то можно на него крутить
							if (cloneItem && gallery.allItems.index(cloneItem.prev()) != -1 && gallery.allItems.index(cloneItem.next()) != -1)
							{
								// если хотя бы один айтем виден полностью, то не нужно ничего прокручивать, иначе...
								
								if ( !itemVisibile(item) && !itemVisibile(cloneItem) )
								{
									var needPosition = getItemParameters( (getItemParameters(item).difference < getItemParameters(cloneItem).difference ? item : cloneItem) ).left;
									gallery.galleryAnimate(-needPosition)
								}
							} else {
							// у айтема нет клона. Просматриваем, виден ли выбранный айтем
								if (!itemVisibile(item)) gallery.galleryAnimate(-getItemParameters(item).left)
							}
						},
						// устанавливаем таймер вращения айтемов
						setGalleryTimer: function(){
							if (!gallery.timerRotating)
								gallery.timerRotating = setInterval(function(){
									gallery.next()
								}, gallery.options.rotatingInterval)
						},
						// удаляем таймер вращения айтемов
						removeGalleryTimer: function(){
							if (gallery.timerRotating)
							{
								clearInterval(gallery.timerRotating);
								gallery.timerRotating = null
							}
						}
					});


					// задаем стили для галереи
					gallery.css({
						position:'relative',
						zIndex: 5,
						width: totalWidth,
						overflow: 'hidden',
						margin: 0,
						padding: 0
					});


					// создаем главный контейнер и ставим его перед тэгом UL
					gallery.container = $('<div class="' + gallery.options.containerClass + '"/>').addClass(gallery.options.additionalClass).css({position: 'relative'});
					gallery.before(gallery.container);


					// создаем внутренний контейнер и добавляем его в основной
					var innerContainer = $('<div class="' + gallery.options.containerClass + '-content" style="position:relative;"/>');

					if (gallery.options.createMainShadows || gallery.options.createClipShadows)
					function createShadowsSpan(shadowsClass, classPrefix)
					{
						return $('<span class="' + shadowsClass + ' ' + shadowsClass + '_' + classPrefix + '"/>')
							.css({
								position: 'absolute',
								display: 'block',
								overflow: 'hidden'
							})
					}

					// создаем элементы для главной/общей тени
					if (gallery.options.createMainShadows)
					{
						$('<div class="' + gallery.options.containerClass + '-i"/>')
							.css({
								width: '100%',
								overflow:'hidden',
								position:'relative'
							})
							.append( createShadowsSpan(gallery.options.mainShadowsClass, 'tl') )
							.append( createShadowsSpan(gallery.options.mainShadowsClass, 'tr') )

							.append(innerContainer)
							.appendTo(
								gallery.container
									.append( createShadowsSpan(gallery.options.mainShadowsClass, 'bl') )
									.append( createShadowsSpan(gallery.options.mainShadowsClass, 'br') )
							);

						// проставляем стили для теней
						gallery.container
							.addClass('s_gal_cont_shadows')
							.css({overflow: 'hidden'})
					} else {
						// отказались от тени
						gallery.container.append(innerContainer)
					}


					// создаем кнопку Prev и добавляем ее во внутренний контейнер
					if (gallery.options.buttonPrevHTML != null)
					{
						gallery.buttonPrev = $(gallery.options.buttonPrevHTML)
							.addClass(gallery.options.buttonPrevClass)
							.css({
								display: 'none',
								'text-decoration': 'none',
								outline: 'none',
								overflow: 'hidden',
								position: 'absolute',
								top: '50%',
								left: 0
							})
							.appendTo(innerContainer)
							.click(function(){
								// если сейчас нет анимации
								if (gallery.canAnimate && gallery.options.autoRotating && rotatingMethod != null)
								{
									// останавливаем автоскролл
									gallery.removeGalleryTimer();
	
									// и создаем проверочный таймер, который при завершении анимации запустит автоскролл
									var sgButtonPrevTimer = setInterval(function(){
										// но таймер не бдует
										if (gallery.canAnimate)
										{
											// удаляем этот проверочный таймер
											clearInterval(sgButtonPrevTimer);
	
											// и, если пользователь не водит мышкой по галерее, запускаем автоскролл заново
											if (!gallery.hoverOnGallery) gallery.setGalleryTimer()
										}
									},50)
								}

								return false
							})
							.hover(function(){
									$(this).addClass(gallery.options.buttonPrevClass + '-hover')
								},function(){
									$(this).removeClass(gallery.options.buttonPrevClass + '-hover')
								}
							);
						gallery.buttonPrev
							// выравниваем/центрируем кнопки по высоте проставлением отрицательного маргина
							.css({
								'margin-top': -Math.round(gallery.buttonPrev.height() / 2)
							})
							// проставляем стили для внутреннего тэга SPAN кнопки, если конечно таковой есть
							.find('span').css({
								position: 'absolute',
								display: 'block',
								cursor: 'pointer'
							});
					}

					// создаем кнопку Next и добавляем ее во внутренний контейнер
					if (gallery.options.buttonNextHTML != null)
					{
						gallery.buttonNext = $(gallery.options.buttonNextHTML)
							.addClass(gallery.options.buttonNextClass)
							.css({
								display: 'none',
								'text-decoration': 'none',
								outline: 'none',
								overflow: 'hidden',
								position: 'absolute',
								top: '50%',
								right: 0
							})
							.appendTo(innerContainer)
							.click(function(){
								// если сейчас нет анимации
								if (gallery.canAnimate && gallery.options.autoRotating && rotatingMethod != null)
								{
									// останавливаем автоскролл
									gallery.removeGalleryTimer();
	
									// и создаем проверочный таймер, который при завершении анимации запустит автоскролл
									var sgButtonNextTimer = setInterval(function(){
										// но таймер не бдует
										if (gallery.canAnimate)
										{
											// удаляем этот проверочный таймер
											clearInterval(sgButtonNextTimer);
	
											// и, если пользователь не водит мышкой по галерее, запускаем автоскролл заново
											if (!gallery.hoverOnGallery) gallery.setGalleryTimer()
										}
									},50)
								}
	
								return false
							})
							.hover(function(){
									$(this).addClass(gallery.options.buttonNextClass + '-hover')
								},function(){
									$(this).removeClass(gallery.options.buttonNextClass + '-hover')
								}
							);
	
	
						gallery.buttonNext
							// выравниваем/центрируем кнопки по высоте проставлением отрицательного маргина
							.css({
								'margin-top': -Math.round(gallery.buttonNext.height() / 2)
							})
							// проставляем стили для внутреннего тэга SPAN кнопки, если конечно таковой есть
							.find('span').css({
								position: 'absolute',
								display: 'block',
								cursor: 'pointer'
							});
					}


					// создаем Clip контейнер и добавляем его во внутренний контейнер
					gallery.clip = $('<div class="' + gallery.options.containerClass + '-clip"/>')
						.css({
							position: 'relative',
							overflow: 'hidden'
						});


					// создаем элементы для тени Clip'а
					if (gallery.options.createClipShadows)
					{
						var containerClip = $('<div class="s_gal_clip_shadows_i"/>')
							.css({
								position: 'relative',
								overflow: 'hidden'
							})
							.append( createShadowsSpan(gallery.options.clipShadowsClass, 'tl') )
							.append( createShadowsSpan(gallery.options.clipShadowsClass, 'tr') )
							.append(gallery.clip);

						$('<div class="s_gal_clip_shadows"/>')
							.css({
								position: 'relative',
								overflow: 'hidden'
							})
							.append( createShadowsSpan(gallery.options.clipShadowsClass, 'bl') )
							.append( createShadowsSpan(gallery.options.clipShadowsClass, 'br') )
							.append(containerClip)
							.appendTo(innerContainer)
					} else {
						// отказались от тени
						innerContainer.append(gallery.clip)
					}


					// теперь перемещаем всю галерею (тэг UL) в анимационный контейнер
					gallery.clip.append(gallery[0]);


					// проверка на минимальное/максимальное число. Делается, чтоб пользователь не ошибся в номере проставленного им айтема
					gallery.options.startItem = Math.max( Math.min(gallery.options.startItem, gallery.items.length) - 1, 0);


					// если указано, что первым в галерее будет айтем номер 2 или более, то прокручиваем галерею
					if (gallery.options.startItem != 0)
					{
						// позиция айтема в галерее относительно начала галереи
						var left = gallery.getItemPosition(gallery.items, gallery.options.startItem);
						if (left + gallery.clip.width() <= gallery.width())
						{
							// перелистываем галерею на нужный айтем (еще остается место для вращения)
							var needPosition = -left
						} else {
							// перелистываем галерею в самый конец
							var needPosition = -(gallery.width() - gallery.clip.width())
						}

						// передвигаем галерею на заданный айтем
						gallery.css({marginLeft: needPosition})
					}


					// загружаем методы вращения
					$.fn.scrollGallery.rotatingMethod = $.extend({});
					var rotatingMethod = $.fn.scrollGallery.rotatingMethod[gallery.options.rotatingMethod];
					if (rotatingMethod != null) rotatingMethod(gallery);


					// если установлено автоматическое вращение и найден метод вращения, то запускаем его
					if (gallery.options.autoRotating && rotatingMethod != null)
					{
						// устанавливаем таймер вращения айтемов
						gallery.setGalleryTimer();

						gallery.hover(function(){
								// указываем, что происходит движение по галерее
								gallery.hoverOnGallery = true;

								// удаляем таймер, так как юзер скользит мышкой по галерее
								gallery.removeGalleryTimer()
							},function(){
								// убираем курсор мышки с галереи
								// указываем, что происходит движение по галерее
								gallery.hoverOnGallery = false;

								// если анимация(вращение галереи) уже завершена, то можем снова устанавливать автоматическую анимацию
								if (gallery.canAnimate)
								{
									gallery.setGalleryTimer()
								} else {
								// анимация все-еще происходит. Задаем цикл, который будет проверять, когда она закончится
									var sgTimer = setInterval(function(){
										if (gallery.canAnimate)
										{
											// анимация завершена, запускаем таймер заново. Сделано, чтобы не было разных временных промежутков между вращением айтемов
											clearInterval(sgTimer);
											gallery.setGalleryTimer()
										}
									},50)
								}
							}
						)
					}

					// вызывается функция окончания создания галереи
					if (typeof(gallery.options.onComplete) == 'function') gallery.options.onComplete(gallery);

					// показываем кнопки Prev/Next
					if (gallery.options.buttonPrevHTML != null) gallery.buttonPrev.css({display: 'block'});
					if (gallery.options.buttonNextHTML != null) gallery.buttonNext.css({display: 'block'});

					// удаляем галерею при выгрузке страницы
					$(window).bind('unload', function(){
						gallery.container.remove()
					})
				};

				//  и удаляем буферный вспомогательный элемент
				bufferDiv.parent().remove();
		
			},35)
		}


		return gallery
	}
})(jQuery);
