/*
 * jQuery Infinite Carousel
 * @author admin@catchmyfame.com - http://www.catchmyfame.com
 * @version 2.0.2
 * @date June 12, 2010
 * @category jQuery plugin
 * @copyright (c) 2009 admin@catchmyfame.com (www.catchmyfame.com)
 * @license CC Attribution-Share Alike 3.0 - http://creativecommons.org/licenses/by-sa/3.0/
 */

(function($) {
    $.fn.extend({
        infiniteCarousel: function(options)
        {
            var defaults =
            {
                transitionSpeed: 800,
                displayTime: 6000,
                textholderHeight: .25,
                displayProgressBar: true,
                displayThumbnails: true,
                displayThumbnailNumbers: true,
                displayThumbnailBackground: true,
                thumbnailWidth: '20px',
                thumbnailHeight: '20px',
                thumbnailFontSize: '.7em',
                easeLeft: 'linear',
                easeRight: 'linear',
                imagePath: 'images/',
                inView: 1, //the number of images "in view" to the user
                padding: '0px',
                advance: 1,
                showControls: true,
                autoHideControls: false,
                autoHideCaptions: true, //captions view is raised on hover and lowered when !hovering
                animateCaptionsOnMove: true, //animate captions (down/up) when the view transitions
                autoStart: true,
                prevNextInternal: true,
                enableKeyboardNav: true,
                enableArrowAnimation: true,  //the caption's textbox left and right arrows will flash on carousel transitions
                onSlideStart: function() {
                },
                onSlideEnd: function() {
                },
                onPauseClick: function() {
                }
            };
            var options = $.extend(defaults, options);

            return this.each(function() {
                var randID = Math.round(Math.random() * 100000000);
                var o = options;
                var obj = $(this);
                var autopilot = o.autoStart;

                var numImages = $('img', obj).length; // Number of images
                var imgHeight = $('img:first', obj).height();
                var imgWidth = $('img:first', obj).width();

                if (o.inView > numImages - 1) o.inView = numImages - 1; // check to make sure inview isnt greater than the number of images. inview should be at least two less than numimages (otherwise hinting wont work and animating left may catch a flash), but one less can work
                $('p', obj).hide(); // Hide any text paragraphs in the carousel
                $(obj).css({'position':'relative','overflow':'hidden'}).width((imgWidth * o.inView) + (o.inView * parseInt(o.padding) * 2)).height(imgHeight); //,'overflow':'hidden'
                $('ul', obj).css({'list-style':'none','margin':'0','padding':'0','position':'relative'}).width(imgWidth * numImages);
                $('li', obj).css({'display':'inline','float':'left'});

                // Move rightmost image over to the left
                $('li:last', obj).prependTo($('ul', obj));

                $('ul', obj).css('left', '-200px').width(9999);

                // Build progress bar
                if (o.displayProgressBar)
                {
                    $(obj).append('<div id="progress' + randID + '" class="ic-progress-bar" style="position:absolute;bottom:0;background:#bbb;left:0;z-index:1"></div>');
                    $('#progress' + randID).width('100%').height(5).css('opacity', '.6');
                }

                // Animate progress bar
                function startProgressBar(barTime)
                {
                    barTime = (barTime == null) ? o.displayTime : barTime;
                    $('#progress' + randID).width('100%').height(5);
                    $('#progress' + randID).animate({'width':0}, barTime);
                }

                //build overlay div that is 200 px wide, 100% of height of the carousel, and append to both sides.
                html = '<div id="overlayLeft" style="background-color:#333; height:325px;position:absolute;left:0px;;top:0px;" onclick="javascript:void(0);"></div>';
                html += '<div id="overlayRight" style="background-color:#333; height:325px;position:absolute;right:0px;top:0px;" onclick="javascript:void(0);"></div>';
                $(obj).append(html);

                $('#overlayLeft').width(o.padding);
                $('#overlayLeft').css('opacity', '.75');

                $('#overlayRight').width(o.padding);
                $('#overlayRight').css('opacity', '.75');

                // Left and right arrow div actions (custom)
                $('#overlayRight').click(function() {
                    $('#progress' + randID).stop().fadeOut();
                    forcePrevNext('next');
                    setTimeout(function() {
                        $('#play_btn' + randID).fadeIn(500);
                    }, o.transitionSpeed);
                    clearTimeout(clearInt);
                }).hover(function() {
                    $(this).animate({opacity:'.25'}, 500)
                }, function() {
                    $(this).animate({opacity:'.75'}, 500)
                });
                $('#overlayLeft').click(function() {
                    $('#progress' + randID).stop().fadeOut();
                    forcePrevNext('prev');
                    setTimeout(function() {
                        $('#play_btn' + randID).fadeIn(500);
                    }, o.transitionSpeed);
                    clearTimeout(clearInt);
                }).hover(function() {
                    $(this).animate({opacity:'.25'}, 500)
                }, function() {
                    $(this).animate({opacity:'.75'}, 500)
                });


                // Build textholder div(s) as wide as one image and as tall as the textholderHeight option
                var containerBorder = parseInt($(obj).css('border-bottom-width')) + parseInt($(obj).css('border-top-width'));
                if (isNaN(containerBorder)) containerBorder = 0; // IE returns NaN for $(obj).css('border-bottom-width')
                var containerPaddingLeft = parseInt($(obj).css('padding-left')); // Normally we'd do both left and right but only left matters here

                for (i = 1; i <= o.inView; i++)
                {
                    $(obj).append('<div id="textholder' + randID + '_' + i + '" class="textholder" style="position:absolute;overflow:hidden;width:' + imgWidth + 'px;bottom:0px;margin-bottom:' + -(imgHeight * o.textholderHeight + containerBorder) + 'px;"><span style="display:block;margin:7px 35px 0 35px;"></span></div>');
                    $('#textholder' + randID + '_' + i).css({'left':(i - 1) * (imgWidth + parseInt(o.padding) * 2),'margin-left':parseInt(o.padding) + containerPaddingLeft,'margin-right':o.padding});
                    $('#textholder' + randID + '_' + i).height(imgHeight * o.textholderHeight).css({'backgroundColor':'#333333','opacity':'0.5', 'color':'#FFFFFF', 'padding':'6px', 'font-size':'13px'});
                    html = '<div class="minmax" id="minmax' + randID + '_' + i + '" style="width:8px;height:8px;position:absolute;top:1px;right:10px;cursor:pointer;background:url(' + o.imagePath + 'caption.gif) no-repeat 0 -8px"></div>';
                    html += '<div class="close" id="close' + randID + '_' + i + '" style="width:8px;height:8px;position:absolute;top:1px;right:1px;cursor:pointer;background:url(' + o.imagePath + 'caption.gif) no-repeat 0 0"></div>';
                    $('#textholder' + randID + '_' + i).append(html);
                    if(!o.showControls) {
                       $('#minmax' + randID + '_' + i).hide();
                       $('#close' + randID + '_' + i).hide();
                    }

                    if (!o.autoHideCaptions) showtext($('li:eq(' + i + ') p', obj).html(), i);
                }
                var textholderPadding = parseInt($('#textholder' + randID + '_1').css('padding-left')) + parseInt($('#textholder' + randID + '_1').css('padding-right'));
                if (textholderPadding > 0) $('.textholder', obj).width(imgWidth - textholderPadding);

                $('.close', obj).each(function(i) { // Need to use each() because a loop doesn't work in this situation. see http://www.bennadel.com/blog/534-The-Beauty-Of-The-jQuery-Each-Method.htm
                    $(this).click(function() {
                        $('#textholder' + randID + '_' + (i + 1)).animate({marginBottom:(-imgHeight * o.textholderHeight) - containerBorder - 1 + 'px'}, 500)
                    });
                });
                $('.minmax', obj).each(function(i) { // Same reason as previous chunk
                    $(this).click(function() {
                        if (parseInt($('#textholder' + randID + '_' + (i + 1)).css('margin-bottom')) == 0)
                        {
                            $('#textholder' + randID + '_' + (i + 1)).animate({marginBottom:((-imgHeight * o.textholderHeight) - containerBorder + 12) + 'px'}, 500, function() {
                                $('#minmax' + randID + '_' + (i + 1)).css('background-position', '0 -16px')
                            });
                        }
                        else
                        {
                            $('#textholder' + randID + '_' + (i + 1)).animate({marginBottom:'0px'}, 500, function() {
                                $('#minmax' + randID + '_' + (i + 1)).css('background-position', '0 -8px')
                            });
                        }

                    });
                });

                function showtext(t, i)
                {
                    if (t != null)
                    {
                        $('#textholder' + randID + '_' + i + ' span').html(t); // Change textholder content
                        $('#textholder' + randID + '_' + i).stop().animate({marginBottom:'0px'}, 500); // Raise textholder
                        $('#minmax' + randID + '_' + i).css('background-position', '0 -8px');
                        showminmax();
                    }
                }

                function showminmax()
                {
                    if (o.showControls && !autopilot)
                    {
                        $('.minmax', obj).fadeIn(250);
                        $('.close', obj).fadeIn(250);
                    }
                }

                function hideCaption() {
                    $('.textholder', obj).stop().animate({marginBottom:(-imgHeight * o.textholderHeight - containerBorder - 1) + 'px'}, o.transitionSpeed)
                }

                if (o.displayThumbnails)
                {
                    function thumbclick(event)
                    {
                        target_num = this.id.split('_'); // we want target_num[1]
                        if (viewable[0] != target_num[1])
                        {
                            status = 'pause';
                            $('#progress' + randID).stop().fadeOut();
                            clearTimeout(clearInt);
                            $('#thumbs' + randID + ' div').css({'cursor':'default'}).unbind('click'); // Unbind the thumbnail click event until the transition has ended
                            autopilot = 0;
                            setTimeout(function() {
                                $('#play_pause_btn' + randID).css('background-position', '0 -16px')
                            }, o.transitionSpeed);
                            $('#play_pause_btn' + randID).unbind('click').bind('click', function() {
                                forceStart();
                            });
                        }
                        if (target_num[1] > viewable[0])
                        {
                            diff = target_num[1] - viewable[0];
                            moveLeft(diff);
                        }
                        if (target_num[1] < viewable[0])
                        {
                            diff = viewable[0] - target_num[1];
                            moveRight(diff);
                        }
                    }

                    var viewable = []; // track which images are being displayed
                    var unviewable = []; // track which images are being displayed
                    // Build thumbnail viewer and thumbnail divs
                    $(obj).after('<div id="thumbs' + randID + '" style="position:relative;overflow:auto;clear:left;text-align:left;padding-top:5px;"></div>');
                    for (i = 0; i <= numImages - 1; i++)
                    {
                        thumb = $('img:eq(' + (i + 1) + ')', obj).attr('src');
                        $('#thumbs' + randID).append('<div class="thumb" id="thumb' + randID + '_' + (i + 1) + '" style="cursor:pointer;background-image:url(' + thumb + ');display:inline;float:left;width:' + o.thumbnailWidth + ';height:' + o.thumbnailHeight + ';line-height:' + o.thumbnailHeight + ';padding:0;overflow:hidden;text-align:center;border:2px solid #ccc;margin-right:4px;font-size:' + o.thumbnailFontSize + ';font-family:Arial;color:#000;text-shadow:0 0 3px #fff">' + (i + 1) + '</div>');
                        if (i <= o.inView) $('#thumb' + randID + '_' + i).css({'border-color':'#ff0000'});
                        unviewable.push(i + 1);
                    }
                    // Initialize viewable/unviewable arrays
                    for (i = 1; i <= o.inView; i++) viewable.push(unviewable.shift());

                    // Next two lines are a special case to handle the first list element which was originally the last
                    thumb = $('img:first', obj).attr('src');
                    $('#thumb' + randID + '_' + numImages).css({'background-image':'url(' + thumb + ')'});
                    $('#thumbs' + randID + ' div.thumb:not(:first)').css({opacity:.65}); // makes all thumbs 65% opaque except the first one

                    $('#thumbs' + randID + ' div.thumb').hover(function() {
                        $(this).animate({'opacity':1}, 150)
                    }, function() {
                        if (viewable[0] != this.id.split('_')[1]) $(this).animate({'opacity':.65}, 250)
                    }); // add hover to thumbs
                    // Assign click handler for the thumbnails. Normally the format $('.thumb') would work but since it's outside of our object (obj) it would get called multiple times
                    $('#thumbs' + randID + ' div').bind('click', thumbclick); // We use bind instead of just plain click so that we can repeatedly remove and reattach the handler

                    if (!o.displayThumbnailNumbers) $('#thumbs' + randID + ' div').text('');
                    if (!o.displayThumbnailBackground) $('#thumbs' + randID + ' div').css({'background-image':'none'});
                }

                if (o.showControls)
                {
                    // Pause/play button(img)
                    html = '<div id="play_pause_btn' + randID + '" class="play_pause_btn" style="cursor:pointer;position:absolute;top:3px;right:3px;border:none;width:16px;height:16px;background:url(' + o.imagePath + 'playpause.gif) no-repeat 0 0"></div>';
                    $(obj).append(html);
                    var status = 'play';
                    $('#play_pause_btn' + randID).css('opacity', .5).hover(function() {
                        $(this).animate({opacity:'1'}, 250)
                    }, function() {
                        $(this).animate({opacity:'.5'}, 250)
                    });
                    $('#play_pause_btn' + randID).click(function() {
                        status = (status == 'play') ? 'pause' : 'play';
                        (status == 'play') ? forceStart() : forcePause();
                    });

                    if (!o.prevNextInternal)
                    {
                        wrapID = $(obj).attr('id') + 'Wrapper';
                        $(obj).wrap('<div id="' + wrapID + '"></div>').css('margin', '0 auto');
                        $('#' + wrapID).css('position', 'relative').width(($(obj).width() + 40 + parseInt($(obj).css('padding-left')) + parseInt($(obj).css('padding-right'))));
                    }

                    // Prev/next button(img)
                    arrowsTop = ((imgHeight / 2) - 15) + parseInt(o.padding);
                    html = '<div id="btn_rt' + randID + '" style="position:absolute;right:210px;bottom:20px;height:30px;width:13px;"><a href="javascript:void(0);"><img style="border:none;margin-right:2px" src="images/rt.png" /></a></div>';
                    html += '<div id="btn_lt' + randID + '" style="position:absolute;left:210px;bottom:20px;height:30px;width:13px;"><a href="javascript:void(0);"><img style="border:none;margin-left:2px" src="images/lt.png" /></a></div>';
                    (o.prevNextInternal) ? $(obj).append(html) : $('#' + wrapID).append(html);

                    $('#btn_rt' + randID).css('opacity', .5).click(function() {
                        forcePrevNext('next');
                    }).hover(function() {
                        $(this).animate({opacity:'1'}, 250)
                    }, function() {
                        $(this).animate({opacity:'.5'}, 250)
                    });
                    $('#btn_lt' + randID).css('opacity', .5).click(function() {
                        forcePrevNext('prev');
                    }).hover(function() {
                        $(this).animate({opacity:'1'}, 250)
                    }, function() {
                        $(this).animate({opacity:'.5'}, 250)
                    });

                    if (o.autoHideControls && o.prevNextInternal)
                    {
                        function showcontrols()
                        {
                            $('#play_pause_btn' + randID).stop().animate({top:'3px',right:'3px'}, 250);
                            $('#btn_rt' + randID).stop().animate({top:arrowsTop + 'px',right:'2px'}, 250);
                            $('#btn_lt' + randID).stop().animate({top:arrowsTop + 'px',left:'2px'}, 250);
                        }

                        function hidecontrols()
                        {
                            $('#play_pause_btn' + randID).stop().animate({top:-16 - containerBorder + 'px',right:-16 - containerBorder + 'px'}, 250);
                            $('#btn_rt' + randID).stop().animate({right:'-16px'}, 250);
                            $('#btn_lt' + randID).stop().animate({left:'-16px'}, 250);
                        }

                        $(obj).hover(showcontrols, hidecontrols);
                        hidecontrols();
                    }
                    if (o.autoHideCaptions)
                    {
                        var isHover;

                        function autoShowCap() {
                            isHover = true;
                            for (i = 1; i <= o.inView; i++) showtext($('li:eq(' + i + ') p', obj).html(), i);
                        }

                        function autoHideCap() {
                            isHover = false;
                            hideCaption();
                        }

                        $(obj).hover(autoShowCap, autoHideCap);
                        hideCaption();
                    }
                }


                function keyBind() {
                    if (o.enableKeyboardNav)
                    {
                        $(document).keydown(function(event) {
                            if (event.keyCode == 39)
                            {
                                forcePrevNext('next');
                                $(document).unbind('keydown');
                            }
                            if (event.keyCode == 37)
                            {
                                forcePrevNext('prev');
                                $(document).unbind('keydown');
                            }
                            if (event.keyCode == 80 || event.keyCode == 111) forcePause();
                            if (event.keyCode == 83 || event.keyCode == 115)
                            {
                                forceStart();
                                $(document).unbind('keydown');
                            }
                        });
                    }
                }

                function forcePrevNext(dir)
                {
                    o.onPauseClick.call(this);
                    $('#btn_rt' + randID).unbind('click');
                    $('#btn_lt' + randID).unbind('click');
                    setTimeout(function() {
                        $('#play_pause_btn' + randID).css('background-position', '0 -16px')
                    }, o.transitionSpeed - 1);
                    autopilot = 0;
                    $('#progress' + randID).stop().fadeOut();
                    status = 'pause';
                    clearTimeout(clearInt);
                    (dir == 'prev') ? moveRight() : moveLeft();
                    $('#play_pause_btn' + randID).unbind('click');
                    setTimeout(function() {
                        $('#play_pause_btn' + randID).bind('click', function() {
                            forceStart();
                        });
                        $('#btn_rt' + randID).bind('click', function() {
                            forcePrevNext('next')
                        });
                        $('#btn_lt' + randID).bind('click', function() {
                            forcePrevNext('prev')
                        });
                    }, o.transitionSpeed);
                }

                function forcePause()
                {
                    $('#play_pause_btn' + randID).unbind('click'); // unbind the click, wait for transition, then reenable
                    if (autopilot)
                    {
                        o.onPauseClick.call(this);
                        $('#play_pause_btn' + randID).fadeTo(250, 0, function() {
                            $(this).css({'background-position':'0 -16px','opacity':'.5'});
                        }).animate({opacity:.5}, 250);
                        autopilot = 0;
                        showminmax();
                        $('#progress' + randID).stop().fadeOut();
                        clearTimeout(clearInt);
                        setTimeout(function() {
                            $('#play_pause_btn' + randID).bind('click', function() {
                                forceStart();
                            })
                        }, o.transitionSpeed);
                    }
                }

                function forceStart()
                {
                    $('#play_pause_btn' + randID).unbind('click'); // unbind the click, wait for transition, then reenable
                    if (!autopilot)
                    {
                        setTimeout(function() {
                            $('#play_pause_btn' + randID).css('background-position', '0 0')
                        }, o.transitionSpeed - 1);
                        autopilot = 1;
                        moveLeft();
                        clearInt = setInterval(function() {
                            moveLeft();
                        }, o.displayTime + o.transitionSpeed);
                        setTimeout(function() {
                            $('#play_pause_btn' + randID).bind('click', function() {
                                forcePause();
                            })
                        }, o.transitionSpeed);
                    }
                }

                function preMove()
                {
                    if (o.animateCaptionsOnMove) hideCaption();
                    // Fade out play/pause/left/right
                    if (o.showControls && o.prevNextInternal)
                    {
                        if (o.enableArrowAnimation) {
                            $('#btn_lt' + randID).fadeOut(200);
                            $('#btn_rt' + randID).fadeOut(200);
                        }

                        $('#play_pause_btn' + randID).fadeOut(200);
                        $('.minmax', obj).fadeOut(200);
                        $('.close', obj).fadeOut(200);

                    }
                    if (o.displayThumbnails) for (i = 1; i <= numImages; i++) $('#thumb' + randID + '_' + i).css({'border-color':'#ccc'}).animate({'opacity': .65}, 500);
                }

                function postMove()
                {
                    if (o.showControls && o.prevNextInternal)
                    {
                        if (o.enableArrowAnimation) {
                            $('#btn_lt' + randID).fadeIn(200);
                            $('#btn_rt' + randID).fadeIn(200);
                        }

                        $('#play_pause_btn' + randID).fadeIn(200);
                        $('.minmax', obj).fadeIn(200);
                        $('.close', obj).fadeIn(200);
                    }
                    keyBind();
                    if (o.autoHideCaptions && isHover) autoShowCap();
                    if (o.displayThumbnails) for (i = 0; i < viewable.length; i++) $('#thumb' + randID + '_' + viewable[i]).css({'border-color':'#ff0000'}).animate({'opacity': 1}, 500);
                    if (!o.autoHideCaptions) for (i = 1; i <= o.inView; i++) showtext($('li:eq(' + i + ') p', obj).html(), i);
                    if (o.displayThumbnails) $('#thumbs' + randID + ' div').unbind('click').bind('click', thumbclick).css({'cursor':'pointer'});
                    ary = [];
                    for (x = 1; x <= o.inView; x++) {
                        ary.push($('img:eq(' + x + ')', obj).attr('src'))
                    }
                    o.onSlideEnd.call(this, ary);
                }

                function moveLeft(dist)
                {
                    if (dist == null) dist = o.advance;
                    preMove();
                    if (o.displayThumbnails)
                    {
                        for (i = 1; i <= dist; i++) {
                            viewable.push(unviewable.shift());
                            unviewable.push(viewable.shift());
                        }
                    }
                    if (o.displayTime == 0) {
                        clearInterval(clearInt);
                    } // If running a contonuous show with no display time, fist clear the interval. Then below, recursively call moveLeft

                    $('li:lt(' + dist + ')', obj).clone(true).insertAfter($('li:last', obj)); // Copy the first image (offscreen to the left) to the end of the list (offscreen to the right)
                    $('li:lt(' + dist + ')', obj).remove();

                    o.onSlideStart.call(this, viewable, 'left');
                    //This sucks BUT we need to move the ul to zero (back to the right from a negative value) because we remove the item from the front of the
                    //list and append it to the back which puts the element in the correct spot. So no animation actually happens unless we move the list
                    //to the right first and animate left.
                    $('ul', obj).css({'left':'0'});
                    $('ul', obj).animate({'left':-(imgWidth - (parseInt(o.padding)))}, o.transitionSpeed, o.easeLeft, function() { // Animate the entire list to the left
                         // When the animation finishes, remove the first image (on the left). It has already been copied to the end of the list (right)

                        $(this).css({'left':-(imgWidth - (parseInt(o.padding)))});
                        if (o.displayProgressBar && autopilot) startProgressBar();
                        postMove();
                        if (o.displayTime == 0) {
                            moveLeft();
                        }
                    });
                }

                function moveRight(dist)
                {
                    if (dist == null) dist = o.advance;
                    preMove();
                    if (o.displayThumbnails)
                    {
                        for (i = 1; i <= dist; i++) {
                            viewable.unshift(unviewable.pop());
                            unviewable.unshift(viewable.pop());
                        }
                    }

                    $('li:gt(' + (numImages - (dist + 1)) + ')', obj).clone(true).insertBefore($('li:first', obj)); // Copy rightmost (last) li and insert it after the first li
                    $('li:gt(' + (numImages - dist) + ')', obj).remove();
                    o.onSlideStart.call(this, viewable, 'right');
                    $('ul', obj).css('left', -(imgWidth * (dist + 1) - (parseInt(o.padding))))
                            .animate({left:-(imgWidth - (parseInt(o.padding)))}, o.transitionSpeed, o.easeRight, function() {
                        postMove();
                    });
                }

                // Kickoff the show
                if (autopilot)
                {
                    var clearInt = setInterval(function() {
                        moveLeft();
                    }, o.displayTime + o.transitionSpeed);
                    if (o.displayProgressBar) startProgressBar(o.displayTime + o.transitionSpeed);
                } else {
                    status = 'pause';
                    $('#play_pause_btn' + randID).css({'background-position':'0 -16px'});
                }
                keyBind();
            });
        }
    });
})(jQuery);
