﻿/*
 * Carousel.js
 * Liam Smith
 * InfoMine Inc.
 * August 6, 2009
 * Modified by Ping Chan 3/31/2010
*/

/* 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">
 *      jQuery(document).ready(function()
 *      {
 *           jQuery('#divMyCarousel').Carousel(
 *           {
 *                url: 'http://www.infomine.com/myimageservice.ashx',
 *                visible: 5,
 *                delay: 2000,
 *                speed: 800,
 *                imgWidth: 100,
 *                imgHeight: 100,
 *           }
 *      });
 * </script>
 *
*/

jQuery.fn.Carousel=function (options) {
    var defaults={
        url: null,
        visible: 5,
        delay: 1000,
        speed: 800,
        imgWidth: 90,
        imgHeight: 90,
        linkTarget: '_parent',
        direction: 'horizontal',
        resizable: false
    }

    var options=jQuery.extend(defaults,options);

    var param={
        //div: null,
        liList: new Array(),
        downloadIndex: 0,
        curIndex: 0,
        imageCount: 0,
        liSize: 0,
        paramSeparator: (options.url.indexOf('?')> -1)?'&':'?',
        isVertical: (options.direction=='vertical'),
        impression: 0,
        animDistance: 0,
        size: options.visible,
        skip: false,
        buildUrl: function (fromIndex,len) {
            return options.url+this.paramSeparator+"from="+fromIndex+"&len="+len+"&imid="+this.impression+"&jsoncallback=?";
        },
        onSizeChange: function (div) {
            //var div=this.div;
            jQuery(div).hide();
            var p=jQuery(div).parent();
            var s=this.isVertical?Math.floor(p.height()/options.imgHeight):Math.floor(p.width()/options.imgWidth);
            jQuery(div).show();
            if(s>=options.visible&&s!=this.size) {
                this.size=Math.max(s,options.visible);
                jQuery(div).css(this.isVertical?{ 'height': options.imgHeight*this.size}:{ 'width': options.imgWidth*this.size });
                this.skip=true;
                if(this.liSize>0) this.animDistance= -(this.size*this.liSize);
            }
        }
    }

    return this.each(function () {
        // initialize carouse params
        initCarousel(jQuery(this));
    });

    function initCarousel(div) {
        var isV=param.isVertical;
        //param.div=div;
        // initialize params
        jQuery(div).css({ 'position': 'relative' })
        jQuery(div).html('<ul></ul>');
        var ul=jQuery('ul',div);
        if(options.resizable) {
            jQuery(window).resize(function () { param.onSizeChange(div); });
            param.onSizeChange(div);
        }
        // Apply default styling.
        ul.css({ 'position': 'absolute',margin: '0px',padding: '0px','list-style-type': 'none','height': isV?99999:options.imgHeight,'width': isV?options.imgWidth:99999 });
        //var totalSize=options.imgWidth*param.size;
        div.css({ overflow: 'hidden','width': isV?options.imgWidth:options.imgWidth*param.size,'height': isV?options.imgHeight*param.size:options.imgHeight });
        if(!window.parent&&options.linkTarget=='_parent') options.linkTarget='_self';

        // get the first param.size * 2 images
        var endIndex=param.size*2;
        loadImages(0,endIndex,function (data) {
            param.imageCount=data.imageCount;
            param.impression=data.impression;
            param.curIndex=endIndex;
            //duplicate all images if imagecount between param.size and param.size*2
            if(param.imageCount>param.size&&param.imageCount<param.size*2) {
                for(var i=0;i<param.imageCount;i++) { param.liList.push(jQuery(param.liList[i]).clone()); };
                param.imageCount=param.imageCount*2;
            }
            //set initial images into ul
            endIndex=Math.min(endIndex,param.imageCount);
            for(var i=0;i<endIndex;i++) { ul.append(param.liList[i]); };
            var li=jQuery('li:eq(0)',ul);
            param.liSize=isV?jQuery(li).outerHeight(true):jQuery(li).outerWidth(true);
            param.animDistance= -(param.size*param.liSize);
            // start the carousel cycle if image.count>param.size
            if(param.imageCount>param.size) setTimeout(function () { rollCarousel(div); },options.delay);
        });
    }

    function rollCarousel(div) {
        if(param.liList.length<param.imageCount) {
            var len=(param.liList.length-param.downloadIndex)>=param.size?param.size:param.size*2+param.downloadIndex-param.liList.length;
            loadImages(param.downloadIndex,len,function (data) { rollTheCarousel(div); });
        } else {
            rollTheCarousel(div);
        }
    }

    function rollTheCarousel(div) {
        var ul=jQuery('ul',div);
        if(!param.skip&&jQuery('li',ul).length>=param.size*2) {//make sure img are load before slide
            ul.animate((param.isVertical?{ top: param.animDistance}:{ left: param.animDistance }),options.speed,function () {
                jQuery('li:lt('+(param.size)+')',ul).remove();
                if(param.isVertical) { ul.css({ 'top': 0 }); } else { ul.css('left',0); }
                getNext(div);
            });
        } else {
            getNext(div);
            param.skip=false;
        }
    }

    function getNext(div) {
        var ul=jQuery('ul',div);
        var j=param.curIndex+param.size;
        var endIndex=Math.min(j,param.imageCount,param.liList.length);
        if(jQuery('li',ul).length<param.size*2) {
            for(var i=param.curIndex;i<endIndex;i++) { ul.append(jQuery(param.liList[i]).clone()); };
            if(j>=param.imageCount) {
                //reaching the end of list, start over from the beggining	
                endIndex=j-param.imageCount;
                if(endIndex>0) for(var i=0;i<endIndex;i++) { ul.append(jQuery(param.liList[i]).clone()); };
            }
            param.curIndex=endIndex;
        }
        setTimeout(function () { rollCarousel(div); },options.delay);
    }

    function loadImages(fromIndex,len,callback) {
        var jsonUrl=param.buildUrl(fromIndex,len);
        if(jsonUrl&&callback) jQuery.getJSON(jsonUrl,function (data) {
            var images=data.images;
            param.downloadIndex=data.to+1;
            for(var i=0;i<images.length;i++) {
                if(!images[i].src) images[i].src='http://www.infomine.com/global/assets/images/1x1trans.gif'
                var li=jQuery('<li><a target="'+options.linkTarget+'" href="'+images[i].url+'"><img src="'+images[i].src+'" border="0" /></a></li>');
                li.css(param.isVertical?{'height': options.imgHeight+'px'}:{'width':options.imgWidth+'px'});
                li.css({'float':(param.isVertical?'none':'left'),'overflow':'hidden'});
                param.liList.push(li);
            }
            callback(data);
        });
    }

    function debug(msg) {
        jQuery('#debug').text(msg);
    }

}
