// main gallery module
(function($) {
	$.fn.gallery = function(options) { return new Gallery(this.get(0), options); };
	function Gallery(context, options) { this.init(context, options); };
	Gallery.prototype = {
		options:{},
		init: function (context, options){
			this.options = $.extend({
				infinite: false,								//true = infinite gallery
				duration: 700,									//duration of effect it 1000 = 1sec
				slideElement: 1,								//number of elements for a slide
				autoRotation: false,							//false = option is disabled; 1000 = 1sec
				effect: false,									//false = slide; true = fade
				listOfSlides: 'ul > li',						//elements galleries
				switcher: false,								//false = option is disabled; 'ul > li' = elements switcher
				disableBtn: false,								//false = option is disabled; 'hidden' = class adds an buttons "prev" and "next"
				nextBtn: 'a.link-next, a.btn-next, a.next',		//button "next"
				prevBtn: 'a.link-prev, a.btn-prev, a.prev',		//button "prev"
				circle: true,									//true = cyclic gallery; false = not cyclic gallery
				direction: false,								//false = horizontal; true = vertical
				event: 'click',									//event for the buttons and switcher
				IE: false,										//forced off effect it "fade" in IE
				autoHeight: false,								//auto height on fade
				easing: 'swing',
				onStart: function(){},
				onChange: function(){}
			}, options || {});
			var _el = $(context).find(this.options.listOfSlides);
			this.holder = $(context);
			if (this.options.effect) this.list = _el;
			else this.list = _el.parent();
			this.switcher = $(context).find(this.options.switcher);
			this.nextBtn = $(context).find(this.options.nextBtn);
			this.prevBtn = $(context).find(this.options.prevBtn);
			this.count = _el.index(_el.filter(':last'));
			
			if (this.options.switcher) this.active = this.switcher.index(this.switcher.filter('.active:eq(0)'));
			else this.active = _el.index(_el.filter('.active:eq(0)'));
			if (this.active < 0) this.active = 0;
			this.last = this.active;
			
			this.woh = _el.outerWidth(true);
			this.options.onStart(this);
			if (!this.options.direction) this.installDirections(this.list.parent().width());
			else {
				this.woh = _el.outerHeight(true);
				this.installDirections(this.list.parent().height());
			}
			
			if (!this.options.effect) {
				this.rew = this.count - this.wrapHolderW + 1;
				this.list.css({position: 'relative'}).css(this.dirAnimate());
			}
			else {
				this.rew = this.count;
				this.list.css({opacity: 0}).removeClass('active').eq(this.active).addClass('active').css({opacity: 1}).css('opacity', 'auto');
				this.switcher.removeClass('active').eq(this.active).addClass('active');
				if(this.options.autoHeight) this.list.parent().css({height: this.list.eq(this.active).outerHeight()});
			}
			this.flag = true;
			if (this.options.infinite){
				this.count++;
				this.active += this.count;
				this.list.append(_el.clone());
				this.list.append(_el.clone());
				this.list.css(this.dirAnimate());
			}
			
			this.initEvent(this, this.nextBtn, true);
			this.initEvent(this, this.prevBtn, false);
			if (this.options.disableBtn) this.initDisableBtn();
			if (this.options.autoRotation) this.runTimer(this);
			if (this.options.switcher) this.initEventSwitcher(this, this.switcher);
		},
		dirAnimate: function(){
			if (!this.options.direction) return {left: -(this.woh * this.active)};
			else return {top: -(this.woh * this.active)};
		},
		initDisableBtn: function(){
			this.prevBtn.removeClass('prev-'+this.options.disableBtn);
			this.nextBtn.removeClass('next-'+this.options.disableBtn);
			if (this.active == 0 || this.count+1 == this.wrapHolderW) this.prevBtn.addClass('prev-'+this.options.disableBtn);
			if (this.active == 0 && this.count+1 == 1 || this.count+1 <= this.wrapHolderW) this.nextBtn.addClass('next-'+this.options.disableBtn);
			if (this.active == this.rew) this.nextBtn.addClass('next-'+this.options.disableBtn);
		},
		installDirections: function(temp){
			this.wrapHolderW = Math.ceil(temp / this.woh);
			if (((this.wrapHolderW - 1) * this.woh + this.woh / 2) > temp) this.wrapHolderW--;
		},
		fadeElement: function(){
			if ($.browser.msie && this.options.IE){
				this.list.eq(this.last).css({opacity:0});
				this.list.removeClass('active').eq(this.active).addClass('active').css({opacity:'auto'});
			}
			else{
				this.list.eq(this.last).animate({opacity:0}, {queue:false, easing: this.options.easing, duration: this.options.duration});
				this.list.removeClass('active').eq(this.active).addClass('active').animate({
					opacity:1
				}, {queue:false, duration: this.options.duration, complete: function(){
					$(this).css('opacity','auto');
				}});
			}
			if(this.options.autoHeight) this.list.parent().animate({height: this.list.eq(this.active).outerHeight()}, {queue:false, duration: this.options.duration});
			if (this.options.switcher) this.switcher.removeClass('active').eq(this.active).addClass('active');
			this.last = this.active;
		},
		scrollElement: function($this){
			if (!$this.options.infinite) $this.list.stop().animate($this.dirAnimate(), {queue:false, easing: $this.options.easing, duration: $this.options.duration, complete:function(){ $this.options.onChange($this) }});
			else $this.list.stop().animate($this.dirAnimate(), $this.options.duration, $this.options.easing, function(){ $this.flag = true;$this.options.onChange($this); });
			if ($this.options.switcher) $this.switcher.removeClass('active').eq($this.active / $this.options.slideElement).addClass('active');
		},
		runTimer: function($this){
			if($this._t) clearTimeout($this._t);
			$this._t = setInterval(function(){
				if ($this.options.infinite) $this.flag = false;
				$this.toPrepare($this, true);
			}, this.options.autoRotation);
		},
		initEventSwitcher: function($this, el){
			el.bind($this.options.event, function(){
				$this.active = $this.switcher.index($(this)) * $this.options.slideElement;
				if($this._t) clearTimeout($this._t);
				if ($this.options.disableBtn) $this.initDisableBtn();
				if (!$this.options.effect) $this.scrollElement($this);
				else $this.fadeElement();
				if ($this.options.autoRotation) $this.runTimer($this);
				return false;
			});
		},
		initEvent: function($this, addEventEl, dir){
			addEventEl.bind($this.options.event, function(){
				if ($this.flag){
					if ($this.options.infinite) $this.flag = false;
					if($this._t) clearTimeout($this._t);
					$this.toPrepare($this, dir);
					if ($this.options.autoRotation) $this.runTimer($this);
				}
				return false;
			});
		},
		toPrepare: function($this, side){
			if (!$this.options.infinite){
				if (($this.active == $this.rew) && $this.options.circle && side) $this.active = -$this.options.slideElement;
				if (($this.active == 0) && $this.options.circle && !side) $this.active = $this.rew + $this.options.slideElement;
				for (var i = 0; i < $this.options.slideElement; i++){
					if (side) { if ($this.active + 1 <= $this.rew) $this.active++; }
					else { if ($this.active - 1 >= 0) $this.active--; }
				};
			}
			else{
				if ($this.active >= $this.count + $this.count && side) $this.active -= $this.count;
				if ($this.active <= $this.count-1 && !side) $this.active += $this.count;
				$this.list.css($this.dirAnimate());
				if (side) $this.active += $this.options.slideElement;
				else $this.active -= $this.options.slideElement;
			}
			if (this.options.disableBtn) this.initDisableBtn();
			if (!$this.options.effect) $this.scrollElement($this);
			else $this.fadeElement();
		},
		stop: function(){
			if (this._t) clearTimeout(this._t);
		},
		play: function(){
			if (this._t) clearTimeout(this._t);
			if (this.options.autoRotation) this.runTimer(this);
		}
	}
	
	// scrolling gallery plugin
	jQuery.fn.scrollGallery = function(_options){
		var _options = jQuery.extend({
			sliderHolder: '>div',
			slider:'>ul',
			slides: '>li',
			pagerLinks:'div.pager a',
			btnPrev:'a.link-prev',
			btnNext:'a.link-next',
			activeClass:'active',
			disabledClass:'disabled',
			generatePagination:'div.pg-holder',
			curNum:'em.scur-num',
			allNum:'em.sall-num',
			circleSlide:true,
			pauseClass:'gallery-paused',
			pauseButton:'none',
			pauseOnHover:true,
			autoHeight:false,
			autoRotation:false,
			stopAfterClick:false,
			switchTime:5000,
			duration:650,
			easing:'swing',
			event:'click',
			splitCount:false,
			afterInit:false,
			vertical:false,
			step:false
		},_options);
		return this.each(function(){
			// gallery options
			var _this = jQuery(this);
			var _sliderHolder = jQuery(_options.sliderHolder, _this);
			var _slider = jQuery(_options.slider, _sliderHolder);
			var _slides = jQuery(_options.slides, _slider);
			var _btnPrev = jQuery(_options.btnPrev, _this);
			var _btnNext = jQuery(_options.btnNext, _this);
			var _pagerLinks = jQuery(_options.pagerLinks, _this);
			var _generatePagination = jQuery(_options.generatePagination, _this);
			var _curNum = jQuery(_options.curNum, _this);
			var _allNum = jQuery(_options.allNum, _this);
			var _pauseButton = jQuery(_options.pauseButton, _this);
			var _pauseOnHover = _options.pauseOnHover;
			var _pauseClass = _options.pauseClass;
			var _autoHeight = _options.autoHeight;
			var _autoRotation = _options.autoRotation;
			var _activeClass = _options.activeClass;
			var _disabledClass = _options.disabledClass;
			var _easing = _options.easing;
			var _duration = _options.duration;
			var _switchTime = _options.switchTime;
			var _controlEvent = _options.event;
			var _step = _options.step;
			var _vertical = _options.vertical;
			var _circleSlide = _options.circleSlide;
			var _stopAfterClick = _options.stopAfterClick;
			var _afterInit = _options.afterInit;
			var _splitCount = _options.splitCount;
			// gallery init
			if(!_slides.length) return;
			if(_splitCount) {
				var curStep = 0;
				var newSlide = jQuery('<slide>').addClass('split-slide');
				_slides.each(function(){
					newSlide.append(this);
					curStep++;
					if(curStep > _splitCount-1) {
						curStep = 0;
						_slider.append(newSlide);
						newSlide = jQuery('<slide>').addClass('split-slide');
					}
				});
				if(curStep) _slider.append(newSlide);
				_slides = _slider.children();
			}
			
			var _currentStep = 0;
			var _sumWidth = 0;
			var _sumHeight = 0;
			var _hover = false;
			var _stepWidth;
			var _stepHeight;
			var _stepCount;
			var _offset;
			var _timer;
			_slides.each(function(){
				_sumWidth+=jQuery(this).outerWidth(true);
				_sumHeight+=jQuery(this).outerHeight(true);
			});
			// calculate gallery offset
			function recalcOffsets() {
				if(_vertical) {
					if(_step) {
						_stepHeight = _slides.eq(_currentStep).outerHeight(true);
						_stepCount = Math.ceil((_sumHeight-_sliderHolder.height())/_stepHeight)+1;
						_offset = -_stepHeight*_currentStep;
					} else {
						_stepHeight = _sliderHolder.height();
						_stepCount = Math.ceil(_sumHeight/_stepHeight);
						_offset = -_stepHeight*_currentStep;
						if(_offset < _stepHeight-_sumHeight) _offset = _stepHeight-_sumHeight;
					}
				} else {
					if(_step) {
						_stepWidth = _slides.eq(_currentStep).outerWidth(true)*_step;
						_stepCount = Math.ceil((_sumWidth-_sliderHolder.width())/_stepWidth)+1;
						_offset = -_stepWidth*_currentStep;
						if(_offset < _sliderHolder.width()-_sumWidth) _offset = _sliderHolder.width()-_sumWidth;
					} else {
						_stepWidth = _sliderHolder.width();
						_stepCount = Math.ceil(_sumWidth/_stepWidth);
						_offset = -_stepWidth*_currentStep;
						if(_offset < _stepWidth-_sumWidth) _offset = _stepWidth-_sumWidth;
					}
				}
			}
			// gallery control
			if(_btnPrev.length) {
				_btnPrev.bind(_controlEvent,function(){
					if(_stopAfterClick) stopAutoSlide();
					prevSlide();
					return false;
				});
			}
			if(_btnNext.length) {
				_btnNext.bind(_controlEvent,function(){
					if(_stopAfterClick) stopAutoSlide();
					nextSlide();
					return false;
				});
			}
			if(_generatePagination.length) {
				_generatePagination.empty();
				recalcOffsets();
				var _list = jQuery('<ul />');
				for(var i=0; i<_stepCount; i++) jQuery('<li><a href="#">'+(i+1)+'</a></li>').appendTo(_list);
				_list.appendTo(_generatePagination);
				_pagerLinks = _list.children();
			}
			if(_pagerLinks.length) {
				_pagerLinks.each(function(_ind){
					jQuery(this).bind(_controlEvent,function(){
						if(_currentStep != _ind) {
							if(_stopAfterClick) stopAutoSlide();
							_currentStep = _ind;
							switchSlide();
						}
						return false;
					});
				});
			}
			// gallery animation
			function prevSlide() {
				recalcOffsets();
				if(_currentStep > 0) _currentStep--;
				else if(_circleSlide) _currentStep = _stepCount-1;
				switchSlide();
			}
			function nextSlide() {
				recalcOffsets();
				if(_currentStep < _stepCount-1) _currentStep++;
				else if(_circleSlide) _currentStep = 0;
				switchSlide();
			}
			function refreshStatus(ind) {
				if(_pagerLinks.length) _pagerLinks.removeClass(_activeClass).eq(_currentStep).addClass(_activeClass);
				if(!_circleSlide) {
					_btnPrev.removeClass(_disabledClass);
					_btnNext.removeClass(_disabledClass);
					if(_currentStep == 0) _btnPrev.addClass(_disabledClass);
					if(_currentStep == _stepCount-1) _btnNext.addClass(_disabledClass);
				}
				if(_curNum.length) _curNum.text(_currentStep+1);
				if(_allNum.length) _allNum.text(_stepCount);
				
				// autoHeight
				
				var heightSlide;
				
				if(_autoHeight){
					heightSlide = _slides.eq(_currentStep).outerHeight();
					if(ind != 0){
						_slider.animate({height: heightSlide}, {queue: false, duration: _duration});
					}else{
						_slider.css({height: heightSlide});
					}
				}
			}
			function switchSlide() {
				recalcOffsets();
				if(_vertical) _slider.animate({marginTop:_offset},{duration:_duration,queue:false,easing:_easing});
				else _slider.animate({marginLeft:_offset},{duration:_duration,queue:false,easing:_easing});
				refreshStatus();
				autoSlide();
			}
			// autoslide function
			function stopAutoSlide() {
				if(_timer) clearTimeout(_timer);
				_autoRotation = false;
			}
			function autoSlide() {
				if(!_autoRotation || _hover) return;
				if(_timer) clearTimeout(_timer);
				_timer = setTimeout(nextSlide,_switchTime);
			}
			if(_pauseOnHover) {
				_this.hover(function(){
					_hover = true;
					if(_timer) clearTimeout(_timer);
				},function(){
					_hover = false;
					autoSlide();
				});
			}
			recalcOffsets();
			refreshStatus(0);
			autoSlide();
			// pause buttton
			if(_pauseButton.length) {
				_pauseButton.click(function(){
					if(_this.hasClass(_pauseClass)) {
						_this.removeClass(_pauseClass);
						_autoRotation = true;
						autoSlide();
					} else {
						_this.addClass(_pauseClass);
						stopAutoSlide();
					}
					return false;
				});
			}
			if(_afterInit && typeof _afterInit === 'function') _afterInit(_this, _slides);
		});
	}
	
	// slideshow plugin
	jQuery.fn.fadeGallery = function(_options){
		var _options = jQuery.extend({
			slideElements:'div.slideset > div',
			pagerLinks:'div.pager a',
			btnNext:'a.next, .link-next',
			btnPrev:'a.prev, .link-prev',
			btnPlayPause:'a.play-pause',
			btnPlay:'a.play',
			btnPause:'a.pause',
			pausedClass:'paused',
			disabledClass: 'disabled',
			playClass:'playing',
			activeClass:'active',
			loadingClass:'ajax-loading',
			loadedClass:'slide-loaded',
			dynamicImageLoad:false,
			dynamicImageLoadAttr:'alt',
			currentNum:false,
			allNum:false,
			startSlide:null,
			noCircle:false,
			pauseOnHover:true,
			autoRotation:false,
			autoHeight:false,
			onBeforeFade:false,
			onAfterFade:false,
			onChange:false,
			disableWhileAnimating:false,
			switchTime:3000,
			duration:650,
			event:'click'
		},_options);
	
		return this.each(function(){
			// gallery options
			if(this.slideshowInit) return; else this.slideshowInit;
			var _this = jQuery(this);
			var _slides = jQuery(_options.slideElements, _this);
			var _pagerLinks = jQuery(_options.pagerLinks, _this);
			var _btnPrev = jQuery(_options.btnPrev, _this);
			var _btnNext = jQuery(_options.btnNext, _this);
			var _btnPlayPause = jQuery(_options.btnPlayPause, _this);
			var _btnPause = jQuery(_options.btnPause, _this);
			var _btnPlay = jQuery(_options.btnPlay, _this);
			var _pauseOnHover = _options.pauseOnHover;
			var _dynamicImageLoad = _options.dynamicImageLoad;
			var _dynamicImageLoadAttr = _options.dynamicImageLoadAttr;
			var _autoRotation = _options.autoRotation;
			var _activeClass = _options.activeClass;
			var _loadingClass = _options.loadingClass;
			var _loadedClass = _options.loadedClass;
			var _disabledClass = _options.disabledClass;
			var _pausedClass = _options.pausedClass;
			var _playClass = _options.playClass;
			var _autoHeight = _options.autoHeight;
			var _duration = _options.duration;
			var _switchTime = _options.switchTime;
			var _controlEvent = _options.event;
			var _currentNum = (_options.currentNum ? jQuery(_options.currentNum, _this) : false);
			var _allNum = (_options.allNum ? jQuery(_options.allNum, _this) : false);
			var _startSlide = _options.startSlide;
			var _noCycle = _options.noCircle;
			var _onChange = _options.onChange;
			var _onBeforeFade = _options.onBeforeFade;
			var _onAfterFade = _options.onAfterFade;
			var _disableWhileAnimating = _options.disableWhileAnimating;
	
			// gallery init
			var _anim = false;
			var _hover = false;
			var _prevIndex = 0;
			var _currentIndex = 0;
			var _slideCount = _slides.length;
			var _timer;
			if(_slideCount < 2) return;
	
			_prevIndex = _slides.index(_slides.filter('.'+_activeClass));
			if(_prevIndex < 0) _prevIndex = _currentIndex = 0;
			else _currentIndex = _prevIndex;
			if(_startSlide != null) {
				if(_startSlide == 'random') _prevIndex = _currentIndex = Math.floor(Math.random()*_slideCount);
				else _prevIndex = _currentIndex = parseInt(_startSlide);
			}
			_slides.hide().eq(_currentIndex).show();
			if(_autoRotation) _this.removeClass(_pausedClass).addClass(_playClass);
			else _this.removeClass(_playClass).addClass(_pausedClass);
	
			// gallery control
			if(_btnPrev.length) {
				_btnPrev.bind(_controlEvent,function(){
					if (_slides.filter(':animated').length > 0) return;
					prevSlide();
					return false;
				});
			}
			if(_btnNext.length) {
				_btnNext.bind(_controlEvent,function(){
					if (_slides.filter(':animated').length > 0) return;
					nextSlide();
					return false;
				});
			}
			if(_pagerLinks.length) {
				_pagerLinks.each(function(_ind){
					jQuery(this).bind(_controlEvent,function(){
						if(_currentIndex != _ind) {
							if(_disableWhileAnimating && _anim) return;
							_prevIndex = _currentIndex;
							_currentIndex = _ind;
							switchSlide();
						}
						return false;
					});
				});
			}
	
			// play pause section
			if(_btnPlayPause.length) {
				_btnPlayPause.bind(_controlEvent,function(){
					if(_this.hasClass(_pausedClass)) {
						_this.removeClass(_pausedClass).addClass(_playClass);
						_autoRotation = true;
						autoSlide();
					} else {
						_autoRotation = false;
						if(_timer) clearTimeout(_timer);
						_this.removeClass(_playClass).addClass(_pausedClass);
					}
					return false;
				});
			}
			if(_btnPlay.length) {
				_btnPlay.bind(_controlEvent,function(){
					_this.removeClass(_pausedClass).addClass(_playClass);
					_autoRotation = true;
					autoSlide();
					return false;
				});
			}
			if(_btnPause.length) {
				_btnPause.bind(_controlEvent,function(){
					_autoRotation = false;
					if(_timer) clearTimeout(_timer);
					_this.removeClass(_playClass).addClass(_pausedClass);
					return false;
				});
			}
	
			// dynamic image loading (swap from ATTRIBUTE)
			function loadSlide(slide) {
				if(!slide.hasClass(_loadingClass) && !slide.hasClass(_loadedClass)) {
					var images = slide.find(_dynamicImageLoad) // pass selector here
					var imagesCount = images.length;
					if(imagesCount) {
						slide.addClass(_loadingClass);
						images.each(function(){
							var img = this;
							img.onload = function(){
								img.loaded = true;
								img.onload = null;
								setTimeout(reCalc,_duration);
							}
							img.setAttribute('src', img.getAttribute(_dynamicImageLoadAttr));
							img.setAttribute(_dynamicImageLoadAttr,'');
						}).css({opacity:0});
	
						function reCalc() {
							var cnt = 0;
							images.each(function(){
								if(this.loaded) cnt++;
							});
							if(cnt == imagesCount) {
								slide.removeClass(_loadingClass);
								images.animate({opacity:1},{duration:_duration,complete:function(){
									if(jQuery.browser.msie && jQuery.browser.version < 9) jQuery(this).css({opacity:'auto'})
								}});
								slide.addClass(_loadedClass)
							}
						}
					}
				}
			}
	
			// gallery animation
			function prevSlide() {
				if(_disableWhileAnimating && _anim) return;
				_prevIndex = _currentIndex;
				if(_currentIndex > 0) _currentIndex--;
				else {
					if(_noCycle) return;
					else _currentIndex = _slideCount-1;
				}
				switchSlide();
			}
			function nextSlide() {
				if(_disableWhileAnimating && _anim) return;
				_prevIndex = _currentIndex;
				if(_currentIndex < _slideCount-1) _currentIndex++;
				else {
					if(_noCycle) return;
					else _currentIndex = 0;
				}
				switchSlide();
			}
			function refreshStatus() {
				if(_dynamicImageLoad) loadSlide(_slides.eq(_currentIndex));
				if(_pagerLinks.length) _pagerLinks.removeClass(_activeClass).eq(_currentIndex).addClass(_activeClass);
				if(_currentNum) _currentNum.text(_currentIndex+1);
				if(_allNum) _allNum.text(_slideCount);
				_slides.eq(_prevIndex).removeClass(_activeClass);
				_slides.eq(_currentIndex).addClass(_activeClass);
				if(_noCycle) {
					if(_btnPrev.length) {
						if(_currentIndex == 0) _btnPrev.addClass(_disabledClass);
						else _btnPrev.removeClass(_disabledClass);
					}
					if(_btnNext.length) {
						if(_currentIndex == _slideCount-1) _btnNext.addClass(_disabledClass);
						else _btnNext.removeClass(_disabledClass);
					}
				}
				if(typeof _onChange === 'function') {
					_onChange(_this, _slides, _prevIndex, _currentIndex);
				}
			}
			function switchSlide() {
				_anim = true;
				if(typeof _onBeforeFade === 'function') _onBeforeFade(_this, _slides, _prevIndex, _currentIndex);
				_slides.eq(_prevIndex).fadeOut(_duration,function(){
					_anim = false;
				});
				_slides.eq(_currentIndex).fadeIn(_duration,function(){
					if(typeof _onAfterFade === 'function') _onAfterFade(_this, _slides, _prevIndex, _currentIndex);
				});
				if(_autoHeight) _slides.eq(_currentIndex).parent().animate({height:_slides.eq(_currentIndex).outerHeight(true)},{duration:_duration,queue:false});
				refreshStatus();
				autoSlide();
			}
	
			// autoslide function
			function autoSlide() {
				if(!_autoRotation || _hover) return;
				if(_timer) clearTimeout(_timer);
				_timer = setTimeout(nextSlide,_switchTime);
			}
			if(_pauseOnHover) {
				_this.hover(function(){
					_hover = true;
					if(_timer) clearTimeout(_timer);
				},function(){
					_hover = false;
					autoSlide();
				});
			}
			refreshStatus();
			autoSlide();
		});
	}
	
	
}(jQuery));
