﻿(function(window, $){
	function Slider(jParent, options){
		var oSlider = this, aDirections = ['Prev', 'Next'], oOldSlider = jParent.data('sliderObj');
		if(typeof oOldSlider != 'undefined') {
			return oOldSlider;
		}
		this.optValues = $.extend(true, {}, this.defOptions, options);
		this.jContainer = jParent.find(this.optValues.cssSelectors.Container);
		if(this.optValues.cssSelectors.Wrapper.length)
			this.jWrapper = this.jContainer.parents(this.optValues.cssSelectors.Wrapper);
		else
			this.jWrapper = this.jContainer.parent();
		this.Links = {};
		for(var dirNo = 0; dirNo < aDirections.length; dirNo++){
			this.Links['j' + aDirections[dirNo]] = jParent.find(this.optValues.cssSelectors[aDirections[dirNo]]);
			(function(dirName){
				var jLink = oSlider.Links['j' + dirName];
				jLink.click(function(){
					if(jLink.hasClass(oSlider.optValues.cssClasses.disabledLink)) return false;
					oSlider['go' + dirName]();
					return false;
				});
			})(aDirections[dirNo]);
		}
		this.getFrames();
		this.actDimensions = this.Dimensions[this.optValues.Vertical?'Vertical':'Horizontal'];
		this.curPage = 0;
		if(this.optValues.cssSelectors.pageList){
			this.jPageList = jParent.find(this.optValues.cssSelectors.pageList);
		}
		this.setSizes();
		if (this.optValues.cssSelectors.activeFrame) {
			this.goToFrame(this.jFrames.filter(this.optValues.cssSelectors.activeFrame));
		}
		$(window).resize(function(){
			oSlider.onResize();
		});
		this.jParent = jParent;
		jParent.data('sliderObj', this);
	}
	
	Slider.prototype = {
		defOptions : {
			cssSelectors : {
				Container : '',
				Wrapper : '',
				Prev : '',
				Next : '',
				Frames : '> div',
				pageList : false,
				pageListLink : false,
				activeFrame : false
			},
			cssClasses : {
				disabledLink : 'disabled',
				activePage : 'active'
			},
			Loop : false,
			Vertical : false,
			Step : 'auto', // число кадров | 'auto'
			fitToParent : false,
			fixResize : true, //что это? ))
			setContSize: true,
			beforeResize : false,
			frameFilter: false,
			afterResize : false
		},
		Dimensions : {
			Vertical : {
				start : 'top',
				scroll : 'scrollTop',
				size : 'height',
				outerSize : 'outerHeight'
			},
			Horizontal : {
				start : 'left',
				scroll : 'scrollLeft',
				size : 'width',
				outerSize : 'outerWidth'
			}
		},
		checkElements : function(){
			
		},
		getFrames: function (frmSelector, frmFilter) {
			var oSlider = this;
			if (typeof frmSelector == 'undefined') {
				frmSelector = this.optValues.cssSelectors.Frames;
			} else if (typeof frmSelector == 'function') {
				frmFilter = frmSelector;
				frmSelector = this.optValues.cssSelectors.Frames;
			}
			if (typeof frmFilter == 'undefined') {
				frmFilter = this.optValues.frameFilter;
			}
			this.jFrames = this.jContainer.find(frmSelector);
			this.Frames = [];
			this.jFrames.each(function(){
				var jFrame = $(this), incFrame = true;
				if (typeof frmFilter == 'function') {
					incFrame = frmFilter.call(oSlider, jFrame);
				}
				if (incFrame) {
					oSlider.Frames.push({jFrame : jFrame});
				}
			});
		},
		onResize: function (oOpts) {
			if (this.looping) {
				return;
			}
			var curFrameNo = 0, prntSize = this.jParent[this.actDimensions.outerSize]();
			if (typeof this.prntSize == 'number' && prntSize == this.prntSize) {
				return;
			}
			this.prntSize = prntSize;
			if (this.Pages[this.curPage] && this.Pages[this.curPage].Frames[0]) {
				curFrameNo = this.Pages[this.curPage].Frames[0].frameNo;
			}
			this.setSizes();
			this.goToFrame(curFrameNo, true, true);
		},
		setSizes : function(oOpts){
			oOpts = oOpts || {};
			var optNames = ['setContSize', 'fitToParent'], optNmNo = 0, optName;
			while (optName = optNames[optNmNo++]) {
				if (typeof oOpts[optName] == 'undefined') {
					oOpts[optName] =  this.optValues[optName];
				}
			}
			var wrapperRealSize, viewSize, framesSize = 0, stepSize, pageSize = 0; 
			if(oOpts.fitToParent){
				this.jContainer[this.actDimensions.size](1);
				this.jWrapper[this.actDimensions.size]('auto');
				wrapperRealSize = this.jWrapper[this.actDimensions.size]();
				this.jWrapper[this.actDimensions.size](wrapperRealSize);
			}
			viewSize = this.jWrapper[this.actDimensions.outerSize]();
			if (!typeof (stepSize = this.optValues.Step) == 'number') {
				stepSize = 'auto';
			}
			if (typeof this.optValues.beforeResize == 'function') {
				this.optValues.beforeResize.call(this);
			}
			this.Pages = [{Frames : []}];
			this.realPages = [[]];
			for(var frameNo = 0, pageNo = 0; frameNo < this.Frames.length; frameNo++){
				var jFrame = this.Frames[frameNo].jFrame, frameSize = jFrame[this.actDimensions.outerSize](true);
				if (frameSize === 0) {
					continue;
				}
				if(
					(stepSize == 'auto' && pageSize + frameSize > viewSize)
					|| (stepSize != 'auto' && (frameNo + 1) / stepSize > pageNo + 1)
				){
					pageNo += 1;
					//framesSize += pageSize;
					framesSize = framesSize + pageSize;
					pageSize = 0;
					if (!this.Pages[pageNo]) {
						this.Pages[pageNo] = {Frames : []};
					}
					if (!this.realPages[pageNo]) {
						this.realPages[pageNo] = [];
					}
				}
				pageSize += frameSize;
				this.Pages[pageNo].Frames.push({jFrame:jFrame, frameNo:frameNo});
				this.realPages[pageNo].push(jFrame);
				this.Frames[frameNo].Page = pageNo
				this.Pages[pageNo].Scroll = framesSize;
				//console.log('fr' + frameNo + ' pg' + pageNo + ' ' + framesSize + ' ' + pageSize);
			}
			framesSize += pageSize;
			while(this.Pages[pageNo] && this.Pages[pageNo].Scroll >= framesSize - viewSize){
				if(pageNo < this.Pages.length - 1){
					for(var frNo = 0; frNo < this.Pages[pageNo + 1].Frames.length; frNo++){
						this.Frames[this.Pages[pageNo + 1].Frames[frNo].frameNo].Page = pageNo;
						this.Pages[pageNo].Frames.push(this.Pages[pageNo + 1].Frames[frNo]);
						//console.log('fr' + frNo);
					}
					//console.log('pg' + pageNo + ' ' + this.Pages[pageNo].Scroll + ' ' + viewSize + ' ' + framesSize);
					this.Pages.splice(pageNo + 1, 1);
				}
				this.Pages[pageNo].Scroll = framesSize - viewSize;
				pageNo--;
			}
			if (oOpts.setContSize) {
				this.jContainer[this.actDimensions.size](framesSize);
			}
			this.updateLinks();
			this.updatePageList();
			//console.log(this.Pages);
		},
		updatePageList : function(){
			if(!this.jPageList) return false;
			var oSlider = this, jPageListLinks = this.optValues.cssSelectors.pageListLink ? this.jPageList.find(this.optValues.cssSelectors.pageListLink) : this.jPageList.children();
			var jLink = jPageListLinks.first().clone().removeClass(this.optValues.cssClasses.activePage);
			jPageListLinks.remove();
			for(var pageNo = 0; pageNo < this.Pages.length; pageNo++){
				(function(jLink, pageNo){
					jLink.clone().appendTo(oSlider.jPageList).click(function(){
						oSlider.Slide(pageNo);
					});
				})(jLink, pageNo);
			}
			this.updatePageListLinks();
		},
		updatePageListLinks : function(){
			if(!this.jPageList) return false;
			var jPageListLinks = this.optValues.cssSelectors.pageListLink ? this.jPageList.find(this.optValues.cssSelectors.pageListLink) : this.jPageList.children();
			jPageListLinks.removeClass(this.optValues.cssClasses.activePage)
						  .eq(this.curPage).addClass(this.optValues.cssClasses.activePage);
			
		},
		goToFrame : function(Frame, fast, noLoop){
			var oCurFrame;
			if(Frame instanceof jQuery) Frame = this.jFrames.index(Frame);
			if(typeof Frame != 'number') return;
			oCurFrame = this.Frames[Frame];
			if (oCurFrame && oCurFrame.Page) {
				this.Slide(oCurFrame.Page, fast, noLoop);
			}
		},
		goNext : function(){
			this.Slide(this.curPage + 1);
		},
		goPrev : function(){
			this.Slide(this.curPage - 1);
		},
		Slide: function(pageNo, fast, noLoop){
			//console.log(pageNo + ' ' + fast + ' ' + noLoop + ' ' + this.curPage);
			if (this.animated) {
				return;
			}
			if (typeof fast === 'undefined') {
				fast = false;
			}
			if (pageNo == this.curPage && !fast) {
				return;
			}
			if (typeof noLoop === 'undefined') {
				noLoop = false;
			}
			var oSlider = this, wrapperCss = {}, pagesLength = this.Pages.length, 
				doLoop = !noLoop && oSlider.optValues.Loop;
			if (doLoop && (pageNo < 0 || pageNo >= pagesLength)) {
				pageNo = this.loopFrames(pageNo);
			} else if (!noLoop) {
				this.curPage = pageNo;
			}
			
			if (fast) {
				this.jWrapper[this.actDimensions.scroll](this.Pages[pageNo].Scroll);
				this.updatePageListLinks();
			} else {
				wrapperCss[this.actDimensions.scroll] = this.Pages[pageNo].Scroll;
				this.animated = true;
				this.jWrapper.animate(wrapperCss, fast ? 0 : '', function(){
					oSlider.updatePageListLinks();
					oSlider.animated = false;
				});
			}
			if (!oSlider.optValues.Loop) {
				this.updateLinks();
			}
		},
		loopFrames: function (pageNo) {
			var toLeft = pageNo > this.curPage, stepSize = Math.abs(pageNo - this.curPage),
				aMovedPages = this.realPages.splice(toLeft ? 0 : (this.realPages.length - stepSize), stepSize);
			this.looping = true;
			for (var pgNo = 0, mPagesLength = aMovedPages.length; pgNo < mPagesLength; pgNo += 1) {
				for (var frNo = 0, frmsLength = aMovedPages[pgNo].length; frNo < frmsLength; frNo += 1) {
					aMovedPages[pgNo][frNo][toLeft ? 'insertAfter' : 'insertBefore'](this.Frames[toLeft ? this.Frames.length - 1 : 0].jFrame);
					this.Frames[toLeft ? 'push' : 'unshift'](this.Frames[toLeft ? 'shift' : 'pop']());
				}
			}
			this.setSizes();
			if (toLeft) {
				pageNo -= stepSize;
				this.Slide(pageNo - stepSize, true, true);
			} else {
				pageNo += 1;
				this.Slide(pageNo + stepSize, true, true);
			}
			this.looping = false;
			return pageNo;
		},
		updateLinks : function () {
			var linkNo = 0;
			for(var linkName in this.Links){
				this.Links[linkName].removeClass(this.optValues.cssClasses.disabledLink);
				if (this.optValues.Loop ? this.Pages.length <= 1 : (this.Pages.length - 1) * linkNo == this.curPage) {
					this.Links[linkName].addClass(this.optValues.cssClasses.disabledLink);
				}
				linkNo += 1; 
			}
		}
	}
	
	$.fn.goSlider = function(options){
		new Slider($(this), options);
		return this;
	}
	
	$.fn.setSliderDefOptions = function(options){
		Slider.prototype.defOptions = $.extend(true, {}, Slider.prototype.defOptions, options);
	}
})(self, jQuery);
