/*
 * Cornerstone UI Carousel Widget
 *
 *
 * http://docs.jquery.com/UI/Tabs
 *
 * Depends:
 *	ui.core.js
 */
(function($) {

$.widget("ui.cscarousel", {

	_init: function() {
		var self = this, o = this.options;
		self.moving = false;
		self.position = isNaN(o.position)?0:o.position;
		self._pos = self.position;
		this.element.css("visibility", "visible");

		this._fixList(true);

		this._autoId = false;

		if(o.btnPrev)
			$(o.btnPrev).bind('click', function() {
				return self._go(self._pos-o.scroll);
			});

		if(o.btnNext)
			$(o.btnNext).bind('click', function() {
				return self._go(self._pos+o.scroll);
			});

		if(o.btnGo) {
			$.each(o.btnGo, function(i, val) {
				$(val).bind('click', function() {
					return self._go(o.circular ? o.visible+i : i);
				});
			});
			$(o.btnGo[this._i(self._pos)]).addClass('ui-active');
		}

		if(o.mouseWheel && this.element.mousewheel)
			this.element.mousewheel(function(e, d) {
				self._go(self._pos-(d<0 ? -1 : 1), false, true);
				return false;
			});

		if(o.run) {
		        this._beforeauto(o.reverse ? (self._pos-o.scroll) :
		            (self._pos+o.scroll));
			this._autoId = setInterval(function() {
				if (o.reverse) {
				    self._go(self._pos-o.scroll, true);
				} else {
					self._go(self._pos+o.scroll, true);
				}	
			}, o.auto+o.speed);
		}

		if(o.btnStop) {
			$(o.btnStop).addClass(o.run ? "ui-running" : "ui-stopped").bind('click', function() {
				if(!self.stop())
					self.start();
			});
		}

        function vis() {
            return li.slice(self._pos).slice(0,v);
        };
	},

	_offset: function(el, val) {
	    el.css(this.options.vertical ? 'top' : 'left', val + "px");
	    return this;
	},

	_size: function(el, val) {
	    el.css(this.options.vertical ? 'height' : 'width', val + "px");
	    return this;
	},

    _max: function(el, attr) {
        var maxDim = 0;
        var index = 0;
        el.each(function(i) {
            if (this[attr] > maxDim) {
                maxDim = this[attr];
                index = i;
            }
        });
        return el.eq(index);
    },

	_fixList: function(init) {
	    var self = this, o = this.options, v = o.visible;
	    if (init) {
		    this.list = $("ul", this.element);
		    this.items = $("li", this.list);

    		if (o.circular) {
    			this.list.prepend(this.items.slice(this.items.size() - v).clone().addClass('ui-carousel-wrap'))
    			  .append(this.items.slice(0, v).clone().addClass('ui-carousel-wrap'));
    			this._pos += v;
    		}
		    this.list.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"});
		    if (o.effect == 'fade') {
		        var e = document.createElement('div');
		        this.element.append(e);
		        e = $(e);
		        this.effectElement = e;
		        e.css({position: 'absolute', left: 0, top: 0, 'display' : 'none'});
		    }
	    } else {
	        this.items = $("li:not(.ui-carousel-wrap)", this.list);
	    }
	    this._li = $("li", this.list); // All li with possible wrap elements

		this._li.css({display: "block", overflow: "hidden", "float": "left", clear: o.vertical ? "both" : "none"});
		this.element.css({overflow: "hidden", position: "relative", "z-index": "2", left: "0px"});

		var maxW = this._max(this._li, 'offsetWidth');
		var maxH = this._max(this._li, 'offsetHeight');
		this._iL = o.vertical ? (maxH.height() + css(maxH, 'marginTop') + css(maxH, 'marginBottom')) :
		    (maxW.width() + css(maxW, 'marginLeft') + css(maxW, 'marginRight'));

		this._li.css({height: maxH.height(), width: maxW.width()});

		this._offset(this.list, -(self._pos * this._iL))._size(this.list, this._li.size() * this._iL);

		this._size(this.element, this._iL * v);					 // Width of the DIV. length of visible images
		if (this.effectElement) {
		    this.effectElement.height(this.element.height()).width(this.element.width());
		}
        function css(e, p) {
            return parseInt($.css(e[0], p)) || 0;
        };
        if (o.vertical) {
            var w = maxW.width();
            this.list.width(w);
            this.element.width(w);
        }
	},

    stop: function() {
        var o = this.options;
        if(this._autoId == false)
            return false;

        clearInterval(this._autoId);
        this._autoId = false;
        if (o.btnStop)
            $(o.btnStop).removeClass("ui-running").addClass("ui-stopped");
        return true;
    },

    start: function() {
        var self = this, o = this.options;
        if(this._autoId != false)
            return false;
        if (o.btnStop)
            $(o.btnStop).removeClass("ui-stopped").addClass("ui-running");
        this._go(this._pos+o.scroll, true);
        this._beforeauto(self._pos+o.scroll);
        this._autoId = setInterval(function() {
            self._go(self._pos+o.scroll, true);
        }, o.auto+o.speed);
    },

    go: function(index) {
        var o = this.options;
        if (typeof index == 'string') {
            if (index == 'NEXT') {
                this._go(this._pos + o.scroll);
            } else if (index == 'PREV') {
                this._go(this._pos - o.scroll);
            }
        } else {
            this._go(o.circular ? o.visible + index : index);
        }
    },

    _to: false,
    
    _beforeauto: function(to) {
        var self = this, o = this.options;
        var totalItems = this._li.size(), v = o.visible, liSize = this._iL;
        if(o.circular) {
            if (to < 0) {// 'to' position wrapping
                to = (to % (totalItems + 1)) + totalItems - (2*v);
            } else if (to > (totalItems-v)) {
                to = (to % (totalItems + 1)) - totalItems + (2*v);
            }
        } else {
            if (to < 0) {
                return;
            } else if (to > (totalItems - v)) {
                to = totalItems - v;
                if (prev == to) return;
            }
        }
        var data = {carousel: this, from: this._i(this._pos), to: this._i(to)};
        this._trigger('beforeauto', null, data);
    },

    _go: function(to, isAuto, isWheel) {
        var self = this, o = this.options;

        this._to = false;
        if (this.moving) {
            var tt = this._to;
            if (isWheel && tt && tt.isWheel) {
                if (to < this._pos && tt.to < this._pos) {
                    to = tt.to - 1;
                } else if (to > this._pos && tt.to > this._pos) {
                    to = tt.to + 1;
                }
            }
            this._to = {to: to, isAuto: isAuto, isWheel: isWheel};
            return false;
        }

        var prev = this._pos; // Save position to change btnGo styles

        if(!isAuto && this._autoId !== false)
            this.stop();

        // _beforeauto has copy of this code with slight difference
        var totalItems = this._li.size(), v = o.visible, liSize = this._iL;
        if(o.circular) {
            if (to < 0) {// 'to' position wrapping
                to = (to % (totalItems + 1)) + totalItems - (2*v);
            } else if (to > (totalItems-v)) {
                to = (to % (totalItems + 1)) - totalItems + (2*v);
            }
            if (this._pos <= v && to > (totalItems/2)) {// moving to closest end
                this._pos = totalItems-(2*v)+this._pos;
                this._offset(this.list, -this._pos*liSize);
            } else if (this._pos >= totalItems-(2*v) && to < (totalItems/2)) {
                this._pos = this._pos-totalItems+(2*v);
                this._offset(this.list, -this._pos*liSize);
            }
        } else {
            if (to < 0) {
                return;
            } else if (to > (totalItems - v)) {
                to = totalItems - v;
                if (isAuto) this.stop();
                if (prev == to) return;
            }
        }
        var data = {carousel: this, from: this._i(prev), to: this._i(to)};
        this._trigger('beforemove', null, data);

        var imgChecksCount = 0;
        this.moving = true;
        var moveInterval = false;
        (function move() {
            if (moveInterval != false) {
                // Prevents parallel flows racing
                clearInterval(moveInterval);
                moveInterval = false;
            }
            var isLoaded = true;
            for (var i = to; i < (to+v); ++i) {
                $('img', self._li.get(i)).each(function (ind, img) {
                    if (!img.complete) {
                        isLoaded = false;
                        return false;
                    }
                });
                if (!isLoaded) {
                    if (imgChecksCount < 10) {
                        self._to = false;
                        ++imgChecksCount;
                        moveInterval = setInterval(move, 300);
                        return;
                    } else {
                        break;
                    }
                }
            }

            self._pos = to;
            self.position = self._i(self._pos);
            o.positionElement.val(self.position);
    
            var t = o.speed;
            if (isWheel) t = 50;
            var afterEffectCallback = function() {
                if (t > 0 && o.effect == "fade") {
                    self._offset(self.list, -self._pos*liSize);
                    self.list.css('opacity', 1);
                    self.effectElement.empty().hide();
                }
                self.moving = false;
                self._trigger('aftermove', null, data);
                var opt = self._to;
                if (opt != false) {
                    self._go(opt.to, opt.isAuto, opt.isWheel);
                }
            };
            if(t > 0 && o.effect == "fade") {
                var e = self.effectElement.css({opacity: 0, display: 'block'});
                e.append(self._li.slice(to, to + v).clone());
                self.list.animate({opacity:0}, {queue:false, duration:t, complete: afterEffectCallback});
                e.animate({opacity:1}, {queue:false, duration:t});
            } else {
                self.list.animate(
                    o.vertical ? { top: -(self._pos*liSize) } : { left: -(self._pos*liSize) } , t, o.easing,
                    afterEffectCallback
                );
            }
            if(o.btnGo) {
                $(o.btnGo[self._i(prev)]).removeClass('ui-active');
                $(o.btnGo[self._i(self._pos)]).addClass('ui-active');
            }
            // Disable buttons when the carousel reaches the last/first, and enable when not
            if(!o.circular) {
                $(o.btnPrev + "," + o.btnNext).removeClass("ui-disabled");
                $( (self._pos-o.scroll<0 && o.btnPrev)
                    ||
                   (self._pos+o.scroll > totalItems-v && o.btnNext)
                    ||
                   []
                 ).addClass("ui-disabled");
            }
        })();
        return true;
    },

    _i: function(pos) {
        var o = this.options, l = this.items.size();
        if (!o.circular)
            return pos;
        pos -= o.visible;
        if (pos < 0)
            return l + pos;
        if (pos >= l)
            return pos - l;
        return pos;
    },
/*
	_setData: function(key, value) {
		if (key == 'selected') {
			if (this.options.collapsible && value == this.options.selected) {
				return;
			}
			this.select(value);
		}
		else {
			this.options[key] = value;
			if (key == 'deselectable') {
				this.options.collapsible = value;
			}
			this._tabify();
		}
	},
*/
	destroy: function() {
		var o = this.options;

		//TODO: implement
	},

	add: function(content, index) {
		var o = this.options, v = o.visible, len = this.items.length;
		if (index === undefined) {
			index = len; // append by default
		}
		var item = document.createElement('li');
	    if (index == len) {
	        if (o.circular && len > 0) {
	            this.items.eq(index - 1).after(item);
	        } else {
	            this.list.append(item);
	        }
	    } else {
	        this.items.eq(index).before(item);
	    }
	    item = $(item).append(content);
		if (o.circular) {
		    if (len < v) {
    	        $("li", this.list).eq(index).before(item.clone().addClass('ui-carousel-wrap'));
    	        $("li", this.list).eq(2*len+1+index).after(item.clone().addClass('ui-carousel-wrap'));
		    } else {
    		    if (index < v) {
                    var l = $("li", this.list);
                    l.slice(len + v + 1 + index).each(function(i, e) {$(e).replaceWith(l.eq(i - len - v).clone().addClass('ui-carousel-wrap'));});
    		    }
    		    if (index > (len - v)) {
                    var l = $("li", this.list);
                    l.slice(len - index + 1 - v, v).each(function(i, e) {$(e).replaceWith(l.eq(i + len + 1).clone().addClass('ui-carousel-wrap'));});
    		    }
		    }
		}
		this._fixList();

		// callback
		this._trigger('add', null, {});
	},

	remove: function(index) {
		var o = this.options;

		//TODO: implement

		// callback
		this._trigger('remove', null, {});
	},

	enable: function(index) {
		var o = this.options;
		//TODO: implement

		// callback
		this._trigger('enable', null, {});
	},

	disable: function(index) {
		var self = this, o = this.options;
		//TODO: implement

		// callback
		this._trigger('disable', null, {});
	},

	abort: function() {
	    //TODO: implement as stop of any animation
	},

	length: function() {
		return this.items.length;
	}

});

$.extend($.ui.cscarousel, {
	version: '1.0.0',
	defaults: {
        btnPrev: null,
        btnNext: null,
        btnGo: null,
        btnStop: null,
        mouseWheel: false,
        auto: 2000,
        run: false,

        effect: "slide",
        speed: 200,
        easing: null,

        vertical: false,
        circular: true,
        visible: 3,
        position: 0,
        scroll: 1
	}
});

})(jQuery);
