/**
 * @license 
 * jQuery Tools @VERSION Scrollable - New wave UI design
 * 
 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
 * 
 * http://flowplayer.org/tools/scrollable.html
 *
 * Since: March 2008
 * Date: @DATE 
 */
(function ($) {

    // static constructs
    $.tools = $.tools || { version: '@VERSION' };

    $.tools.scrollable = {

        conf: {
            activeClass: 'active',
            circular: false,
            clonedClass: 'cloned',
            disabledClass: 'disabled',
            easing: 'swing',
            initialIndex: 0,
            item: null,
            items: '.items',
            itemsNumber: 1,
            keyboard: true,
            mousewheel: false,
            next: '.next',
            prev: '.prev',
            speed: 400,
            vertical: false,
            touch: true,
            wheelSpeed: 0
        }
    };

    // get hidden element's width or height even though it's hidden
    function dim(el, key) {
        var v = parseInt(el.css(key), 10);
        if (v) { return v; }
        var s = el[0].currentStyle;
        return s && s.width && parseInt(s.width, 10);
    }

    function find(root, query) {
        var el = $(query);
        return el.length < 2 ? el : root.parent().find(query);
    }

    var current;

    // constructor
    function Scrollable(root, conf) {

        // current instance
        var self = this,
			 fire = root.add(self),
			 itemWrap = root.children(),
			 index = 0,
			 vertical = conf.vertical;

        if (!current) { current = self; }
        if (itemWrap.length > 1) { itemWrap = $(conf.items, root); }

        // methods
        $.extend(self, {

            getConf: function () {
                return conf;
            },

            getIndex: function () {
                return index;
            },

            getSize: function () {
                return self.getItems().size();
            },

            getNaviButtons: function () {
                return prev.add(next);
            },

            getRoot: function () {
                return root;
            },

            getItemWrap: function () {
                return itemWrap;
            },

            getItems: function () {
                return itemWrap.children(conf.item).not("." + conf.clonedClass);
            },

            move: function (offset, time) {
                return self.seekTo(index + offset, time);
            },

            next: function (time) {
                return self.move(1, time);
            },

            prev: function (time) {
                return self.move(-1, time);
            },

            begin: function (time) {
                return self.seekTo(0, time);
            },

            end: function (time) {
                return self.seekTo(self.getSize() - 1, time);
            },

            focus: function () {
                current = self;
                return self;
            },

            addItem: function (item) {
                item = $(item);

                if (!conf.circular) {
                    itemWrap.append(item);
                } else {
                    itemWrap.children("." + conf.clonedClass + ":last").before(item);
                    itemWrap.children("." + conf.clonedClass + ":first").replaceWith(item.clone().addClass(conf.clonedClass));
                }

                fire.trigger("onAddItem", [item]);
                return self;
            },

            getVisibleItemCount: function (i) {
                if (i < 0)
                    i = 0;
                if (i >= self.getSize())
                    return 1;

                var wrapPos = 0,
		startIndex = i,
		rootSize = vertical ? root.innerHeight(true) : root.innerWidth(true);
                for (var loop = 0; loop < i; loop++)
                    wrapPos -= vertical ? self.getItems().eq(loop).outerHeight(true) : self.getItems().eq(loop).outerWidth(true);
                for (i; i < self.getSize(); i++) {
                    var item = self.getItems().eq(i),
			itemPos = vertical ? item.position().top + wrapPos : item.position().left + wrapPos,
			itemSize = vertical ? item.outerHeight(true) : item.outerWidth(true);
                    if (itemPos + itemSize > rootSize)
                        break;
                }
                return i - startIndex;
            },

            /* all seeking functions depend on this */
            seekTo: function (i, time, fn) {

                // ensure numeric index
                if (!i.jquery) { i *= 1; }

                // avoid seeking from end clone to the beginning
                if (conf.circular && i === 0 && index == -1 && time !== 0) { return self; }

                //Mike edit for 5 items
                var itemzNumber;
                if (conf.circular) { var itemzNumber = 0; } else { itemzNumber = conf.itemsNumber; }
                // check that index is sane
                if (!conf.circular && i < 0 || i > self.getSize() - itemzNumber || i < -1) { return self; }

                var item = i;

                if (i.jquery) {
                    i = self.getItems().index(i);

                } else {
                    item = self.getItems().eq(i);
                }

                // onBeforeSeek
                var e = $.Event("onBeforeSeek");
                if (!fn) {
                    fire.trigger(e, [i, time]);
                    if (e.isDefaultPrevented() || !item.length) { return self; }
                }

                var props = vertical ? { top: -item.position().top} : { left: -item.position().left };

                index = i;
                current = self;
                if (time === undefined) { time = conf.speed; }

                itemWrap.animate(props, time, conf.easing, fn || function () {
                    fire.trigger("onSeek", [i]);
                });

                return self;
            }

        });

        // callbacks	
        $.each(['onBeforeSeek', 'onSeek', 'onAddItem'], function (i, name) {

            // configuration
            if ($.isFunction(conf[name])) {
                $(self).bind(name, conf[name]);
            }

            self[name] = function (fn) {
                if (fn) { $(self).bind(name, fn); }
                return self;
            };
        });

        // circular loop
        if (conf.circular) {

            var cloned1 = self.getItems().slice(-1).clone().prependTo(itemWrap);
            var cloned2 = self.getItems().eq(1).clone().appendTo(itemWrap);

            //Mike edit for 5 items
            if (conf.itemsNumber == 10) {
                var cloned22 = self.getItems().eq(2).clone().appendTo(itemWrap);
                var cloned23 = self.getItems().eq(3).clone().appendTo(itemWrap);
                var cloned24 = self.getItems().eq(4).clone().appendTo(itemWrap);
                var cloned25 = self.getItems().eq(5).clone().appendTo(itemWrap);
                var cloned26 = self.getItems().eq(6).clone().appendTo(itemWrap);
                var cloned27 = self.getItems().eq(7).clone().appendTo(itemWrap);
                var cloned28 = self.getItems().eq(8).clone().appendTo(itemWrap);
                var cloned29 = self.getItems().eq(9).clone().appendTo(itemWrap);
                var cloned30 = self.getItems().eq(10).clone().appendTo(itemWrap);

                cloned1.add(cloned2).add(cloned22).add(cloned23).add(cloned24).add(cloned25).add(cloned26).add(cloned27).add(cloned28).add(cloned29).add(cloned30).addClass(conf.clonedClass);

            } else {
                cloned1.add(cloned2).addClass(conf.clonedClass);
            }

            self.onBeforeSeek(function (e, i, time) {


                if (e.isDefaultPrevented()) { return; }

                /*
                1. animate to the clone without event triggering
                2. seek to correct position with 0 speed
                */
                if (i == -1) {
                    self.seekTo(cloned1, time, function () {
                        self.end(0);
                    });
                    return e.preventDefault();

                } else if (i == self.getSize()) {
                    self.seekTo(cloned2, time, function () {
                        self.begin(0);
                    });
                }

            });

            // seek over the cloned item
            self.seekTo(0, 0, function () { });
        }

        // next/prev buttons
        
        var timerID;
        var prev = find(root, conf.prev).hover(function () {
            self.prev();
            timerID = setInterval(slidePrevMike, conf.speed);
        }, function () {
            clearInterval(timerID);
        });
        var next = find(root, conf.next).hover(function () {
            self.next();
            timerID = setInterval(slideNextMike, conf.speed);
        }, function () {
            clearInterval(timerID);
        });
        
        function slidePrevMike() {
            self.prev();
        }
        function slideNextMike() {
            self.next();
        }

        //var prev = find(root, conf.prev).click(function () { slidePrevMike(); });
        //var next = find(root, conf.next).click(function () { slideNextMike(); });

        var prev = find(root, conf.prev).click(function () { self.prev(); });
        var next = find(root, conf.next).click(function () { self.next(); });
        
        //Mike check for next button to be disabled
        if (self.getSize() <= conf.itemsNumber) {
            next.toggleClass(conf.disabledClass);
        }

        if (!conf.circular && self.getSize() > 1) {

            self.onBeforeSeek(function (e, i) {
                setTimeout(function () {
                    if (!e.isDefaultPrevented()) {
                        prev.toggleClass(conf.disabledClass, i <= 0);
                        next.toggleClass(conf.disabledClass, i >= self.getSize() - conf.itemsNumber);
                    }
                }, 1);
            });

            if (!conf.initialIndex) {
                prev.addClass(conf.disabledClass);
            }
        }

        // mousewheel support
        if (conf.mousewheel && $.fn.mousewheel) {
            root.mousewheel(function (e, delta) {
                if (conf.mousewheel) {
                    self.move(delta < 0 ? 1 : -1, conf.wheelSpeed || 50);
                    return false;
                }
            });
        }

        // touch event
        if (conf.touch) {
            var touch = {};

            itemWrap[0].ontouchstart = function (e) {
                var t = e.touches[0];
                touch.x = t.clientX;
                touch.y = t.clientY;
            };

            itemWrap[0].ontouchmove = function (e) {

                // only deal with one finger
                if (e.touches.length == 1 && !itemWrap.is(":animated")) {
                    var t = e.touches[0],
						 deltaX = touch.x - t.clientX,
						 deltaY = touch.y - t.clientY;

                    self[vertical && deltaY > 0 || !vertical && deltaX > 0 ? 'next' : 'prev']();
                    e.preventDefault();
                }
            };
        }

        if (conf.keyboard) {

            $(document).bind("keydown.scrollable", function (evt) {

                // skip certain conditions
                if (!conf.keyboard || evt.altKey || evt.ctrlKey || $(evt.target).is(":input")) { return; }

                // does this instance have focus?
                if (conf.keyboard != 'static' && current != self) { return; }

                var key = evt.keyCode;

                if (vertical && (key == 38 || key == 40)) {
                    self.move(key == 38 ? -1 : 1);
                    return evt.preventDefault();
                }

                if (!vertical && (key == 37 || key == 39)) {
                    self.move(key == 37 ? -1 : 1);
                    return evt.preventDefault();
                }

            });
        }

        // initial index
        if (conf.initialIndex) {
            self.seekTo(conf.initialIndex, 0, function () { });
        }
    }


    // jQuery plugin implementation
    $.fn.scrollable = function (conf) {

        // already constructed --> return API
        var el = this.data("scrollable");
        if (el) { return el; }

        conf = $.extend({}, $.tools.scrollable.conf, conf);

        this.each(function () {
            el = new Scrollable($(this), conf);
            $(this).data("scrollable", el);
        });

        return conf.api ? el : this;

    };


})(jQuery);

