/* =========================================================
// jquery.innerFade.js

// Date: 2009-07-21
// Author: Wes Baker
// Mail: wes@wesbaker.com	
// Web: http://www.wesbaker.com
// *********************************************************
// Modifications for ZoomGallery, by Tim Doherty:
// 1) Zoom, Pan functions
// 2) Bind event handlers for zoom, pan buttons
// 3) Thumbnail scroll functions
// 4) Bind event handlers for thumbnail scroll
// ========================================================= */

(function($) {
    var container, elements, settings;
    var currentTimeout = null;
    var count = 0;

    //zoomGallery timer
    var zoomTimeout = null;

    $.fn.innerFade = function(options) {
        return this.each(function() {
            $.innerFade(this, options);
        });
    };

    $.innerFade = function(container, options) {
        // Define default settings
        var defaultSettings = {
            'animationType': 'fade',
            'easing': 'linear',
            'speed': 'normal',
            'type': 'sequence',
            'timeout': 2000,
            'loop': true,
            'containerHeight': 'auto',
            'runningClass': 'innerFade',
            'children': null,
            'cancelLink': null,
            'pauseLink': '.pause',
            'prevLink': '.prev',
            'nextLink': '.next',
            'indexContainer': null,
            'currentItemContainer': null,
            'totalItemsContainer': null,
            'panContainer': null,
            'zoomIn': null,
            'zoomOut': null,
            'panLeft': null,
            'panUp': null,
            'panDown': null,
            'panRight': null,
            'playClass': null,
            'pauseClass': null,
            'indexScroller': null,
            'indexScrollLeft': null,
            'indexScrollRight': null
        };


        // Combine default and set settings or use default
        if (options) { settings = $.extend(defaultSettings, options); }

        // If children option is set use that as elements, otherwise use the called jQuery object
        elements = (settings.children === null) ? $(container).children() : $(container).children(settings.children);

        container = container;

        // Start the loop
        if (elements.length > 1) {
            // Establish the Next and Previous Handlers
            $.bindControls();

            // Establish Cancel Handler
            if (settings.cancelLink) { $.bindCancel(); };

            // Set outer container as relative, and use the height that's set and add the running class
            $(container).css({ 'position': 'relative', 'height': settings.containerHeight }).addClass(settings.runningClass);

            // Build the Index if one is specified
            if (settings.indexContainer) {
                $.innerFadeIndex();
            };

            $(elements).filter(':gt(0)').hide(0);
            // Set the z-index from highest to lowest (20, 19, 18...) and set their position as absolute
            for (var i = 0; i < elements.length; i++) {
//                $(elements[i]).css('z-index', String(elements.length - i)).css('position', 'absolute');
                $(elements[i]).css('z-index', String(elements.length - i)).css({ 'left': '0px', 'position': 'absolute', 'top': '0px' }); //11/19/2009 - Tim Doherty - IE requires explicit top, left CSS position attributes
            }

            var toShow = '';
            var toHide = '';

            if (settings.type == "random") {
                toHide = Math.floor(Math.random() * elements.length);
                do {
                    toShow = Math.floor(Math.random() * elements.length);
                } while (toHide == toShow);

                $.fadeTimeout(toShow, toHide, true);
                $(elements[toHide]).show();
            } else if (settings.type == 'random_start') {
                settings.type = 'sequence';
                toShow = Math.floor(Math.random() * (elements.length));

                $.fadeTimeout((toShow + 1) % elements.length, toShow, true);
                $(elements[toShow]).show();
            } else {
                // Otherwise and if its sequence
                toShow = 0;
                toHide = elements.length - 1;

                $.fadeTimeout(toShow, toHide, true);
                $(elements[0]).show();
            }

            // Set item count containers
            if (settings.currentItemContainer) { $.currentItem(toShow); };
            if (settings.totalItemsContainer) { $.totalItems(); };

            // Establish the Pause Handler
            $.bindPause();

            //Establish zoom hanlder
            $.bindZoom();

            //Establish the pan handler
            $.bindPan();

            //Eztablish index scrollers
            $.bindScrollers();
        }
    };


    /**
    * Fades the slideshow to the item selected from the previous item
    * @param {Number} toShow The position in the elements array of the item to be shown
    * @param {Number} toHide The position in the elements array of the item to be hidden
    */
    $.fadeToItem = function(toShow, toHide) {

        //Reset any zoom and pan
        $.resetZoom();
        $.resetPan();

        // Update the next and previous controls
        var buildControls = function() {
            if (settings.nextLink || settings.prevLink) { $.bindControls(); }
        };

        if (settings.animationType == 'slide') {
            $(elements[toHide]).slideUp(settings.speed);
            //$(elements[toShow]).slideDown(settings.speed, function() { buildPreviousNext(); }); //Tim Doherty - "buildPreviousNext(") does not exists, fails after first transition
            $(elements[toShow]).slideDown(settings.speed, function() { buildControls(); });
        } else if (settings.animationType == 'slideOver') {
            var itemWidth = $(elements[0]).width();
            $(container).css({ 'overflow': 'hidden' });
            $(elements[toHide]).css({ 'left': '0px', 'position': 'absolute', 'right': 'auto', 'top': '0px' });
            $(elements[toShow]).css({ 'left': 'auto', 'position': 'absolute', 'right': '-' + itemWidth + 'px', 'top': '0px' }).show();

            $(elements[toHide]).animate({ 'left': '-' + itemWidth + 'px' }, settings.speed, settings.easing, function() {
                $(this).hide();
            });
            $(elements[toShow]).animate({ 'right': '0px' }, settings.speed, settings.easing, function() {
                buildControls();
            });
        } else {
            $(elements[toHide]).fadeOut(settings.speed);
            $(elements[toShow]).fadeIn(settings.speed, function() {
                buildControls();
            });
        }
        // Update the toShow item
        if (settings.currentItemContainer) {
            $.currentItem(toShow);
        };

        // Update indexes with active classes
        if (settings.indexContainer) {
            $.updateIndexes(toShow);
        };
    };

    /**
    * Fades to the item of your choosing and establishes the timeout for the next item to fade to
    * @param {Number} toShow The position in the elements array of the item to be shown
    * @param {Number} toHide The position in the elements array of the item to be hidden
    * @param {Boolean} firstRun If this is the first run of innerfade, pass true, otherwise pass false
    */
    $.fadeTimeout = function(toShow, toHide, firstRun) {
        // If its not the first run, then fade
        if (firstRun != true) {
            $.fadeToItem(toShow, toHide);
        };

        // Increment the count of slides shown
        count++;

        // Check if loop is false, if it is check to see how many slides have been shown.
        // In the case that you're at the last slide, stop the slideshow and return.
        if (settings.loop == false && count >= elements.length) {
            $.stopSlideshow();
            return;
        };

        // Get ready for next fade
        if (settings.type == "random") {
            toHide = toShow;
            while (toShow == toHide) { toShow = Math.floor(Math.random() * elements.length); }
        } else {
            toHide = (toHide > toShow) ? 0 : toShow;
            toShow = (toShow + 1 >= elements.length) ? 0 : toShow + 1;
        }

        // Set the time out
        currentTimeout = setTimeout((function() { $.fadeTimeout(toShow, toHide, false); }), settings.timeout);
    };

    /* Allows the unbind function to be called from javascript */
    $.fn.innerFadeUnbind = function() {
        return this.each(function(index) {
            $.stopSlideshow();
        });
    };

    /**
    * Stops the slideshow
    * @param {jQuery Object} container The container that first calls the innerfade plugin
    */
    $.stopSlideshow = function() {
        //Toggle the play/pause button
        $(settings.pauseLink).removeClass(settings.pauseClass);
        $(settings.pauseLink).addClass(settings.playClass);
        clearTimeout(currentTimeout);
        currentTimeout = null;
    };

    /**
    * Establishes the Next and Previous link behavior
    * @param {jQuery Object} container The container that first calls the innerfade plugin
    * @param {Array} elements The elements within the container
    * @param {Object} settings The settings object which contains speed, style, selectors of the items and so on
    */
    $.bindControls = function() {
        $(settings.nextLink).unbind().one('click', function(event) {
            event.preventDefault();
            $.stopSlideshow();

            var $currentElement = $(elements).filter(':visible');
            var currentElementIndex = $(elements).index($currentElement);

            var $nextElement = ($currentElement.next().length > 0) ? $currentElement.next() : $(elements).filter(':first');
            var nextElementIndex = $(elements).index($nextElement);

            $.fadeToItem(nextElementIndex, currentElementIndex);
        });

        $(settings.prevLink).unbind().one('click', function(event) {
            event.preventDefault();
            $.stopSlideshow();

            var $currentElement = $(elements).filter(':visible');
            var currentElementIndex = $(elements).index($currentElement);

            var $previousElement = ($currentElement.prev().length > 0) ? $currentElement.prev() : $(elements).filter(':last');
            var previousElementIndex = $(elements).index($previousElement);

            $.fadeToItem(previousElementIndex, currentElementIndex);
        });
    };

    /**
    * Establishes the Pause Button
    * @param {jQuery Object} container The container that first calls the innerfade plugin
    * @param {Array} elements The array of elements within the container
    * @param {Object} settings The settings object which contains speed, style, selectors of the items and so on
    */
    $.bindPause = function() {
        $(settings.pauseLink).unbind().click(function(event) {
            event.preventDefault();
            if (currentTimeout != null) {
                $.stopSlideshow();
            } else {
                //Toggle the play/pause button
                $(settings.pauseLink).removeClass(settings.playClass);
                $(settings.pauseLink).addClass(settings.pauseClass);

                var tag = $(container).children(':first').attr('tagName').toLowerCase();
                var nextItem = '';
                var previousItem = '';

                if (settings.type == "random") {
                    previousItem = Math.floor(Math.random() * elements.length);
                    do {
                        nextItem = Math.floor(Math.random() * elements.length);
                    } while (previousItem == nextItem);
                } else if (settings.type == "random_start") {
                    previousItem = Math.floor(Math.random() * elements.length);
                    nextItem = (previousItem + 1) % elements.length;
                } else {
                    previousItem = $(tag, $(container)).index($(tag + ':visible', $(container)));
                    nextItem = ((previousItem + 1) == elements.length) ? 0 : previousItem + 1;
                }

                $.fadeTimeout(nextItem, previousItem, false);
            }
        });
    };

    /**
    * Establishes the Cancel Button
    */
    $.bindCancel = function() {
        $(settings.cancelLink).unbind().click(function(event) {
            event.preventDefault();
            $.stopSlideshow();
        });
    };

    /**
    * Updates the indexes and adds an active class to the visible item
    * @param {Number} toShow The position in the elements array of the item to be shown
    */
    $.updateIndexes = function(toShow) {
        $(settings.indexContainer).children().removeClass('active');
        $('> :eq(' + toShow + ')', $(settings.indexContainer)).addClass('active');
    };

    /**
    * Creates handlers for the links created by the $.handleIndexes and $.generateIndexes functions
    * @param {Number} count The item to be setting the link on
    * @param {jQuery Object} link The selector or jQuery object of the link
    */
    $.createIndexHandler = function(count, link) {
        $(link).click(function(event) {
            event.preventDefault();
            var $currentVisibleItem = $(elements).filter(':visible');
            var currentItemIndex = $(elements).index($currentVisibleItem);
            $.stopSlideshow();
            if ($currentVisibleItem.size() <= 1) {
                $.fadeToItem(count, currentItemIndex);
            };
        });
    };

    /**
    * Creates one link for each item in the slideshow, to show that item immediately
    */
    $.createIndexes = function() {
        var $indexContainer = $(settings.indexContainer);

        for (var i = 0; i < elements.length; i++) {
            var $link = $('<li><a href="#">' + (i + 1) + '</a></li>');
            $.createIndexHandler(i, link);
            return $link;
        };
    };

    /**
    * Establishes links between the slide elements and index items in the indexContainer
    */
    $.linkIndexes = function() {
        var $indexContainer = $(settings.indexContainer);
        var $indexContainerChildren = $('> :visible', $indexContainer);

        //        var $indexContainerChildren = $indexContainer.children();
        //        
        if ($indexContainerChildren.size() == elements.length) {
            var count = elements.length;
            for (var i = 0; i < count; i++) {
                $('a', $indexContainer).click(function(event) { event.preventDefault(); });
                $.createIndexHandler(i, $indexContainerChildren[i]);
            };
        } else {
            alert("There is a different number of items in the menu and slides. There needs to be the same number in both.\nThere are " + $indexContainerChildren.size() + " in the indexContainer.\nThere are " + elements.length + " in the slides container.");
        };
    };

    /**
    * Determines if the index container is empty or not. If its empty then it generates links, if its not empty it links one to one
    */
    $.innerFadeIndex = function() {
        var $indexContainer = $(settings.indexContainer);
        if ($indexContainer.html().length <= 0) {
            $.createIndexes();
        } else {
            $.linkIndexes();
        };
    };

    /**
    * Changes the text of the current item selector to the index of the current item
    */
    $.currentItem = function(current) {
        var $container = $(settings.currentItemContainer);
        $container.text(current + 1);
    };

    /**
    * Changes the text of the total item selector to the total number of items
    */
    $.totalItems = function() {
        var $container = $(settings.totalItemsContainer);
        $container.text(elements.length);
    };


    /***********************************************************/
    /* New functionality by Tim Doherty                        */
    /***********************************************************/


    /**
    * Establishes the Zoom in Button
    */
    $.bindZoom = function() {
        $(settings.zoomIn).unbind().mouseup(function(event) {
            event.preventDefault();
            clearTimeout(zoomTimeout);
            zoomTimeout = null;
        }).mousedown(function(event) {
            event.preventDefault();
            if (currentTimeout != null) {
                $.stopSlideshow();
            }
            $.zoomIt('in');
        });


        $(settings.zoomOut).unbind().mouseup(function(event) {
            event.preventDefault();
            clearTimeout(zoomTimeout);
            zoomTimeout = null;
        }).mousedown(function(event) {
            event.preventDefault();
            if (currentTimeout != null) {
                $.stopSlideshow();
            }
            $.zoomIt('out');
        });
    };

    //zoom in/out the currently selected image
    $.zoomIt = function(direction) {

        //$.resetPan();

        var widthStep = 16;

        //Get the currently selected element
        var $currentElement = $(elements).filter(':visible');

        //Get the image tag
        var $img = $('img', $currentElement);

        //use original aspect ratio to calcuate new height
        var $aspectRatio = 480 / 640;

        if ((direction == 'in') && $img.width() < 1280) {
            $img.width($img.width() + widthStep);
            //scroll to keep the image centered
            $(settings.panContainer).scrollLeft($(settings.panContainer).scrollLeft() + (widthStep / 2));

            $img.height($img.height() + Math.round(widthStep * $aspectRatio));
            //scroll to keep the image centered
            $(settings.panContainer).scrollTop($(settings.panContainer).scrollTop() + (Math.round(widthStep * $aspectRatio) / 2));

        } else if ($img.width() > 640) {
            $img.width($img.width() - widthStep);
            //scroll to keep the image centered
            $(settings.panContainer).scrollLeft($(settings.panContainer).scrollLeft() - (widthStep / 2));

            $img.height($img.height() - Math.round(widthStep * $aspectRatio));
            //scroll to keep the image centered
            $(settings.panContainer).scrollTop($(settings.panContainer).scrollTop() - (Math.round(widthStep * $aspectRatio) / 2));
        }
        zoomTimeout = setTimeout((function() { $.zoomIt(direction); }), 5);

    };

    /**
    * Establishes the Pan Buttons
    */
    $.bindPan = function() {
        $(settings.panLeft).unbind().mouseup(function(event) {
            event.preventDefault();
            clearTimeout(zoomTimeout);
            zoomTimeout = null;
            //alert('mouseup');

        }).mousedown(function(event) {
            event.preventDefault();
            if (currentTimeout != null) {
                $.stopSlideshow();
            }
            $.panIt('right');
            //alert('mousedown');
        });


        $(settings.panRight).unbind().mouseup(function(event) {
            event.preventDefault();
            clearTimeout(zoomTimeout);
            zoomTimeout = null;
            //alert('mouseup');

        }).mousedown(function(event) {
            event.preventDefault();
            if (currentTimeout != null) {
                $.stopSlideshow();
            }
            $.panIt('left');
            //alert('mousedown');
        });

        $(settings.panUp).unbind().mouseup(function(event) {
            event.preventDefault();
            clearTimeout(zoomTimeout);
            zoomTimeout = null;
            //alert('mouseup');

        }).mousedown(function(event) {
            event.preventDefault();
            if (currentTimeout != null) {
                $.stopSlideshow();
            }
            $.panIt('up');
            //alert('mousedown');
        });

        $(settings.panDown).unbind().mouseup(function(event) {
            event.preventDefault();
            clearTimeout(zoomTimeout);
            zoomTimeout = null;
            //alert('mouseup');

        }).mousedown(function(event) {
            event.preventDefault();
            if (currentTimeout != null) {
                $.stopSlideshow();
            }
            $.panIt('down');
            //alert('mousedown');
        });
    };

    //Pan/scroll functions
    $.panIt = function(direction) {

        var $step = 5;

        switch (direction) {
            case 'left':
                $(settings.panContainer).scrollLeft($(settings.panContainer).scrollLeft() + $step);
                break;

            case 'right':
                $(settings.panContainer).scrollLeft($(settings.panContainer).scrollLeft() - $step);
                break;

            case 'up':
                $(settings.panContainer).scrollTop($(settings.panContainer).scrollTop() - $step);
                break;

            case 'down':
                $(settings.panContainer).scrollTop($(settings.panContainer).scrollTop() + $step);
                break;
        }
        zoomTimeout = setTimeout((function() { $.panIt(direction); }), 10);
    };

    //Bind the scroll left/right thumbnail nav buttons
    $.bindScrollers = function() {
        $(settings.indexScrollLeft).unbind().mouseup(function(event) {
            event.preventDefault();
            clearTimeout(zoomTimeout);
            zoomTimeout = null;
        }).mousedown(function(event) {
            event.preventDefault();

            $.scrollIt('right');
        });


        $(settings.indexScrollRight).unbind().mouseup(function(event) {
            event.preventDefault();
            clearTimeout(zoomTimeout);
            zoomTimeout = null;
        }).mousedown(function(event) {
            event.preventDefault();
            $.scrollIt('left');
        });
    };

    //Scroll the thumbnail nav bar
    $.scrollIt = function(direction) {
        var step = 10;

        switch (direction) {
            case 'left':
                $(settings.indexScroller).scrollLeft($(settings.indexScroller).scrollLeft() + 10);
                break;
            case 'right':
                $(settings.indexScroller).scrollLeft($(settings.indexScroller).scrollLeft() - 10);
                break;
        }
        zoomTimeout = setTimeout((function() { $.scrollIt(direction); }), 10);
    };

    $.resetPan = function() {
        $(settings.panContainer).scrollLeft(0);
        $(settings.panContainer).scrollTop(0);
    };

    $.resetZoom = function() {
        //Get the currently selected element
        var $currentElement = $(elements).filter(':visible');

        //Get the image tag
        var $img = $('img', $currentElement);

        $img.width(640);
        $img.height(480);
    };


})(jQuery);