﻿(function($) {
    $.fn.jCarouselDynamic = function(opt) {
        opt = $.extend({
            prevSelector: null,
            nextSelector: null,
            carouselSelector: 'ul',
            itemSelector: 'li',

            autoScrollSpeed: 0,
            scrollSpeed: 300,

            startItemIndex: 0,
            scrollItemCount: 1,
            circular: false,
            
            initialiseCallback: null
        }, opt || {});

        return this.each(function() {
            //var chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
            var carousel = $(this).find(opt.carouselSelector);
            var carouselWidth = 0;
            var clipWidth = carousel.parent().width();
            var carouselScrollLock = false;
            var itemIndex = opt.startItemIndex;
            var itemCount = 0;
            var firstItemIndex = 0;
            var lastItemIndex = 0;
            var preloadImages = null;
            var paused = false;

            preload();

            function preload() {
                preloadImages = new Array();

                carousel.find('img').each(function(index) {
                    var preloadImage = new Image();

                    preloadImage.src = $(this).attr('src');

                    preloadImages.push(preloadImage);
                });
            }

            function initialiseCircular() {
                if (opt.circular) {
                    var width = 0;
                    var items = new Array();
                    var itemIndex = 0;
                    var itemsParent = null;

                    carousel.find(opt.itemSelector).each(function(index) {
                        if (!itemsParent) itemsParent = $(this).parent();

                        items.push($(this));
                    });

                    firstItemIndex = 0;
                    lastItemIndex = items.length;
                    width = 0;

                    for (itemIndex = items.length - 1; itemIndex >= 0; itemIndex--) {
                        if (width <= clipWidth) {
                            width += items[itemIndex].outerWidth();

                            firstItemIndex++;

                            itemsParent.prepend(items[itemIndex].clone());
                        }
                    }

                    width = 0;

                    for (itemIndex = 0; itemIndex < items.length; itemIndex++) {
                        if (width <= clipWidth) {
                            width += items[itemIndex].outerWidth();

                            itemsParent.append(items[itemIndex].clone());
                        }
                    }
                }
            }

            function initialiseWidth() {
                carouselWidth = 0;
                itemCount = 0;

                carousel.find(opt.itemSelector).each(function(index) {
                    var item = $(this);

                    carouselWidth += item.outerWidth();

                    itemCount++;
                });

                carousel.width(carouselWidth);
            }

            function initialiseIndex() {
                if (opt.startItemIndex > 0)
                    goToItem(firstItemIndex + opt.startItemIndex);
                else
                    goToItem(firstItemIndex);
            }

            function initialiseAutoScroll() {
                if (opt.autoScrollSpeed && opt.autoScrollSpeed > 0) {
                    setInterval(function() {
                        if (!paused) moveToItem(itemIndex + 1);
                    }, opt.autoScrollSpeed);
                }
            }

            function itemsInClip(fromItemIndex) {
                var clipItemCount = 0;
                var width = 0;

                carousel.find(opt.itemSelector).each(function(index) {
                    var item = $(this);

                    if (index >= fromItemIndex && width <= clipWidth) {
                        width += item.outerWidth();

                        clipItemCount++;
                    }
                });

                return clipItemCount;
            }

            function goToItem(toItemIndex) {
                if (itemIndex != toItemIndex && toItemIndex >= 0 && toItemIndex < (itemCount - 1)) {
                    var carouselLeft = 0;

                    carousel.find(opt.itemSelector).each(function(index) {
                        if (index < toItemIndex)
                            carouselLeft -= $(this).outerWidth();
                    });

                    if (carouselLeft > 0)
                        carouselLeft = 0;

                    if (carouselLeft < (0 - (carouselWidth - clipWidth)))
                        carouselLeft = (0 - (carouselWidth - clipWidth));

                    carousel.css('left', (carouselLeft) + 'px');
                    itemIndex = toItemIndex;
                }
            }

            function moveToItem(toItemIndex) {
                if (opt.circular && toItemIndex < firstItemIndex && toItemIndex < itemIndex) {
                    var index = itemIndex;

                    goToItem(index + lastItemIndex);

                    toItemIndex = (index + lastItemIndex) - 1;
                }

                if (opt.circular && toItemIndex > lastItemIndex && toItemIndex > itemIndex) {
                    var index = itemIndex;

                    goToItem(index - lastItemIndex);

                    toItemIndex = (index - lastItemIndex) + 1;
                }

                if (itemIndex != toItemIndex && toItemIndex >= 0 && toItemIndex < (itemCount - 1) && !carouselScrollLock) {
                    carouselScrollLock = true;

                    var carouselFromLeft = carousel.position().left;
                    var carouselToLeft = 0;
                    var animLeft = 0;

                    carousel.find(opt.itemSelector).each(function(index) {
                        if (index < toItemIndex)
                            carouselToLeft -= $(this).outerWidth();
                    });

                    if (carouselToLeft > 0)
                        carouselToLeft = 0;

                    if (carouselToLeft < (0 - (carouselWidth - clipWidth)))
                        carouselToLeft = (0 - (carouselWidth - clipWidth));

                    if (carouselToLeft != carouselFromLeft) {
                        if (carouselToLeft < carouselFromLeft) {
                            animLeft = (carouselFromLeft - carouselToLeft);

                            carousel.animate({ left: '-=' + animLeft }, opt.scrollSpeed, function() { itemIndex = toItemIndex; carouselScrollLock = false; });
                        } else if (carouselToLeft > carouselFromLeft) {
                            animLeft = (carouselToLeft - carouselFromLeft);

                            carousel.animate({ left: '+=' + animLeft }, opt.scrollSpeed, function() { itemIndex = toItemIndex; carouselScrollLock = false; });
                        }
                    } else {
                        carouselScrollLock = false;
                    }
                }
            }

            $(window).load(function () {
                initialiseCircular();
                initialiseWidth();
                initialiseIndex();
                initialiseAutoScroll();

                if (opt.initialiseCallback && typeof opt.initialiseCallback == 'function')
                    opt.initialiseCallback.call(this);
            });

            carousel.hover(function() {
                paused = true;
            }, function() {
                paused = false;
            });

            if(opt.prevSelector) {
                $(opt.prevSelector).hover(function() {
                    paused = true;
                }, function() {
                    paused = false;
                });

                $(opt.prevSelector).click(function() {
                    moveToItem(itemIndex - opt.scrollItemCount);
                });
            }

            if(opt.nextSelector) {
                $(opt.nextSelector).hover(function() {
                    paused = true;
                }, function() {
                    paused = false;
                });

                $(opt.nextSelector).click(function() {
                    moveToItem(itemIndex + opt.scrollItemCount);
                });
            }

        });
    }
})(jQuery);

