/**
 * @author alexander.farkas
 */
(function($){
	$.widget('ui.scroller', {
		_init: function(){
			
			var elem = this.element[0],
			o = this.options,
			that = this,
			fn		= o.animateOptions.complete
		;
			
	        o.animateOptions.complete = function(){
            	if(fn && $.isFunction(fn)){
					fn.call(this, that);
				}
	            that.propagate('end');
	        };
			
	        o.direction = (o.direction == 'vertical') ? {
	            scroll: 'scrollTop',
	            outerD: 'outerHeight',
	            dim: 'height',
				dir: 'Top'
	        } : {
	            scroll: 'scrollLeft',
	            outerD: 'outerWidth',
	            dim: 'width',
				dir: 'Left'
	        };
			
	        this.moveElem = $(o.moveWrapper, elem);
	        this.atomElem = $(o.atoms, elem);
	        this.hidingWrapper = $(o.hidingWrapper, elem);
	        
	        this.nextLink = $(o.nextLink, elem);
	        this.prevLink = $(o.prevLink, elem);
	        
	        this.position = 0;
	        this.atomPos = 0;
	        this.percentage = 0;
	        this.oldPosition = 0;
	        this.oldAtomPos = 0;
	        if (o.hidingHeight || o.hidingWidth) {
	            var css = (o.hidingHeight) ? {
	                height: o.hidingHeight
	            } : {};
	            if ((o.hidingWidth)) {
	                css = $.extend(css, {
	                    width: o.hidingWidth
	                });
	            }
	            this.hidingWrapper.css(css);
	        }
			
			this.selectedFocus = false;
			
			
			if($.fn.setFocus && $.fn.closest){
				var traverse = {};
				if((o.direction.dir === 'Top')){
					traverse[$.ui.keyCode.UP] = 'prev';
					traverse[$.ui.keyCode.DOWN] = 'next';
				} else {
					traverse[$.ui.keyCode.LEFT] = 'prev';
					traverse[$.ui.keyCode.RIGHT] = 'next';
				}
				this.moveElem
					.bind('keyfocus', function(e){
						var atom = $(e.target).closest(o.atoms);
						if(atom[0]){
							that.scrollIntoView(atom);
						}
					})
					.bind('focusin', function(e){
						var atom = $(e.target).closest(o.atoms);
						that.selectedFocus = (atom[0]) ? atom : false;
					})
					.bind('focusout', function(e){
						that.selectedFocus = false;
					})
					.bind('keydown', function(e){
						
						if(that.selectedFocus === false || !traverse[e.keyCode]){return;}
						var selectElement = that.selectedFocus[traverse[e.keyCode]](o.atoms);
						
						if(selectElement && selectElement[0]){
							e.preventDefault();
							selectElement.setFocus(0, true);
							that.scrollIntoView(selectElement);
						} else if(that.isSliding){
							e.preventDefault();
						}

					});
			}
			
	        this.dims = [0];
	        this.hidingWrapper[0][o.direction.scroll] = 0;
			this.minPos = 0;
	        this.update();
			
			if(o.recalcStageOnresize){
				$(window).bind('resize', function(){
					setTimeout(function(){
						that.stageWidthUpdate.call(that);
					}, 0);
				});
			}
			
	        if (o.diashow) {
	            this.startDiashow();
	            this.element.bind('mouseenter focusin', function(){
	                clearInterval(that.diaTimer);
					setTimeout(function(){
						clearInterval(that.diaTimer);
					}, 99);
	            });
				if(o.restartDiaShow){
					this.element
						.bind('mouseleave focusout', function(){
			                that.startDiashow.call(that);
			            });
				}
	        }
			
	        if (o.enableMwheel && $.fn.mwheelIntent) {
				this.hidingWrapper.mwheelIntent(function(e, d){
	                that.stopDiashow.call(that);
	                d = (d < 0) ? '-' : '+';
					if((that.position >= that.maxPos && d === '-') || (d === '+' && that.position <= that.minPos)){
						return !that.isSliding;
					}
					
	                var moveStep = (o.moveStep) ? o.moveStep : 'atom';
	                that.moveTo(d + 'atom1');
	                return false;
	            });
	        }
						
			var handlePrevNext = function(){
	            var dir = ($.inArray(this, that.prevLink) !== -1) ?
					'+' :
					'-';
				that.stopDiashow.call(that);
	            that.moveTo(dir + o.moveStep);
	            return false;
	        };
			
	        this.nextLink
				.bind('click.uiscroller', handlePrevNext);
	        this.prevLink
				.bind('click.uiscroller', handlePrevNext);
			if($.browser.msie && parseInt($.browser.version, 10) < 7){
				var over = function(){$(this).addClass('over');},
					out = function(){$(this).removeClass('over');}
				;
				this.nextLink
					.hover(over, out);
		        this.prevLink
					.hover(over, out);
			}	
			if(o.defaultSelected){
				this.moveTo('goTo'+ o.defaultSelected, false);
			}		
			this.propagate('init');
		},
		stageWidthUpdate: function(){
			this.dims[1] = this.hidingWrapper[this.options.direction.dim]();
			this.maxPos = (this.dims[0] - this.dims[1]);
			this.updatePosition_Controls();
		},
        createPagination: function(hard){
            var content = '<ul>', that = this, tmpContent, o = this.options;
            this.pagination = $(o.pagination, this.element[0]);
            this.atomElem.each(function(i){
                tmpContent = o.paginationAtoms.replace(/\$number/g, i + 1);
                
                content += (o.paginationTitleFrom) ? tmpContent.replace(/\$title/g, $(o.paginationTitleFrom, this).text()) : tmpContent;
            });
            this.pagination.html(content + '</ul>').find('a').each(function(i){
                $(this).click(function(){
                    that.stopDiashow.call(that);
                    that.moveTo.call(that, 'goTo' + i);
                    return false;
                });
            });
        },
		getIndexNearPos: function(nPos){
			var len = this.dims.length;
			while (len--) {
                if (nPos >= this.dims[len]) {					
                    return len;
                }
            }
            return false;
        },
		inView: function(atom){
			var dir 		= this.options.direction,
				stageDim 	= this.dims[1],
				atomDim 	= atom[dir.outerD](),
				curPos		= this.hidingWrapper['scroll' + dir.dir](),
				atomPos 	= atom[0]['offset'+ dir.dir]
			;
			if(curPos > atomPos || stageDim < atomDim + atomPos - curPos){
				return atomPos;
			}
			return false;
		},
		scrollIntoView: function(atom){
			var inView = this.inView(atom);
			if(inView !== false){
				this.moveTo(inView);
			}
		},

        _setData: function(k, v){
        	var o = this.options;
        	switch(k) {
	        	case 'enableMwheel' :
	        		if( !v && o.enableMwheel){
	        			this.hidingWrapper.unmwheelIntent();
	        		}
	        		break;
	        		
	        	case 'addSubPixel':
	        		if(o.addSubPixel !== v) {
	        			this.dims[0] -= o.addSubPixel;
	        			o.addSubPixel = v;
	        			this.dims[0] += o.addSubPixel;
	        			this.update();
	        		}
	        		break;
        	}
        	$.widget.prototype._setData.apply(this, arguments);
        },
        startDiashow: function(){
            var that = this;
            this.diaTimer = null;
            clearInterval(this.diaTimer);
            this.diaTimer = setInterval(function(){
                ((that.position === that.maxPos && that.options.type !== 'carousel') ? that.moveTo(0, false) : that.moveTo('-' + that.options.moveStep));
            }, this.options.diashow);
        },
        stopDiashow: function(){
            this.element.unbind('.diashow');
            clearInterval(this.diaTimer);
        },
        update: function(hard){
            var that = this, jElm, o = this.options;
            
			if (hard) {
                this.dims = [0];
            }
			
            this.dims[1] = this.hidingWrapper.css({
                overflow: 'hidden',
				position: 'relative'
            })[o.direction.dim]();
			
            var from = this.dims.length - 2;
			for(var i = from, len = this.atomElem.length; i < len; i++){
                jElm = $(this.atomElem[i]);
                that.dims.push(that.dims[0]);
                that.dims[0] += jElm[o.direction.outerD]({margin: true});
			}
			this.dims[0] += o.addSubPixel;
            this.maxPos = (this.dims[0] - this.dims[1]);
			
			var moveCss = {};
			moveCss[o.direction.dim] = this.dims[0] + 'px';
			
            this.moveElem.css(moveCss);
			
            if (o.pagination) {
                this.createPagination(hard);
            }
            this.updatePosition_Controls();
        },
        updatePosition_Controls: function(pos){
			//calculate the curent position
			var o = this.options;
			pos = (isNaN(pos)) ? parseInt(this.hidingWrapper[0][o.direction.scroll], 10) : pos;
			
			function changeState(elem, active){
				var doo = (active) ?{
						style: 'addClass'
					} : {
						style: 'removeClass'
					};
				return elem[doo.style](o.activeLinkClass);
			}
			
            if(pos !== this.position){
				this.percentage = pos / (this.maxPos / 100);
	            this.oldPosition = this.position;
	            this.oldAtomPos = this.atomPos;
	            this.position = pos;
				
	            var num = this.getIndexNearPos(this.position);
	           
			    num = (num) ? num - 2 : 0;
	            this.atomPos = num;
			}
			
			this.percentage = pos / (this.maxPos / 100);
            
            if (pos <= this.minPos && this.prevLink.is('.' + o.activeLinkClass)) {
                o.linkFn.call(this.prevLink, 'hide', this.ui());
				changeState(this.prevLink);
            }
            else 
                if (pos > this.minPos && !this.prevLink.is('.' + o.activeLinkClass)) {
                    o.linkFn.call(this.prevLink, 'show', this.ui());
					changeState(this.prevLink, true);
                }
            if (pos >= this.maxPos && this.nextLink.is('.' + o.activeLinkClass)) {
                o.linkFn.call(this.nextLink, 'hide', this.ui());
				changeState(this.nextLink);
                
            }
            else 
                if (pos < this.maxPos && !this.nextLink.is('.' + o.activeLinkClass)) {
                    o.linkFn.call(this.nextLink, 'show', this.ui());
					changeState(this.nextLink, true);
                }
            if (this.pagination) {
                var oldActive = this.pagination.find('li').filter('.' + o.activePaginationClass).removeClass(o.activePaginationClass), newActive = oldActive.end().eq(this.atomPos).addClass(o.activePaginationClass);
                if ($.isFunction(o.paginationFn)) {
                    o.paginationFn.call(oldActive, 'inactive');
                    o.paginationFn.call(newActive, 'active');
                }
            }
        },
        getNummericPosition: function(ePos){
            var rel = false, num, lastDim = this.dims[this.dims.length - 1];
			
            // handle Atom Step & goTo
            if (ePos.indexOf('goTo') === 0) {
                num = parseInt(/(\d+)$/.exec(ePos)[0], 10) + 2;
                ePos = this.dims[num];
            }
			else if (ePos.indexOf('centerTo') === 0) {
				num = parseInt(/(\d+)$/.exec(ePos)[0], 10) + 2;
				ePos = this.dims[num] - (this.dims[1] / 2) + (this.atomElem.filter(":eq("+num+")")[this.options.direction.outerD]() / 2);
			}
            else 
                if (ePos == '-atom' || ePos == '-atom1') {
                    num = this.atomPos + 3;
                    ePos = (this.dims[num] || this.dims[num] === 0) ? this.dims[num] : lastDim;
                }
                else 
                    if (ePos == '+atom' || ePos == '+atom1') {
                        ePos = (this.atomPos) ? this.dims[this.atomPos + 1] : 0;
                    }
                    else 
                        if (ePos.indexOf('atom') == 1) {
                            num = parseInt(/(\d+)$/.exec(ePos)[0], 10);
                            if (ePos.indexOf('-') === 0) {
                                num += 2;
                                if (this.dims[this.atomPos + num]) {
                                    ePos = this.dims[this.atomPos + num];
                                }
                                else {
                                    ePos = lastDim;
                                }
                            }
                            else {
                                num -= 2;
                                var aLen = this.atomPos - num;
                                if (aLen > 1 && this.dims[this.atomPos - num]) {
                                    ePos = this.dims[this.atomPos - num];
                                }
                                else {
                                    ePos = 0;
                                }
                            }
                        // handle: +/-Number
                        }
                        else 
                            if (ePos.indexOf('+') === 0 || ePos.indexOf('-') === 0) {
                                rel = ePos.slice(0, 1);
                                ePos = parseInt(ePos.slice(1), 10);
                                ePos = (rel == '-') ? this.position + ePos : this.position - ePos;
                            }
                            else {
                                // handle Percentage
                                var per = /(\d+)%$/.exec(ePos);
                                if (per && per[1]) {
                                    ePos = this.maxPos / 100 * parseFloat(ePos);
                                }
                            }
			if(this.options.stickyFirstLast){
				if((ePos - this.maxPos) * -1 < this.atomElem.filter(':last')[this.options.direction.outerD]()){
					ePos = this.maxPos;
				} else if(ePos < this.atomElem[this.options.direction.outerD]()){
					ePos = 0;
				}
			}
            return ePos;
        },
        moveTo: function(pos, anim, animOp){
			pos = (typeof pos === 'string' || isNaN(pos)) ? this.getNummericPosition(pos) : pos;
		    pos = (pos <= 0) ? 0 : (pos >= this.maxPos) ? this.maxPos : pos;
            if (pos === this.position) {
                return false;
            }
            var o = this.options, scroll = o.direction.scroll;
            this.updatePosition_Controls(pos);
            this.propagate('start', this.oldPosition);
            
            anim = (typeof anim == 'undefined') ? o.animate : anim;
            if (anim) {
                //dirty break recursion
                animOp = animOp ||
                {};
                animOp = $.extend({}, o.animateOptions, {
                    slide: this
                }, animOp);
                var animCss = (scroll == 'scrollTop') ? {
                    scrollTop: pos,
                    uiscrollerComplete: pos
                } : {
                    scrollLeft: pos,
                    uiscrollerComplete: pos
                };
                this.hidingWrapper.stop().animate(animCss, animOp);
            }
            else {
                this.hidingWrapper.stop()[0][scroll] = pos;
                this.propagate('end');
            }
        },
        ui: function(){
            return {
                instance: this,
                options: this.options,
                pos: this.position,
                percentPos: this.percentage,
                oldIndex: this.oldAtomPos,
                newIndex: this.atomPos,
                size: this.dims.length - 2
            };
        },
        propagate: function(n, pos){
			var args = (pos || pos === 0) ? $.extend({}, this.ui(), {
                'pos': pos,
                percentPos: pos / (this.maxPos / 100)
            }) : this.ui();
			if(n === 'start'){
				this.isSliding = true;
			} else if(n === 'end'){
				this.isSliding = false;
			}
            this.element.triggerHandler("uiscroller" + n, [args]);
			if(this.options[n]){
				this.options[n].call(this.element[0], {type: 'uiscroller' + n}, args);
			}
        }
	}, true);
	$.ui.scroller.defaults = {
		//Wrapper Classes:
        hidingWrapper: 'div.rack',
        moveWrapper: 'div.rack-design',
        //Elements Classes
        atoms: 'div.container',
        nextLink: 'a.next',
        prevLink: 'a.prev',
        activeLinkClass: 'show',
		stickyFirstLast: true,
		
        linkFn: function(){},
        moveStep: 'atom',
        direction: 'horizontal',
		
        hidingWidth: false,
        hidingHeight: false,
        //animate
        animate: true,
        animateOptions: {
            duration: 600,
            complete: function() {}
        },
        enableMwheel: true,
		
        diashow: false,
		restartDiaShow: true,
		
        addSubPixel: 0,
		recalcStageOnresize: true,
		bindStyle: 'bind',
		
        pagination: false,
        paginationAtoms: '<li class="pa-$number"><a href="#">$number</a></li>',
        paginationTitleFrom: false,
        activePaginationClass: 'on',
        paginationFn: false
	};
    $.extend($.fx.step, {
        uiscrollerComplete: function(fx){
            if (fx.now || fx.now === 0) {
                var scroller = fx.options.slide;
                if (scroller) {
                    scroller.propagate('slide', scroller.hidingWrapper[0][scroller.options.direction.scroll]);
                }
            }
        }
    });
	$.ui.scroller.prototype.init = $.ui.scroller.prototype._init;
})(jQuery);

