if(!jQuery.easing.easeOutQuart) {
    jQuery.easing.easeOutQuart = function (x, t, b, c, d) {
        return -c * ((t=t/d-1)*t*t*t - 1) + b;
    };
    jQuery.easing.easeOutBack = function (x, t, b, c, d, s) {
        if (s == undefined) s = 1.70158;
        return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
    }
    jQuery.easing.easeOutElastic = function (x, t, b, c, d) {
        var s=1.70158; var p=0; var a=c;
        if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.5;
        if (a < Math.abs(c)) { a=c; var s=p/4; }
        else var s = p/(2*Math.PI) * Math.asin (c/a);
        return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
    } 
}
$.widget("ui.ism_carousel", {
    // ism-carousel
    // colapse any html symbol inside a carousel of a determinated number of symbol width
    //optionaly add a title overlay and dots for simgle symbol navigation

    //options
    options: {
        //item: "figure", //optional item to carousel
        caption: false,
        margin: 6,
        crop: 4,
        startAtItem : 0,
        arrows: true,
        width: 'auto',
        height: 'auto',
        nextText: "suiv.",
        prevText: "prec.",
        easing :'easeOutQuart', //easeOutQuart, easeOutBack, easeOutElastic, linear
        autoPlay: false,
        duration: 3000,
        speed: 1000,
        fx: 'slide',
        direction: 'horizontal',
        onAfterChange : null, //callback function onchange carousel
        dots: false,
        dotsOverlay: false //position of the dots
    },
	
	
    _create: function() {
		    this._createLoader();
            this._frontend();
            if(this.options.caption == true) this._caption_create();
    },
    
    _frontend: function () {
        var _this = this;
        
        this.items = this.element.children((this.options.item) ? this.options.item : undefined);
        
        //secure crop and startAtItem
        if(this.options.crop < 1) this.options.crop = 1;
        if(this.options.crop >= this.items.length) this.options.crop = this.items.length-1;
        
        //first active item
        if(this.options.startAtItem > this.items.length - this.options.crop) this.options.startAtItem = this.items.length - this.options.crop;
        this.activeItem = this.items.eq(this.options.startAtItem);
        
        this.hoverHandler = false;

        //adding a this.ism.wrapper inner
        this.element.wrapInner('<div class="ism-carousel-line" />');
        this.element.wrapInner('<div class="ism-carousel-wrapper" />');
        this.line = $('.ism-carousel-line', this.element);
        this.wrapper = $('.ism-carousel-wrapper', this.element);
        
        this.element.css({
            'display':'inline',
            'zoom': '1',
            'display':'inline-block',
            'position': 'relative',
            'width': 'auto'
        })
        
        if(this.options.fx == 'slide') {
        //display items horizontaly
            this.items.css({
                'position' : 'relative',
                'display': 'block',
                'float': 'left',
                'clear': (this.options.direction== 'horizontal') ? 'none': 'both',
                'margin': (this.options.direction== 'horizontal') ? '0px '+this.options.margin+'px 0px 0px' : '0px 0px '+this.options.margin+'px 0px'
            });
        } else {
            this.items.css({
                'position' : 'absolute',
                'display': 'block',
                'top': '0px',
                'left': '0px',
                'display': 'none'
            }); 
        } 
        
        //css of the wrapper
        this.wrapper.css({
            'display': 'block',
            'overflow': 'hidden',
            'position': 'relative',
            'width': (this.options.direction != 'horizontal') ? this._width() : (this._gap() * this.options.crop) - this.options.margin,
            'height': (this.options.direction == 'horizontal') ? this._height() : (this._vertical_gap() * this.options.crop) - this.options.margin
        });
        if(this.options.fx == 'slide') {
            //css of the line
            if(this.options.direction == 'horizontal') {
                this.line.css({
                    'width': this._gap() * this.items.length,
                    'height': this._height(),
                    'position' : 'absolute'
                })
            } else {
                this.line.css({
                    'width': this._width(),
                    'height': this._vertical_gap() * this.items.length,
                    'position' : 'absolute'
                })
            }
        }
        
        //dots
        if (this.options.dots) {
            this.dots = $('<div class="ism-carousel-dots"></div>').prependTo(this.element)

            this.dots.css({
                'position': 'absolute',
                'text-align': 'center',
                'z-index': 4
            });
            
            for(i=0; i<=this.items.length - this.options.crop; i++) {
                $('<a href="#">'+i+'</a>').appendTo(this.dots);
            }

            $("a", this.dots).click(function ()
            {
                var dotIndex = $(this).index();
                if(dotIndex > _this.items.length - _this.options.crop) dotIndex = _this.items.length - _this.options.crop;
                _this._scrollto($(_this.items).eq(dotIndex));
                return false;
            });
        }
        
        
        //next/prev arrows
        //adding arrows
        if (this.options.arrows) {
            this.prevArrow = $('<a href="#" class="ism-carousel-prev" title="'+this.options.prevText+'"><span>'+this.options.prevText+'</span></a>').prependTo(this.element);
            this.nextArrow = $('<a href="#" class="ism-carousel-next" title="'+this.options.nextText+'"><span>'+this.options.nextText+'</span></a>').prependTo(this.element);
        
            this.prevArrow.css({
                'display': 'block',
                'position': 'absolute',
                'top' : '50%',
                'left' : 0,
                'z-index' : 3
            }).click(function ()
            {
                _this.previous();
                return false;
            })
        
            this.nextArrow.css({
                'display': 'block',
                'position': 'absolute',
                'top' : '50%',
                'right' : 0,
                'z-index' : 3
            }).click(function ()
            {
                _this.next();
                return false;
            }) 
        }
        
        this._killLoader();
        //captions enable
        if(this.options.caption == true) {
            this._caption_create();
        }
        //scroll to startItem
        this._scrollto(this.activeItem);
        //autoPlay
        if(this.options.autoPlay == true) this.autoplay(); 
    },
    
    _caption_create:function () {
        var _this = this;
        
		this.caption = $('<div class="ism-carousel-caption"></div>').prependTo(this.element);
		this.caption.css({
			'display': 'block',
			'position' : 'absolute',
			'margin-top' : '-40px',
			'text-align': 'center',
			'opacity': 0,
			'white-space': 'no-wrap'
		})

		this.items.hover(function () {
			var position = $(this).position();
			var wrapperPos = _this.wrapper.position();
			var linePos = _this.line.position();
            if(_this.hoverHandler) {
    			_this.caption.html($(this).attr('title'))
    				.stop(false, true)
    				.animate({
    						left: position.left + wrapperPos.left + linePos.left - (_this.caption.outerWidth(true)/2) + ((_this._gap()-_this.options.margin)/2),
    						opacity: 1
    					}, 
    					_this.options.speed / 2,
    					_this.options.easing
    				);
			}
		}, function () {
		    if(_this.hoverHandler) { 
		        _this.caption.stop(false, true).animate({
    					// left: curPos*-1,
    					opacity: 0
    				}, 
    				_this.options.speed / 2,
    				_this.options.easing);
    		}  
		});
    },
    
    previous: function (boucle) {
        this._scrollto(this.activeItem.prev());
        if(this.options.autoPlay == true) this.pause();
        return false;
    },
        
    next:function (boucle) {
        if(this.activeItem.index() + this.options.crop >= this.items.length && boucle == true)
        {
            this._scrollto(this.items.first());
        }
        else
        {
            this._scrollto(this.activeItem.next())
        }
        if(this.options.autoPlay == true) this.pause();
        return false;
    },
    
    autoplay: function () {
        var _this = this;
        if (this.intervalID == null) this.intervalID = setInterval(function () { _this.next(true) }, this.options.duration);
    },

    pause: function () {
        var _this = this; 
        if (this.intervalID != null) {
            clearInterval(this.intervalID);
            this.intervalID = null;
        }

        if (this.timeOutAutoId != null) {
            clearTimeout(this.timeOutAutoId);
            this.timeOutAutoId = null;
        }
        this.timeOutAutoId = setTimeout(function () { _this.autoplay() }, this.options.duration);
    },

    _scrollto: function (item) {
        var _this = this;
        var  index = item.index();
        
        this.hoverHandler = false;
        if(this.options.caption) this.caption.stop(true, false).animate({opacity: 0}, 200, this.options.easing);
        
        if(index >= 0 && index <= this.items.length - this.options.crop)
        {
            if(this.options.fx == 'slide') {
                //slide transition
                if(this.options.direction == 'horizontal') {
                    var curPos = ((index * this._gap()))*-1;
                    //slide horizontal
                    this.line.stop(true, false).animate({left: curPos}, this.options.speed, this.options.easing, function () {
                        _this._onChange();
                    });
                } else {
                    var curPos = ((index * this._vertical_gap()))*-1;
                    //slide vertical
                    this.line.stop(true, false).animate({top: curPos}, this.options.speed, this.options.easing, function () {
                        _this._onChange();
                    });
                }
            } else {
                //defaut fade
                this.items.not(':eq('+index+')').stop(true, false).fadeOut(this.options.speed);
                item.stop(true, false).delay(this.options.speed/2).fadeIn(this.options.speed, function () {
                    _this._onChange();
                });
            }
            if (this.options.arrows) {
                // show/hide buttons
                if (index == 0) {
                    this.prevArrow.fadeOut('fast');
                } else {
                    this.prevArrow.show()
                }

                if(index >= this.items.length - this.options.crop) {
                    this.nextArrow.fadeOut('fast')
                } else {
                    this.nextArrow.show()
                }
            }
            this.activeItem = item;

            //adding class on current element
            $('.active', this.items).removeClass('active');
            this.activeItem.addClass('active');

            //adding class on current dot
            if (this.options.dots == true) {
                $('.active', this.dots).removeClass('active');
                $('a:eq('+item.index()+')', this.dots).addClass('active');
            }
        }
    },
    
    _createLoader: function () {
        this.loader = $('<div id="ism-carousel-loader" />').insertBefore(this.element);
        this.element.css('visibility', 'hidden');
    },
    
    _killLoader: function () {
        this.loader.hide();
        this.element.css('visibility', 'visible').hide().fadeIn();
    },
    
    _onChange: function () {
        if (this.options.onAfterChange) {
             this.options.onAfterChange();
        };
        this.hoverHandler = true;
    },
    
    _gap: function () {
         return this._width() + this.options.margin;
    },
    
    _vertical_gap: function () {
         return this._height() + this.options.margin;
    },
    
    _width: function () {
         if(this.options.width == "auto") return this.items.first().outerWidth();
         else return this.options.width;
    },
    
    _height: function () {
         if(this.options.height == "auto") return this.items.first().outerHeight();
         else return this.options.height;
    },
    
    length: function() {
        return this.items.length();
    },
    
    destroy: function() {
        $.Widget.prototype.destroy.apply(this, arguments);
    }
});
