﻿(function($) {
    $.fn.PagingCarousel = function(options) {
        // Set the options.
        var opts = $.extend({}, $.fn.PagingCarousel.defaults, options);

        // Go through the matched elements and return the jQuery object.
        return this.each(function() {
            // Extend our options object with metadata from the DOM
            var o = $.metadata ? $.extend({}, opts, $(this).metadata()) : opts;

            var isRunning = false;

            var carouselDiv = $(this);

            var itemDiv = $('div.wrapper', carouselDiv);
            var itemUl = $('ul', carouselDiv);
            var itemLi = $('li', itemUl);

            var carouselWidth = carouselDiv.width();

            var pagingDiv = carouselDiv.siblings(o.pagingClass);

            var prevBtn = carouselDiv.siblings(o.prevButtonClass);
            var nextBtn = carouselDiv.siblings(o.nextButtonClass);

            // Item number to start paging from
            var itemCurr;
            // The page that we want to start paging from
            var pageCurr;
            // The total number of pages
            var pageCount;
            // The current maxpage slice we are on
            var sliceCurr;
            // The total number of maxpage slices
            var sliceCount;
            // Set the above counters starting at our item start number
            updateCount(o.itemStart);

            // We need to set the wrapper div to twice the width of the carousel to get a nice scrolling effect
            itemDiv.width(carouselWidth * 2);

            // Replace the paging buttons on load
            buildPaging();
            // Highlight the current page on load
            updatePaging();
            // Highlight the next/prev buttons on load
            updateNavigation();

            $.extend($.fn.PagingCarousel, {
                RefreshId: function(id) {
                    if (id && (id.length > 0)) {
                        o.params.uniqueid = id;
                        $.ajax({
                            type: 'get',
                            url: o.url,
                            data: $.extend({ start: 1, date: new Date().getTime() }, o.params),
                            dataType: 'json',
                            success: function(data) {
                                if (data.Success) {
                                    o.itemTotal = data.TotalResultCount;
                                    updateCount(1);

                                    itemDiv.empty().append(buildItems(data)).hide().fadeIn(o.speed);

                                    buildPaging();
                                    updatePaging();
                                    updateNavigation();

                                    itemUl = $("ul", itemDiv);

                                    o.onRefresh.call(carouselDiv, o);
                                }
                            }
                        });
                    }
                    else {
                        o.itemTotal = 0;
                        updateCount(0);

                        itemUl.empty();

                        buildPaging();
                        updatePaging();
                        updateNavigation();

                        itemUl = $("ul", itemDiv);

                        o.onRefresh.call(carouselDiv, o);
                    }
                }
            });

            // Function that will scroll the carousel to the specified item number
            function goToItem(itemGoTo) {
                // Check to see whether an animation is already running and that the requested item is within range
                if (!isRunning && !isOutOfRange(itemGoTo)) {
                    isRunning = true;
                    $.ajax({
                        type: 'get',
                        url: o.url,
                        data: $.extend({ start: itemGoTo, date: new Date().getTime() }, o.params),
                        dataType: 'json',
                        success: function(data) {
                            if (data.Success) {
                                o.itemTotal = data.TotalResultCount;
                                updateCount();

                                var itemUlNew = buildItems(data);
                                var itemUlOld = itemUl;
                                var scrollPos;

                                if (itemGoTo < itemCurr) {
                                    scrollPos = 0;
                                    itemDiv.prepend(itemUlNew).css({ left: -(carouselWidth) });
                                } else {
                                    scrollPos = -(carouselWidth);
                                    itemDiv.append(itemUlNew).css({ left: 0 });
                                }

                                itemDiv.animate({ left: scrollPos }, o.speed, 'swing', function() {
                                    itemUlOld.remove();
                                    itemDiv.css({ left: 0 });

                                    itemCurr = itemGoTo;
                                    pageCurr = Math.floor((itemCurr / o.pageSize) + (itemCurr % o.pageSize > 0 ? 1 : 0));

                                    updatePaging();
                                    updateNavigation();

                                    itemUl = $("ul", itemDiv);
                                    isRunning = false;
                                });
                            }
                        }
                    });

                    return true;
                }
                return false;
            }

            // Function that will build our paging navigation and binds our click events
            function buildPaging() {
                var pageStart = ((sliceCurr - 1) * o.maxPages);
                var pageMax = (pageStart + o.maxPages) > pageCount ? pageCount : pageStart + o.maxPages;

                pagingDiv.each(function() {
                    var pagingUl = $('ul', this);
                    var pagingLi = $('li', pagingUl);

                    pagingUl.empty();

                    if (o.setPagingWidth) {
                        pagingUl.width((pageMax * 9) + (pageMax * 10));
                    }

                    // Build the previous max page jump button 
                    // TODO: Clean this function up later
                    if ((pageStart + 1) > o.maxPages && o.showJumpButton) {
                        var page = pageStart - 1;
                        var itemStart = (page * o.pageSize) + 1;
                        var prevJumpLi = $('<li/>').addClass('go-jump').html('<a href="?start=' + itemStart + '&amp;id=' + o.params.uniqueid + '">&laquo;</a>\n');
                        prevJumpLi.data('itemStart', itemStart);
                        prevJumpLi.data('page', page);

                        prevJumpLi.click(function(ev) {
                            if (!goToItem($(this).data('itemStart')))
                                updatePaging();
                            ev.preventDefault();
                        });

                        pagingUl.append(prevJumpLi);
                    }

                    // Build the paging buttons for this max page slice
                    for (i = pageStart; i < pageMax && pageMax > 1; i++) {
                        var page = i + 1;
                        var itemStart = (i * o.pageSize) + 1;

                        var newPageLi = $('<li/>').addClass('go').html('<a href="?start=' + itemStart + '&amp;id=' + o.params.uniqueid + '">' + page + '</a>\n');

                        newPageLi.data('itemStart', itemStart);
                        newPageLi.data('page', page);

                        newPageLi.click(function(ev) {
                            if (!goToItem($(this).data('itemStart')))
                                updatePaging();
                            ev.preventDefault();
                        });
                        pagingUl.append(newPageLi);
                    }

                    // Build the next max page jump button 
                    // TODO: Clean this function up later
                    if (pageMax < pageCount && o.showJumpButton) {
                        var page = i + 1;
                        var itemStart = (i * o.pageSize) + 1;
                        var nextJumpLi = $('<li/>').addClass('go-jump').html('<a href="?start=' + itemStart + '&amp;id=' + o.params.uniqueid + '">&raquo;</a>\n');
                        nextJumpLi.data('itemStart', itemStart);
                        nextJumpLi.data('page', page);

                        nextJumpLi.click(function(ev) {
                            if (!goToItem($(this).data('itemStart')))
                                updatePaging();
                            ev.preventDefault();
                        });

                        pagingUl.append(nextJumpLi);
                    }
                });
            }

            // Highlights the relevant page and determines whether we need to rebuild the paging buttons
            function updatePaging() {
                var sliceNext = Math.floor((itemCurr / (o.pageSize * o.maxPages)) + (itemCurr % (o.pageSize * o.maxPages) > 0 ? 1 : 0));

                pagingDiv.each(function() {
                    // Only rebuild paging if were heading to a new slice
                    if (sliceNext != sliceCurr && o.showJumpButton) {
                        sliceCurr = sliceNext;
                        buildPaging();
                    }

                    var pagingUl = $('ul', this);
                    var pagingLi = $('li', pagingUl);

                    pagingLi.removeClass('selected');
                    pagingLi.each(function() {
                        if ($(this).data('itemStart') == itemCurr) {
                            $(this).addClass('selected');
                        }
                    });
                });
            }

            // Highlights the next and previous buttons and binds our click events
            function updateNavigation() {
                prevBtn.each(function() {
                    var prevBtnText = $(this).text();
                    if (isOutOfRange(itemCurr - o.pageSize))
                        $(this).addClass('disabled').html('<span>' + prevBtnText + '</span>');
                    else {
                        $(this).removeClass('disabled').html('<a href="?start=' + (itemCurr - o.pageSize) + '&amp;id=' + o.params.uniqueid + '">' + prevBtnText + '</a>');

                        $(this).click(function(ev) {
                            return goToItem(itemCurr - o.pageSize);
                            ev.preventDefault();
                        });
                    }
                });

                nextBtn.each(function() {
                    var nextBtnText = $(this).text();
                    if (isOutOfRange(itemCurr + o.pageSize))
                        $(this).addClass('disabled').html('<span>' + nextBtnText + '</span>');
                    else {
                        $(this).removeClass('disabled').html('<a href="?start=' + (itemCurr + o.pageSize) + '&amp;id=' + o.params.uniqueid + '">' + nextBtnText + '</a>');

                        $(this).click(function(ev) {
                            return goToItem(itemCurr + o.pageSize);
                            ev.preventDefault();
                        });
                    }
                });

                // Prevent the anchor tags from triggering a page request
                $('a', nextBtn).click(function(ev) {
                    ev.preventDefault();
                });
                $('a', prevBtn).click(function(ev) {
                    ev.preventDefault();
                });
            }

            function updateCount(goTo) {
                if (!(goTo === undefined)) itemCurr = goTo;
                pageCurr = Math.floor((itemCurr / o.pageSize) + (itemCurr % o.pageSize > 0 ? 1 : 0));
                pageCount = Math.floor((o.itemTotal / o.pageSize) + (o.itemTotal % o.pageSize > 0 ? 1 : 0));
                sliceCurr = Math.floor((itemCurr / (o.pageSize * o.maxPages)) + (itemCurr % (o.pageSize * o.maxPages) > 0 ? 1 : 0));
                sliceCount = Math.floor((o.itemTotal / (o.pageSize * o.maxPages)) + (o.itemTotal % (o.pageSize * o.maxPages) > 0 ? 1 : 0));
            }

            function highlightItem() {
                if (o.highlightItem) {
                    $('li', itemUl).each(function() {
                        if ($(this).data('itemId') == o.highlightItem)
                            $(this).addClass('selected');
                    });
                }
            }

            // Build the html for the items given our json data
            function buildItems(data) {
                var itemUlNew = itemUl.clone().empty();

                $.each(data.List, function(i, tile) {
                    var newItem = $(o.formatResult.call(tile));

                    if (!(tile.ItemId === undefined) && tile.ItemId == o.highlightItem)
                        newItem.addClass('selected');

                    itemUlNew.append(newItem);
                });

                return itemUlNew;
            }

            // Function to check whether the requested item is out of range
            function isOutOfRange(itemGoTo) {
                var isLessThan = itemGoTo < 1;
                var isGreaterThan = itemGoTo > o.itemTotal;
                var isCurrPage = itemCurr == itemGoTo;
                var isMaxPage = (itemGoTo > (o.maxPages * o.pageSize)) && !o.showJumpButton;

                return (isLessThan || isGreaterThan || isCurrPage || isMaxPage)
            }
        });
    };
    // Public defaults.
    $.fn.PagingCarousel.defaults = {
        url: null,
        params: null,
        allItemUrl: null,
        pagingClass: '.tiles-nav.jump',
        nextButtonClass: '.nextButton',
        prevButtonClass: '.prevButton',
        showJumpButton: false,
        setPagingWidth: false,
        speed: 700,
        pageSize: null,
        itemStart: null,
        itemTotal: null,
        maxPages: 10,
        highlightItem: null,
        formatResult: formatItem,
        onRefresh: function() { }
    };

    function formatItem() {
        var item = '';
        var dateCreated = !(window.dateFormat === undefined) ? this.Created.format("d mmm yyyy") : this.Created;
        item += '<li>';
        item += '  <em><a href="/Items/' + this.ItemId + '">' + $('<div/>').text(this.Name).html() + '</a></em>';
        item += '  <dl>';
        item += '      <dt>Date Uploaded:</dt>';
        item += '      <dd>' + dateCreated + '</dd>';
        item += '  </dl>';
        if (this.ThumbnailUri.length > 0)
            item += '  <a href="/Items/' + this.ItemId + '"><img src="' + this.ThumbnailUri + '"  alt="Photo of ' + this.Name + '" /></a>';
        item += '  <div class="extend"></div';
        item += '</li>';
        return item;
    }
})(jQuery);