﻿/*
 * imCarousel.js
 * Liam Smith
 * InfoMine Inc.
 * August 6, 2009
*/

/* INSTRUCTIONS
 * 
 * Step 1: Create Web Service:
 * 
 A web service must be created to feed the carousel with data. The URL to the web service should be entered
 * in the 'url' option of the carousel. The web service should accept 2 parameters, 'from' and 'to' which indicate
 * the indexes of the images to download. Images should be sent to the carousel in the following format:
 *
 *      [jsoncallback]({
 *          'name': 'My Image Feed',
 *          'from': 1,
 *          'to': 10,
 *          'images'
 *          [
 *              {
 *                  'src': 'http://www.infomine.com/section/image.jpg',
 *                  'url': 'http://www.infomine.com/somepage.html'
 *              },
 *              .
 *              .
 *              .
 *              .
 *          ]
 *      })
 *
 * The 'src' element defines the location of the image file, and the 'url' element defines where the image should
 * link to. Note, if the carousel requests images outside the range that are available, no images should be returned.
 *
 * Step 2: Add carousel to page:
 *
 * The carousel requires a <div> tag to work. A temporary loading graphic can be added to the div tag, but this will be
 * cleared as soon as the carousel begins. The following parameters can be passed to the carousel function:
 *
 *      url: The URL of the web service to load data from. 
 *      visible: The number of images that will be visible at a time. [optional]
 *      delay: How long (in milliseconds) to wait before scrolling the carousel. [optional]
 *      speed: The speed (in milliseconds) to animate the carousel. [optional]
 *      imgWidth: The width (in pixels) of the images in the carousel. Note that this must be the total width of
 *           the image, including any padding, borders, and/or margins.
 *      imgHeight: The height (in pixels) of the images in the carousel. Note that this must be the total height of
 *           the image, including any padding, borders, and/or margins.
 *
 * Example:
 * 
 * <div id="divMyCarousel">Loading Carousel...</div>
 * <script language="javascript type="text/javascript">
 *      $(document).ready(function()
 *      {
 *           $('#divMyCarousel').imCarousel(
 *           {
 *                url: 'http://www.infomine.com/myimageservice.ashx',
 *                visible: 5,
 *                delay: 2000,
 *                speed: 800,
 *                imgWidth: 100,
 *                imgHeight: 100,
 *           }
 *      });
 * </script>
 *
*/

$.fn.imCarousel = function(options)
{
    var defaults = 
    {
        url: null,
        visible: 5,
        delay: 1000,
        speed: 800,
        imgWidth: 90,
        imgHeight: 90,
        direction: 'horizontal'
    }
    
    var options = $.extend(defaults,options);
    
    var isVertical = options.direction == 'vertical';
    var bigNumber = 9999999;
    
    return this.each(function()
    {
        var curPosition = (options.visible * -1);
        var downloadComplete = false;
        var animateSpeed = -1;
    
        // Prepare DOM objects.
        var div = $(this);
        $(div).css({'position': 'relative'})
        $(div).html('<ul></ul>');
        var ul = $('ul', div); 
        // Apply default styling.
        ul.css({'position': 'absolute', overflow: 'hidden', margin: '0px', padding: '0px', 'list-style-type': 'none', 'height': isVertical ? bigNumber : options.imgHeight, 'width': isVertical ? options.imgWidth : bigNumber});
        var totalSize = options.imgWidth * options.visible;
        div.css({overflow: 'hidden', 'width': isVertical ? options.imgWidth : options.imgWidth * options.visible, 'height': isVertical ? options.imgHeight * options.visible : options.imgHeight});
        
        scrollCarousel(false);
        curPosition += options.visible;
        scrollCarousel(true);
        
        var resetPosition = -1000;
        
        // Downloads new images and scrolls the carousel one interation.
        function scrollCarousel(doScroll)
        {
            var startIndex = curPosition + options.visible;
            var endIndex = curPosition + (options.visible * 2);
            
            if (! downloadComplete)
            {
                // Load images from server.
                var paramSeparator = '?';
                if (options.url.indexOf('?') > -1)
                    paramSeparator = '&';
                var jsonUrl = options.url + paramSeparator + "from=" + startIndex + "&to=" + endIndex + "&jsoncallback=?";
                $.getJSON(jsonUrl, function(data)
                {
                    var images = data.images;
                    resetPosition = data.imageCount;
                    for (var i = 0; i < images.length; i++)
                    {
                        var src = images[i].src;
                        var url = images[i].url;
                        ul.append('<li style="width: ' + options.imgWidth + 'px;"><a href="' + url + '"><img src="' + src + '" border="0" /></a></li>');
                    }
                    var li = $("li", ul);
                    li.css({float: isVertical ? 'none' : 'left', 'overflow': 'hidden'});

                    var liSize = isVertical ? height(li) : width(li);             
                    setTimeout(function()
                    {
                        if (doScroll)
                        {
                            // Perform animation.
                            var animDistance = (images.length > 0) ? -(curPosition * liSize) : 0

                            var firstRunSpeed = options.speed; // Mod:Andrew
                            if (images.length < options.visible && resetPosition % options.visible == 0) firstRunSpeed = 0; // Mod:Andrew
                            
                            ul.animate(isVertical ? {top: animDistance} : {left: animDistance}, firstRunSpeed, function() // Mod:Andrew
                            {
                                if (images.length >= options.visible)
                                {
                                     scrollCarousel(true);
                                     curPosition += options.visible;
                                     //resetPosition = curPosition;
                                }
                                else
                                {
                                    curPosition = 0;
                                    downloadComplete = true;
                                    scrollCarousel(true);
                                }
                            });
                        } 
                        else
                        {
                            curPosition += options.visible;
                        }
                     }, options.delay);
                }, 'xml');
            }
            else
            {
                var li = $("li", ul);
                li.css({float: isVertical ? 'none' : 'left', 'overflow': 'hidden'});
                var liSize = isVertical ? height(li) : width(li);  
                //set timer only when the total images > options.visible                      
                if(resetPosition>options.visible) setTimeout(function()
                {
                    // Perform animation.
                    var animDistance = (resetPosition > curPosition) ?  -(curPosition * liSize) : 0;
                    if(animateSpeed == -1) animateSpeed = 0; // Mod:Andrew
                    else animateSpeed = options.speed; // Mod:Andrew
                    if(resetPosition <= curPosition) animateSpeed = 0; // Mod:Andrew
                    ul.animate(isVertical ? {top: animDistance} : {left: animDistance}, animateSpeed, function() // Mod:Andrew
                    {
                        if (resetPosition > curPosition)
                        {
                             scrollCarousel(true);
                             curPosition += options.visible;
                        }
                        else
                        {
                            curPosition = options.visible;
                            scrollCarousel(true);
                        }
                    });
                 }, options.delay);
                 
            }
        }
    });
        
    function css(el, prop)
    {
		var r = 0;
		if(el[0]) r= parseInt($.css(el[0], prop)) || 0;
        return r;
    };
    
    function width(el) 
    {
		var r = 0;
		if(el[0]) r=el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
        return r; 
    };
    
    function height(el) 
    {
		var r = 0;
		if(el[0]) r=el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
        return r;
    };    
    
    function debug(msg){
			$('#debug').text(msg);
    }
    
}