(function (window, $) {
	function itSlider(jParent, options) {
		var oItSlider = this, aDirections = ['Prev', 'Next'], oOldItSlider, jActiveFrame,
			oOpts, oSels;
		oOpts = this.optValues = $.extend(true, {}, this.defOptions, options);
		oSels = oOpts.cssSelectors;
		this.jParent = jParent;
		if ((oOldItSlider = this.jParent.data('itSliderObj'))) {
			return oOldItSlider;
		}
		this.jFrames = this.jParent.find(oSels.Frames);
		if (oSels.activeFrame && (jActiveFrame = this.jFrames.filter(oSels.activeFrame)).length) {
			this.curPos = this.jFrames.index(jActiveFrame);
		} else {
			this.curPos = 3;
		}
		this.goPos = this.curPos;
		this.Frames = [];
		this.jFrames.each(function (index) {
			var jFrame = $(this), jImg = jFrame.find('img');
			if (index == oItSlider.curPos) {
				jImg.get(0).onload = function () {
					oItSlider.getSizes();
					oItSlider.Draw();
				};
			}
			jFrame.bind('click.ItSlider', function (e) {
				oItSlider.frameClick(jFrame, e);
			});
			oItSlider.Frames.push({jFrame : jFrame, jImg : jImg});
		});
		this.Wrapper = this.jFrames.parent();
		this.Links = {};
		for (var dirNo = 0; dirNo < aDirections.length; dirNo++) {
			this.Links['j' + aDirections[dirNo]] = this.jParent.find(oSels[aDirections[dirNo]]);
			(function (dirName) {
				var jLink = oItSlider.Links['j' + dirName];
				jLink.bind('click.ItSlider', function () {
					if (jLink.hasClass(oOpts.cssClasses.disabledLink) || oItSlider.Animated) {
						return false;
					}
					oItSlider['go' + dirName]();
					return false;
				});
			})(aDirections[dirNo]);
		}
		if (this.Frames[this.curPos].jImg.get(0).complete) {
			this.Frames[this.curPos].jImg.get(0).onload = null;
			this.getSizes();
			this.Draw();
		}
	}
	
	itSlider.prototype = {
		defOptions : {
			cssSelectors : {
				Prev : '',
				Next : '',
				Frames : '> div',
				pageList : false,
				pageListLink : false,
				activeFrame : false
			},
			cssClasses : {
				disabledLink : 'disabled',
				activePage : 'active',
				hideLeft : 'pers_0',
				hideRight : 'pers_8'
			},
			Loop : true,
			drawResult : null,
			beforeSwitch: null,
			afterSwitch: null,
			States: null
		},
		goTo: function (frameNo) {
			var isNext = this.curPos < frameNo;
			if (this.optValues.Loop) {
				if (this.curPos != frameNo) {
					this.loopTo(isNext, Math.abs(this.curPos - frameNo));
				}
			} else {
				while (this.curPos != frameNo) {
					if (isNext) {
						this.curPos++;
					} else {
						this.curPos--;
					}
					this.Draw(true, true);
				}
			}
		},
		loopTo: function (isNext, loopsCnt) {
			this.Looped = this.Animated = true;
			if (typeof loopsCnt != 'undefined' && !loopsCnt) {
				return;
			}
			this.loopFrames(isNext, loopsCnt);
			this.Draw(true, true);
		},
		goPrev: function () {
			this.Animated = true;
			if (this.optValues.Loop) {
				this.loopFrames(false);
			} else {
				this.goPos--;
			}
			this.Draw(true);
		},
		goNext: function () {
			this.Animated = true;
			if (this.optValues.Loop) {
				this.loopFrames(true);
			} else {
				this.goPos++;
			}
			this.Draw(true);
		},
		getSizes: function () {
			this.FrameSize = {w : this.jFrames.eq(this.curPos).outerWidth(), h: this.jFrames.eq(this.curPos).outerHeight()};
		},
		frameClick: function (jFrame, event) {
			var frameNo;
			if (this.Animated) {
				event.preventDefault();
				return;
			}
			frameNo = this.jFrames.index(jFrame);
			if (frameNo != this.curPos) {
				event.preventDefault();
				this.goTo(frameNo);
			}
		},
		Draw: function (anim, linear) {
			var firstPos = this.goPos - 3, lastPos = this.goPos + 3, hideRight = false, 
				duration = 400, easing = linear ? 'linear' : 'swing', oItSlider = this,
				oOpts = this.optValues, fBefore = oOpts.beforeSwitch, fResult = oOpts.drawResult, 
				oStates = oOpts.States || this.States, fAfter = oOpts.afterSwitch;
			if ($.browser.msie && $.browser.version == '8.0') {
				duration = 800; //Движок IE8 не успевает отрисовать за 400мс
			}
			if (typeof fBefore == 'function') {
				fBefore.call(this, this.Frames[this.goPos].jFrame);
			}
			for (var frameNo = 0; frameNo < this.Frames.length; frameNo++) {
				var jFrame = this.Frames[frameNo].jFrame, jImg = this.Frames[frameNo].jImg, frameCss = {}, frameW;
				if (frameNo < firstPos || (hideRight = frameNo > lastPos)) {
					frameCss = this.getHideCss(hideRight);
					frameW = 90;
				} else {
					var curPos = frameNo - firstPos, isRight = curPos > 3, frameTop = -18,
						posState = isRight ? Math.abs(curPos - 6) : curPos;
					frameW = Math.round(this.FrameSize.w * oStates[posState].size);
					frameCss['left'] = (isRight ? 100 - oStates[posState].pos : oStates[posState].pos) + '%';
					frameCss['z-index'] = posState + 2;
					frameCss['margin-left'] = '-' + Math.round(frameW / 2) + 'px';
					if (curPos != 3) {
						frameTop += Math.round((this.FrameSize.h - this.FrameSize.h * oStates[posState].size) / 2);
					}
					frameCss['top'] = frameTop;
				}
				if (!anim) {
					jImg.css('width', frameW);
					jFrame.css(frameCss);
					if (typeof fAfter == 'function') {
						fAfter.call(this, this.Frames[this.goPos].jFrame);
					}
				} else {
					this.AnimatedFrames = this.Frames.length;
					jImg.animate({'width' : frameW}, duration, easing);
					jFrame.animate(frameCss, duration, easing, function () {
						oItSlider.frameAnimEnd();
					});
				}
			}
			this.updateLinks();
			if (!this.optValues.Loop) {
				this.curPos = this.goPos;
			}
			if (typeof fResult == 'function') {
				fResult.call(this, this.Frames[this.goPos].jFrame);
			}
		},
		loopFrames: function (isNext, loopsCnt) {
			if (isNext && this.curPos == this.goPos) {
				this.goPos++;
			} else if (!isNext && this.curPos == this.goPos - 1) {
				this.goPos--;
			}
			var loopDimensions = isNext ? {from: 0, to: this.Frames.length - 1, ins: 'insertAfter'} : {from: this.Frames.length - 1, to: 0, ins: 'insertBefore'},
				jFromFrame = this.Frames[loopDimensions.from].jFrame, oItSlider = this,
				jToFrame = jFromFrame.clone()[loopDimensions.ins](this.Frames[loopDimensions.to].jFrame);
			jToFrame.css(this.getHideCss(isNext)).bind('click.ItSlider', function (e) {
				oItSlider.frameClick(jToFrame, e);
			});
			this.Frames.splice(loopDimensions.to + (isNext ? 1 : 0), 0, {jFrame: jToFrame, jImg: jToFrame.find('img')});
			this.animCallback = function () {
				jFromFrame.remove();
				this.jFrames = this.jParent.find(this.optValues.cssSelectors.Frames);
				this.Frames.splice(loopDimensions.from + (isNext ? 0 : 1), 1);
				if (--loopsCnt) {
					this.loopTo(isNext, loopsCnt);
				} else {
					this.Looped = false;
				}
			};
		},
		updateLinks: function () {
			var linkNo = 0;
			if (this.optValues.Loop) {
				return;
			}
			for (var linkName in this.Links) {
				this.Links[linkName].removeClass(this.optValues.cssClasses.disabledLink);
				if ((this.Frames.length - 1) * linkNo == this.curPos) {
					this.Links[linkName].addClass(this.optValues.cssClasses.disabledLink);
				}
				linkNo++; 
			}
		},
		getHideCss: function (hideRight) {
			return {
				'margin-left' : (hideRight ? '' : '-') + '90px',
				left : (hideRight ? 100 : 0) + '%',
				top : '18px',
				'z-index' : 1
			};
		},
		frameAnimEnd: function () {
			var fAfter = this.optValues.afterSwitch;
			this.AnimatedFrames--;
			if (this.AnimatedFrames) {
				return;
			}
			if (typeof fAfter == 'function') {
				fAfter.call(this, this.Frames[this.goPos].jFrame);
			}
			if (typeof this.animCallback == 'function') {
				this.animCallback.call(this);
			}
			if (!this.Looped) {
				this.Animated = false;
			}
		},
		States : [
			{pos : 9, size : 0.43},
			{pos : 19, size : 0.6},
			{pos : 30, size : 0.8},
			{pos : 50, size : 1}
		]
	};
	
	$.fn.goItSlider = function (options) {
		new itSlider($(this), options);
	};
	
})(self, jQuery);
