/**
 * @author alexander.farkas
 */
(function($){
	$.widget('ui.scroller', {
		init: function(){
			var elem = this.element[0],
			o = this.options,
			that = this;
	        o.animateOptions.complete = function(){
	            that.propagate('end');
	        };
	        o.direction = (o.direction == 'vertical') ? {
	            scroll: 'scrollTop',
	            outerD: 'outerHeight',
	            dim: 'height'
	        } : {
	            scroll: 'scrollLeft',
	            outerD: 'outerWidth',
	            dim: 'width'
	        };
	        this.pictureUpdate = 0;
	        
	        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.dims = [0];
	        this.hidingWrapper[0][o.direction.scroll] = 0;
	        this.update();
			
			if(o.recalcStageOnresize){
				$(window).resize(function(){
					that.dims[1] = that.hidingWrapper[o.direction.dim]();
				});
			}
			
	        if (o.diashow) {
	            this.startDiashow();
	            this.element.bind('mouseenter.diashow', function(){
	                clearInterval(that.diaTimer);
	            }).bind('mouseleave.diashow', function(){
	                that.startDiashow.call(that);
	            });
	        }
	        if ($.fn.mousewheel) {
	            this.moveElem.mousewheel(function(e, d){
	                that.stopDiashow.call(that);
	                d = (d < 0) ? '-' : '+';
	                var moveStep = (o.moveStep) ? o.moveStep : 'atom';
	                that.moveTo(d + 'atom1');
	                return false;
	            });
	        }
			this.mouseAction = false;
			this.element.bind('mousedown.diashow', function(){
	                that.mouseAction = true;
	            }).bind('mouseup.diashow', function(){
	                that.mouseAction = false;
	            }).bind('mouseleave.diashow', function(){
	                that.mouseAction = false;
	            });
	        this.nextLink.bind('click.uiscroller', function(){
	            that.stopDiashow.call(that);
	            that.moveTo('-' + o.moveStep);
	            return false;
	        });
	        this.prevLink.bind('click.uiscroller', function(){
	            that.stopDiashow.call(that);
	            that.moveTo('+' + o.moveStep);
	            return false;
	        });
			this.propagate('init');
		},
		getAtomNearPos: function(oPos, nPos){
            var i = 2, len = this.dims.length;
            for (; i < len; i++) {
                if (nPos <= this.dims[i]) {
                    return i;
                }
            }
            return false;
        },
        atomfocus: function(){
			var scrollPos = this.hidingWrapper[0][this.options.direction.scroll];
			if(!this.mouseAction && this.mouseAction.position != scrollPos){
				scrollPos = this.getAtomNearPos(this.position, scrollPos);
	            if (isFinite(scrollPos)) {
	                this.moveTo(this.dims[scrollPos], false);
	            }
			}
        },
        startDiashow: function(){
            var that = this;
            this.diaTimer = null;
            clearInterval(this.diaTimer);
            this.diaTimer = setInterval(function(){
                ((that.position === that.maxPos) ? 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'
            })[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]);
                width = jElm[o.direction.outerD]({
                    margin: true
                });
                that.dims[0] += width;
                jElm.bind('focus.uiscroller', function(){
                    setTimeout(function(){
                        that.stopDiashow.call(that);
                        that.atomfocus.call(that);
                    }, 9);
                });
			}
            this.dims[0] += o.addSubPixel;
            this.maxPos = (this.dims[0] - this.dims[1]);
            var moveCss = (o.direction.dim == 'height') ? {
                height: this.dims[0] + 'px'
            } : {
                width: this.dims[0] + 'px'
            };
            this.moveElem.css(moveCss);
            this.pagination = null;
            if (o.pagination) {
                this.createPagination(hard);
            }
			
            this.showHideLinks();
        },
        pictureIsLoaded: function(){
            this.pictureUpdate--;
            if (!this.pictureUpdate) {
                this.update();
            }
        },
        append: function(html, waitForImageLoad){
            var that = this;
            var appendedHTML = $(html).appendTo(this.moveElem[0]);
			this.atomElem = this.atomElem.add(appendedHTML);
            if (waitForImageLoad) {
                appendedHTML.find('img').each(function(){
                    if (!this.complete) {
                        $(this).bind('load.uiscroller', function(){
                            that.pictureIsLoaded.call(that);
                        });
                        that.pictureUpdate++;
                    }
                });
                if (!this.pictureUpdate) {
                    this.update();
                }
            }
            else {
                this.update();
            }
            
        },
        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;
                });
            });
        },
        showHideLinks: function(pos){
			//calculate the curent position
			var o = this.options;
			pos = (isNaN(pos)) ? parseInt(this.hidingWrapper[0][o.direction.scroll], 10) : pos;
            if(pos !== this.position){
				this.percentage = pos / (this.maxPos / 100);
	            this.oldPosition = this.position;
	            this.oldAtomPos = this.atomPos;
	            this.position = pos;
	            var num = this.getAtomNearPos(this.oldPosition, this.position);
	            num = (num) ? num - 2 : 0;
	            this.atomPos = num;
			}
			this.percentage = pos / (this.maxPos / 100);
            
            if (pos <= 0 && this.prevLink.is('.' + o.activeLinkClass)) {
                o.linkFn.call(this.prevLink, 'hide');
                this.prevLink.removeClass(o.activeLinkClass);
            }
            else 
                if (pos > 0 && !this.prevLink.is('.' + o.activeLinkClass)) {
                    o.linkFn.call(this.prevLink, 'show');
                    this.prevLink.addClass(o.activeLinkClass);
                }
            if (pos >= this.maxPos && this.nextLink.is('.' + o.activeLinkClass)) {
                o.linkFn.call(this.nextLink, 'hide');
                this.nextLink.removeClass(o.activeLinkClass);
            }
            else 
                if (pos < this.maxPos && !this.nextLink.is('.' + o.activeLinkClass)) {
                    o.linkFn.call(this.nextLink, 'show');
                    this.nextLink.addClass(o.activeLinkClass);
                }
            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');
                }
            }
        },
        calcNewPos: function(ePos){
            var rel = false, num;
            // handle Atom Step & goTo
            if (ePos.indexOf('goTo') === 0) {
                num = parseInt(/(\d+)$/.exec(ePos)[0], 10) + 2;
                ePos = this.dims[num];
            }
            else 
                if (ePos == '-atom' || ePos == '-atom1') {
                    num = this.atomPos + 3;
                    ePos = (this.dims[num] || this.dims[num] === 0) ? this.dims[num] : this.dims[this.dims.length - 1];
                }
                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 = this.dims[this.dims.length - 1];
                                }
                            }
                            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);
                                }
                            }
            return ePos;
        },
        moveTo: function(pos, anim, animOp){
			pos = (isNaN(pos)) ? this.calcNewPos(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.showHideLinks(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()];
            this.element.triggerHandler("uiscroller" + n, args);
        }
	});
	$.ui.scroller.defaults = {
		//Wrapper Classes:
        hidingWrapper: 'div.stage',
        moveWrapper: 'div.stage-design',
        //Elements Classes
        atoms: 'div.teaser',
        nextLink: 'a.next',
        prevLink: 'a.prev',
        activeLinkClass: 'show',
        linkFn: function(){
        },
        //animate
        animate: true,
        animateOptions: {
            duration: 800
        },
        hidingWidth: false,
        hidingHeight: false,
        moveStep: 'atom',
        direction: 'horizontal',
        pagination: false,
        paginationAtoms: '<li class="pa-$number"><a href="#">$number</a></li>',
        paginationTitleFrom: false,
        activePaginationClass: 'on',
        paginationFn: false,
        diashow: false,
        addSubPixel: 0,
		recalcStageOnresize: 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]);
                }
            }
        }
    });
})(jQuery);
