

Ext.ns('Ext.ux.SimpleCarousel');
Ext.ux.SimpleCarousel = Ext.extend(Ext.util.Observable, {
	startSlide: 0,
    transitionDuration: 0.5,
    transitionEasing: 'easeOut',
    activeSlide: 0,
    restartAfterNavigate: 0,
    wrap: true,
	transitionType: 'linear',
	wrapOffset: [0,0],
	circular: false,
	circularClones: 1,

    constructor: function(elId, config) {
        config = config || {};
        this.addEvents(
            'beforeprev',
            'prev',
            'beforenext',
            'next',
            'beforechange',
            'transition',
            'change',
            'play',
            'pause',
            'freeze',
            'unfreeze'
        );

        Ext.apply(this, config);
        Ext.ux.SimpleCarousel.superclass.constructor.call(this, config);

        this.transition = Ext.isFunction(this.transitionType) ? this.transitionType : Ext.ux.SimpleCarouselTransitions[this.transitionType];

        this.el = Ext.get(elId);
        this.slides = this.els = [];

        this.initMarkup();
        this.initEvents();

        if(this.carouselSize > 0) {
        	if (this.startSlide == 'random') {
        		this.startSlide = Math.floor(Math.random() * (this.carouselSize + 1));
        	}
            this.setSlide(this.startSlide, true);
        }
    },

    initMarkup: function() {
        var dh = Ext.DomHelper;

        this.carouselSize = 0;

        this.els.container = this.el.select('.container').item(0);
        this.els.slidesWrap = this.el.select('.wrap').item(0);
        this.els.descr = this.el.select('.description').item(0);

        this.els.navNext = this.el.select('.next').item(0);
        this.els.navPrev = this.el.select('.prev').item(0);

		this.viewport = this.els.container.getWidth();

        this.el.select('.item').each(function(item) {
            this.slides.push(Ext.get(item.dom));
        }, this);
        this.carouselSize = this.slides.length;
    },

    initEvents: function() {
    	if (this.els.navPrev) {
	        this.els.navPrev.on('click', function(ev) {
	            ev.preventDefault();
	            var target = ev.getTarget();
	            target.blur();
	            if(Ext.fly(target).hasClass('ux-carousel-nav-disabled')) return;
	            this.prev();
	        }, this);

    	}
		if (this.els.navNext) {
	        this.els.navNext.on('click', function(ev) {
	            ev.preventDefault();
	            var target = ev.getTarget();
	            target.blur();
	            if(Ext.fly(target).hasClass('ux-carousel-nav-disabled')) return;
	            this.next();
	        }, this);
		}

        if(this.freezeOnHover) {
            this.els.container.on('mouseenter', this.freeze, this);
            this.els.container.on('mouseleave', this.unFreeze, this, {buffer: (this.interval/2)*1000});
        };

        if(this.interval && this.autoPlay) {
            this.play();
        };
    },
	freeze: function(){
                if(this.playing) {
                    this.fireEvent('freeze', this.slides[this.activeSlide]);
                    this.els.slidesWrap.stopFx(false);
                    Ext.TaskMgr.stop(this.playTask);
                }
    },
    unFreeze: function(){
                if(this.playing) {

                    this.fireEvent('unfreeze', this.slides[this.activeSlide]);
                    Ext.TaskMgr.start(this.playTask);
                }
    },
    prev: function() {
        if (this.fireEvent('beforeprev') === false) {
            return;
        }
        if(this.autoPlay && this.pauseOnNavigate) {
            this.pause();
        }
        this.setSlide(this.activeSlide - 1);

        if(this.autoPlay && this.restartAfterNavigate != 0) {
            this.restartTaskBuffer = this.restartTaskBuffer || new Ext.util.DelayedTask(function() {
                this.play();
            }, this);

            this.restartTaskBuffer.delay(this.restartAfterNavigate*1000);
        }
        this.fireEvent('prev', this.activeSlide);
        return this;
    },

    next: function() {
        if(this.fireEvent('beforenext') === false) {
            return;
        }
        if(this.autoPlay && this.pauseOnNavigate) {
            this.pause();
        }
        this.setSlide(this.activeSlide + 1);

        if(this.autoPlay && this.restartAfterNavigate != 0) {
            this.restartTaskBuffer = this.restartTaskBuffer || new Ext.util.DelayedTask(function() {
                this.play();
            }, this);

            this.restartTaskBuffer.delay(this.restartAfterNavigate*1000);
        }

        this.fireEvent('next', this.activeSlide);
        return this;
    },

    play: function() {
        if(!this.playing) {
            this.playTask = this.playTask || {
                run: function() {
                    this.playing = true;
                    this.setSlide(this.activeSlide+1);
                },
                interval: this.interval*1000,
                scope: this
            };

            this.playTaskBuffer = this.playTaskBuffer || new Ext.util.DelayedTask(function() {
                Ext.TaskMgr.start(this.playTask);
            }, this);

            this.playTaskBuffer.delay(this.interval*1000);
            this.playing = true;
            if(this.showPlayButton) {
                this.els.navPlay.addClass('ux-carousel-playing');
            }
            this.fireEvent('play');
        }
        return this;
    },

    pause: function() {
        if(this.playing) {
            Ext.TaskMgr.stop(this.playTask);
            this.playTaskBuffer.cancel();
            this.playing = false;
            if(this.showPlayButton) {
                this.els.navPlay.removeClass('ux-carousel-playing');
            }
            this.fireEvent('pause');
        }
        return this;
    },

    clear: function() {
        this.els.slidesWrap.update('');
        this.slides = [];
        this.carouselSize = 0;
        this.pause();
        return this;
    },

    add: function(el, refresh) {
        var item = Ext.fly(el).appendTo(this.els.slidesWrap);
        this.slides.push(item);
        this.carouselSize = this.slides.length;
        if(refresh) {
            this.setSlide(this.activeSlide, true);
        }
        return this;
    },

    setSlide: function(index, initialize) {
        if(!this.wrap && !this.slides[index]) {
            return;
        }
        else if(this.wrap) {
            if(index < 0) {
                index = this.carouselSize-1;
            }
            else if(index > this.carouselSize-1) {
                index = 0;
            }
        }
        if(!this.slides[index]) {
            return;
        }

        if (this.fireEvent('beforechange', index, initialize) === false) {
        	return;
        }

		this.transition(index, initialize);

        this.activeSlide = index;
        this.updateNav();
        this.fireEvent('change', this.slides[index], index);
    },

    updateNav: function() {
    	if (this.els.navPrev) {
    		this.els.navPrev.removeClass('ux-carousel-nav-disabled');
 	        if(!this.wrap && this.activeSlide === 0) {
                this.els.navPrev.addClass('ux-carousel-nav-disabled');
	        }
    	}
        if (this.els.navNext) {
        	this.els.navNext.removeClass('ux-carousel-nav-disabled');
	        if(!this.wrap && this.activeSlide === this.carouselSize-1) {
                this.els.navNext.addClass('ux-carousel-nav-disabled');
	        }
        }
    }
});

Ext.ns('Ext.ux.SimpleCarouselTransitions');
Ext.apply(Ext.ux.SimpleCarouselTransitions, {
    linear: function (index, initialize){
    	if (initialize) {
    		var width=0, i, n;
    		if (this.circular && this.circularClones < this.carouselSize) {
    			for (i = 0; i < this.circularClones; i++){
    				n = this.slides[i].dom.cloneNode(true);
    				n.id = Ext.id();
    				this.els.slidesWrap.appendChild(n);
    				n = this.slides[this.slides.length - i - 1].dom.cloneNode(true);
    				n.id = Ext.id();
    				this.els.slidesWrap.insertFirst(n);
				}
    		}

			Ext.each(this.slides,function(i){
				i.slideWith = i.getWidth() + parseInt('0' + i.getStyle('margin-left'),10) + parseInt('0' + i.getStyle('margin-right'),10);// +3;
				width += i.slideWith;
			},this)

			if (this.circular && this.circularClones < this.carouselSize) {
    			for (i = 0; i < this.circularClones; i++){
    				width += this.slides[i].slideWith;
    				width += this.slides[this.slides.length - i - 1].slideWith;
				}
    		}

			this.els.slidesWrap.setWidth(width);
    	}
        var offset = this.slides[index].getLeft() - this.els.slidesWrap.getLeft() - parseInt(this.slides[index].getStyle('margin-left'),10);
        var xNew = (-1 * offset) + this.els.container.getX() + this.wrapOffset[0];
        if (!initialize) {
			this.els.slidesWrap.stopFx(false);
			if (this.circular && this.circularClones < this.carouselSize) {
				if(index == 0 && this.activeSlide == this.carouselSize-1) {
					this.els.slidesWrap.setX(xNew + this.slides[index].slideWith);
            	}
            	if(index == this.carouselSize-1 && this.activeSlide == 0) {
            		this.els.slidesWrap.setX(xNew - this.slides[this.carouselSize-1].slideWith);
            	}
			}

			this.els.slidesWrap.shift({
				duration: this.playing ? (this.autoTransitionDuration || this.transitionDuration) : this.transitionDuration,
				x: xNew,
				easing: this.playing ? (this.autoTransitionEasing || this.transitionEasing) : this.transitionEasing,
				callback: function(){
					this.fireEvent('transition', index);
				},
				scope: this
			});
        } else {
            this.els.slidesWrap.setX(xNew);
        }
	},
	vertical: function (index, initialize){
    	if (initialize) {
    		var height=0, i, n;
    		if (this.circular && this.circularClones < this.carouselSize) {
    			for (i = 0; i < this.circularClones; i++){
    				n = this.slides[i].dom.cloneNode(true);
    				n.id = Ext.id();
    				this.els.slidesWrap.appendChild(n);
    				n = this.slides[this.slides.length - i - 1].dom.cloneNode(true);
    				n.id = Ext.id();
    				this.els.slidesWrap.insertFirst(n);
				}
    		}

			Ext.each(this.slides,function(i){
				i.slideHeight = i.getHeight() + parseInt('0' + i.getStyle('margin-top'),10) + parseInt('0' + i.getStyle('margin-bottom'),10);// +3;
				height += i.slideHeight;
			},this)

			if (this.circular && this.circularClones < this.carouselSize) {
    			for (i = 0; i < this.circularClones; i++){
    				height += this.slides[i].slideHeight;
    				height += this.slides[this.slides.length - i - 1].slideHeight;
				}
    		}

			this.els.slidesWrap.setHeight(height);
    	}
        var offset = this.slides[index].getTop() - this.els.slidesWrap.getTop() - parseInt(this.slides[index].getStyle('margin-top'),10);
        var yNew = (-1 * offset) + this.els.container.getY() + this.wrapOffset[1];
        if (!initialize) {
			this.els.slidesWrap.stopFx(false);
			if (this.circular && this.circularClones < this.carouselSize) {
				if(index == 0 && this.activeSlide == this.carouselSize-1) {
					this.els.slidesWrap.setY(yNew + this.slides[index].slideHeight);
            	}
            	if(index == this.carouselSize-1 && this.activeSlide == 0) {
            		this.els.slidesWrap.setY(yNew - this.slides[this.carouselSize-1].slideHeight);
            	}
			}

			this.els.slidesWrap.shift({
				duration: this.playing ? (this.autoTransitionDuration || this.transitionDuration) : this.transitionDuration,
				y: yNew,
				easing: this.playing ? (this.autoTransitionEasing || this.transitionEasing) : this.transitionEasing,
				callback: function(){
					this.fireEvent('transition', index);
				},
				scope: this
			});
        } else {
            this.els.slidesWrap.setY(yNew);
        }
	},
	fade: function (index, initialize){
		if (initialize) {
    		var width=0;
			Ext.each(this.slides,function(i){
				i.setStyle({left: 0, top: 0, position: 'absolute', visibility: 'hidden', display: 'none'});
			},this);
			this.slides[index].show().setOpacity(1);
    	}
    	if (!initialize) {
			this.slides[index].setOpacity(0);
			this.slides[this.activeSlide].stopFx(false).fadeOut({
				useDisplay: true,
			    duration: this.transitionDuration / 2,
			    easing: this.playing ? (this.autoTransitionEasing || this.transitionEasing) : this.transitionEasing,
			    callback: function(){
			        this.slides[this.activeSlide].setOpacity(1);
			        this.slides[index].fadeIn({
			        	useDisplay: true,
			            duration: this.transitionDuration / 2,
			            easing: this.playing ? (this.autoTransitionEasing || this.transitionEasing) : this.transitionEasing,
			            callback: function(){
							this.fireEvent('transition', index);
						},
						scope: this
			        });
			    },
			    scope: this
			})
		}
	},
	crossfade: function (index, initialize){
		if (initialize) {
    		var width=0;
			Ext.each(this.slides,function(i){
				i.setStyle({left: 0, top: 0, position: 'absolute', visibility: 'hidden', display: 'none'});
			},this);
			this.slides[index].show().setOpacity(1);
    	}
    	if (!initialize) {
			this.slides[index].setOpacity(0);
			this.slides[this.activeSlide].setOpacity(1);
			this.slides[this.activeSlide].stopFx(false).syncFx().fadeOut({
			    duration: this.transitionDuration,
			    easing: this.playing ? (this.autoTransitionEasing || this.transitionEasing) : this.transitionEasing,
			    useDisplay: true
			})
			this.slides[index].stopFx(false).syncFx().fadeIn({
			    duration: this.transitionDuration,
			    easing: this.playing ? (this.autoTransitionEasing || this.transitionEasing) : this.transitionEasing,
			    useDisplay: true,
			    callback: function(){
						this.fireEvent('transition', index);
					},
				scope: this
			});
		}
	}
});

