/**
 * 2010 Peter Lisak www.itstudio.cz
 * Extended for vertical scroll, hiding nav. arrows, and lightbox.
 *
 *
 */

/**
 * Copyright (c) 2009 Anders Ekdahl (http://coffeescripter.com/)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version: 1.2.2
 *
 * Demo and documentation: http://coffeescripter.com/code/ad-gallery/
 */
(function($) {
    $.fn.lbGallery = function(options){
        var defaults = {
            close_txt: "Zavøít"
        };
        var settings = $.extend(false, defaults, options);

        var doc_div = "<div id='lb_overlay'></div>\n\
                    <div id='lb_gallery' class='ad-gallery'>\n\
                    <div class='ad-image-wrapper'>\n\
                    </div>\n\
                    <div class='ad-nav'>\n\
                        <div class='ad-thumbs'>\n\
                            <ul class='ad-thumb-list'>\n\
                            </ul>\n\
                        </div>\n\
                    </div>\n\
                    <div class='ad-controls'>\n\
                    <a id='lb_close'>"+settings.close_txt+"</a>\n\
                    </div>\n\
                </div>\n\
                ";

        $imgs = $(this).find('a');
        $imgs.each(function(i){
        
            $(this).unbind('click').click(function(){
                var xScroll, yScroll;
                if (self.pageYOffset) {
                    yScroll = self.pageYOffset;
                    xScroll = self.pageXOffset;
                } else if (document.documentElement && document.documentElement.scrollTop) {// Explorer 6 Strict
                    yScroll = document.documentElement.scrollTop;
                    xScroll = document.documentElement.scrollLeft;
                } else if (document.body) {// all other Explorers
                    yScroll = document.body.scrollTop;
                    xScroll = document.body.scrollLeft;	
                }

                $('body').prepend(doc_div);

                $('#lb_overlay').css({
                    width:$(document).width(),
                    height:$(document).height()
                    });

                $('#lb_gallery').css({
                    left:$(document).width()>$('#lb_gallery').width()?$(document).width()/2 - $('#lb_gallery').width()/2:0,
                    top:yScroll+50
                    });

                $(window).resize(function(){
                    $('#lb_overlay').css({
                        width:$(document).width(),
                        height:$(document).height()
                        });
                });

                //var widthOfThumb = parseInt($('.ad-thumb-list').css('width'));
            
                $imgs.each(function(i){
                    var longdesc = $(this).find("img").attr('alt');
                    var title = $(this).find("img").attr('title');
                    var className = $(this).find("img").attr('class');
                    var href = $(this).attr('href');
                    var src = $(this).find("img").attr('src');
                
                    $('.ad-thumb-list').append("<li><a href='"+href+"'>\
                                            <img src='"+src+"' title='"+title+"' longdesc='"+
                                            longdesc+"' class='"+className+"' \
                                            ></a></li>");

                });

                $('#lb_close,#lb_overlay').unbind('click').click(function(){
                    $('#lb_gallery').fadeOut('normal',function(){
                        $('#lb_gallery').remove();$('#lb_overlay').remove()
                        });
                });

                $('#lb_gallery').fadeIn('normal');

                var galleries = $('.ad-gallery').adGallery({
                    loader_image:'../images/ad-gallery/loader.gif',
                    effect:'fade',
                    start_at_index:i,
                    animate_first_image:true,
                    cycle:false,
                    slideshow: {
                        enable: false
                    }
                    });

                return false;

            });

        });

    };


    $.fn.adGallery = function(options) {
        var defaults = {
            loader_image: 'loader.gif',
            start_at_index: 0,
            thumb_opacity: 0.6,
            animate_first_image: false,
            animation_speed: 400,
            width: false,
            height: false,
            display_next_and_prev: true,
            display_back_and_forward: true,
            scroll_jump: 0, // If 0, it jumps the width of the container
            slideshow: {
                enable: true,
                autostart: false,
                speed: 5000,
                start_label: 'Start',
                stop_label: 'Stop',
                stop_on_scroll: true,
                countdown_prefix: '(',
                countdown_sufix: ')',
                onStart: false,
                onStop: false
            },
            effect: 'slide-hori', // or 'slide-vert', 'fade', or 'resize', 'none'
            enable_keyboard_move: true,
            cycle: true,
            callbacks: {
                init: false,
                afterImageVisible: false,
                beforeImageVisible: false
            }
        };
        var settings = $.extend(false, defaults, options);
        if(options && options.slideshow) {
            settings.slideshow = $.extend(false, defaults.slideshow, options.slideshow);
        };
        if(!settings.slideshow.enable) {
            settings.slideshow.autostart = false;
        };
        var galleries = [];
        $(this).each(function() {
            var gallery = new AdGallery(this, settings);
            galleries[galleries.length] = gallery;
        });
        // Sorry, breaking the jQuery chain because the gallery instances
        // are returned so you can fiddle with them
        return galleries;
    };

    function VerticalSlideAnimation(img_container, direction, desc) {
        var current_top = parseInt(img_container.css('top'), 10);
        if(direction == 'left') {
            var old_image_top = '-'+ this.image_wrapper_height +'px';
            img_container.css('top', this.image_wrapper_height +'px');
        } else {
            var old_image_top = this.image_wrapper_height +'px';
            img_container.css('top', '-'+ this.image_wrapper_height +'px');
        };
        if(desc) {
            desc.css('bottom', '-'+ desc[0].offsetHeight +'px');
            desc.animate({
                bottom: 0
            }, this.settings.animation_speed * 2);
        };
        return {
            old_image: {
                top: old_image_top
            },
            new_image: {
                top: current_top
            }
            };
    };

    function HorizontalSlideAnimation(img_container, direction, desc) {
        var current_left = parseInt(img_container.css('left'), 10);
        if(direction == 'left') {
            var old_image_left = '-'+ this.image_wrapper_width +'px';
            img_container.css('left',this.image_wrapper_width +'px');
        } else {
            var old_image_left = this.image_wrapper_width +'px';
            img_container.css('left','-'+ this.image_wrapper_width +'px');
        };
        if(desc) {
            desc.css('bottom', '-'+ desc[0].offsetHeight +'px');
            desc.animate({
                bottom: 0
            }, this.settings.animation_speed * 2);
        };
        return {
            old_image: {
                left: old_image_left
            },
            new_image: {
                left: current_left
            }
            };
    };

    function ResizeAnimation(img_container, direction, desc) {
        var image_width = img_container.width();
        var image_height = img_container.height();
        var current_left = parseInt(img_container.css('left'), 10);
        var current_top = parseInt(img_container.css('top'), 10);
        img_container.css({
            width: 0,
            height: 0,
            top: this.image_wrapper_height / 2,
            left: this.image_wrapper_width / 2
            });
        return {
            old_image: {
                width: 0,
                height: 0,
                top: this.image_wrapper_height / 2,
                left: this.image_wrapper_width / 2
                },
            new_image: {
                width: image_width,
                height: image_height,
                top: current_top,
                left: current_left
            }
            };
    };

    function FadeAnimation(img_container, direction, desc) {
        img_container.css('opacity', 0);
        return {
            old_image: {
                opacity: 0
            },
            new_image: {
                opacity: 1
            }
            };
    };

    // Sort of a hack, will clean this up... eventually
    function NoneAnimation(img_container, direction, desc) {
        img_container.css('opacity', 0);
        return {
            old_image: {
                opacity: 0
            },
            new_image: {
                opacity: 1
            },
            speed: 0
        };
    };

    function AdGallery(wrapper, settings) {
        this.init(wrapper, settings);
    };
    AdGallery.prototype = {
        // Elements
        wrapper: false,
        image_wrapper: false,
        gallery_info: false,
        nav: false,
        loader: false,
        preloads: false,
        thumbs_wrapper: false,
        scroll_back: false,
        scroll_forward: false,
        next_link: false,
        prev_link: false,

        slideshow: false,
        image_wrapper_width: 0,
        image_wrapper_height: 0,
        current_index: 0,
        current_image: false,
        //nav_display_width: 0,
        nav_display_height: 0,
        settings: false,
        images: false,
        in_transition: false,
        animations: false,
        init: function(wrapper, settings) {
            var context = this;
            this.wrapper = $(wrapper);
            this.settings = settings;
            this.setupElements();
            this.setupAnimations();
            if(this.settings.width) {
                this.image_wrapper_width = this.settings.width;
                this.image_wrapper.width(this.settings.width);
                this.wrapper.width(this.settings.width);
            } else {
                this.image_wrapper_width = this.image_wrapper.width();
            };
            if(this.settings.height) {
                this.image_wrapper_height = this.settings.height;
                this.image_wrapper.height(this.settings.height);
            } else {
                this.image_wrapper_height = this.image_wrapper.height();
            };
            //this.nav_display_width = this.nav.width();
            this.nav_display_height = this.nav.height();
            this.current_index = 0;
            this.current_image = false;
            this.in_transition = false;

            this.thumbs_wrapper.scroll(function(){
                context.showHideBackForward();
            });

            this.findImages();
            if(this.settings.display_next_and_prev) {
                this.initNextAndPrev();
            };
            // The slideshow needs a callback to trigger the next image to be shown
            // but we don't want to give it access to the whole gallery instance
            var nextimage_callback = function(callback) {
                return context.nextImage(callback);
            };
            this.slideshow = new AdGallerySlideshow(nextimage_callback, this.settings.slideshow);
            this.controls.append(this.slideshow.create());
            if(this.settings.slideshow.enable) {
                this.slideshow.enable();
            } else {
                this.slideshow.disable();
            };
            if(this.settings.display_back_and_forward) {
                this.initBackAndForward();
            };
            if(this.settings.enable_keyboard_move) {
                this.initKeyEvents();
            };
            var start_at = this.settings.start_at_index;
            if(window.location.hash && window.location.hash.indexOf('#ad-image') === 0) {
                start_at = window.location.hash.replace(/[^0-9]+/g, '');
                // Check if it's a number
                if((start_at * 1) != start_at) {
                    start_at = this.settings.start_at_index;
                };
            };

      

            this.loading(true);
            this.showImage(start_at,
                function() {
                    // We don't want to start the slideshow before the image has been
                    // displayed
                    if(context.settings.slideshow.autostart) {
                        context.preloadImage(start_at + 1);
                        context.slideshow.start();
                    };
                }
                );
            this.fireCallback(this.settings.callbacks.init);
        },
        setupAnimations: function() {
            this.animations = {
                'slide-vert': VerticalSlideAnimation,
                'slide-hori': HorizontalSlideAnimation,
                'resize': ResizeAnimation,
                'fade': FadeAnimation,
                'none': NoneAnimation
            };
        },
        setupElements: function() {
            this.controls = this.wrapper.find('.ad-controls');
            this.gallery_info = $('<p class="ad-info"></p>');
            this.controls.append(this.gallery_info);
            this.image_wrapper = this.wrapper.find('.ad-image-wrapper');
            this.image_wrapper.empty();
            this.nav = this.wrapper.find('.ad-nav');
            this.thumbs_wrapper = this.nav.find('.ad-thumbs');
            this.preloads = $('<div class="ad-preloads"></div>');
            this.loader = $('<img class="ad-loader" src="'+ this.settings.loader_image +'">');
            this.image_wrapper.append(this.loader);
            this.loader.hide();
            $(document.body).append(this.preloads);
        },
        loading: function(bool) {
            if(bool) {
                this.loader.show();
            } else {
                this.loader.hide();
            };
        },
        addAnimation: function(name, fn) {
            if($.isFunction(fn)) {
                this.animations[name] = fn;
            };
        },
        findImages: function() {
            var context = this;
            this.images = [];
            //var thumb_wrapper_width = 0;
            var thumb_wrapper_height = 0;
            var thumbs_loaded = 0;
            var thumbs = this.thumbs_wrapper.find('a');
            var thumb_count = thumbs.length;
            if(this.settings.thumb_opacity < 1) {
                thumbs.find('img').css('opacity', this.settings.thumb_opacity);
            };
            thumbs.each(
                function(i) {
                    var link = $(this);
                    var image_src = link.attr('href');
                    var thumb = link.find('img');

                    //nastavime sirku a vysku thumb obrazkov
                    var widthOfThumb = parseInt($('.ad-thumb-list').css('width'));
                    var width = thumb[0].width;
                    var height = thumb[0].height;
                    var heightOfThumb = Math.round(height*(widthOfThumb/width));

                    thumb.css('width',widthOfThumb+'px');
                    thumb.css('height',heightOfThumb+'px');

                    // Check if the thumb has already loaded
                    if(!context.isImageLoaded(thumb[0])) {
                        thumb.load(
                            function() {
                                //thumb_wrapper_width += this.parentNode.parentNode.offsetWidth;
                                thumb_wrapper_height += this.parentNode.parentNode.offsetHeight;
                                thumbs_loaded++;
                            }
                            );
                    } else{
                        //thumb_wrapper_width += thumb[0].parentNode.parentNode.offsetWidth;
                        thumb_wrapper_height += thumb[0].parentNode.parentNode.offsetHeight;
                        thumbs_loaded++;
                    };

                    link.addClass('ad-thumb'+ i);
                    link.click(
                        function() {
                            context.showImage(i);
                            context.slideshow.stop();
                            return false;
                        }
                        ).hover(
                        function() {
                            if(!$(this).is('.ad-active') && context.settings.thumb_opacity < 1) {
                                $(this).find('img').fadeTo(300, 1);
                            };
                            context.preloadImage(i);
                        },
                        function() {
                            if(!$(this).is('.ad-active') && context.settings.thumb_opacity < 1) {
                                $(this).find('img').fadeTo(300, context.settings.thumb_opacity);
                            };
                        }
                        );
                    var desc = false;
                    if(thumb.data('ad-desc')) {
                        desc = thumb.data('ad-desc');
                    } else if(thumb.attr('longdesc') && thumb.attr('longdesc').length) {
                        desc = thumb.attr('longdesc');
                    };
                    var title = false;
                    if(thumb.data('ad-title')) {
                        title = thumb.data('ad-title');
                    } else if(thumb.attr('title') && thumb.attr('title').length) {
                        title = thumb.attr('title');
                    };
                    context.images[i] = {
                        thumb: thumb.attr('src'),
                        image: image_src,
                        error: false,
                        preloaded: false,
                        desc: desc,
                        title: title,
                        size: false
                    };
                }
                );
            // Wait until all thumbs are loaded, and then set the width of the ul
            var inter = setInterval(
                function() {
                    if(thumb_count == thumbs_loaded) {
                        //context.nav.find('.ad-thumb-list').css('width', thumb_wrapper_width +'px');
                        context.nav.find('.ad-thumb-list').css('height', thumb_wrapper_height +'px');
                        clearInterval(inter);
                        context.showHideBackForward();
                    };
                },
                100
                );
        },
        initKeyEvents: function() {
            var context = this;
            $(document).keydown(
                function(e) {
                    if(e.keyCode == 39) {
                        // right arrow
                        context.nextImage();
                        context.slideshow.stop();
                    } else if(e.keyCode == 37) {
                        // left arrow
                        context.prevImage();
                        context.slideshow.stop();
                    };
                }
                );
        },
        initNextAndPrev: function() {
            this.next_link = $('<div class="ad-next"><div class="ad-next-image"></div></div>');
            this.prev_link = $('<div class="ad-prev"><div class="ad-prev-image"></div></div>');
            //this.next_link = $('<div class="ad-next"></div>');
            //this.prev_link = $('<div class="ad-prev"></div>');
            this.image_wrapper.append(this.next_link);
            this.image_wrapper.append(this.prev_link);
            var context = this;
            this.prev_link.add(this.next_link).mouseover(
                function(e) {
                    // IE 6 hides the wrapper div, so we have to set it's width
                    $(this).css('height', context.image_wrapper_height);
                    $(this).find('div').show();
                }
                ).mouseout(
                function(e) {
                    $(this).find('div').hide();
                }
                ).click(
                function() {
                    if($(this).is('.ad-next')) {
                        context.nextImage();
                        context.slideshow.stop();
                    } else {
                        context.prevImage();
                        context.slideshow.stop();
                    };
                }
                ).find('div').css('opacity', 0.7);
        },
        showHideBackForward: function(){//skryje nepotrebne sipky
        
            if(this.thumbs_wrapper.scrollTop()==0){
                this.scroll_back.hide();
            }
            else{
                this.scroll_back.show();
            }
            if(this.thumbs_wrapper.scrollTop() == this.thumbs_wrapper.find('.ad-thumb-list').height()-this.thumbs_wrapper.height()||
                this.thumbs_wrapper.find('.ad-thumb-list').height()<=this.thumbs_wrapper.height()){
                this.scroll_forward.hide();
            }
            else{
                this.scroll_forward.show();
            }
        },
        initBackAndForward: function() {
            var context = this;
            this.scroll_forward = $('<div class="ad-forward"></div>');
            this.scroll_back = $('<div class="ad-back"></div>');
            this.nav.append(this.scroll_forward);
            this.nav.prepend(this.scroll_back);
            var has_scrolled = 0;
            var thumbs_scroll_interval = false;
      
            $(this.scroll_back).add(this.scroll_forward).click(
                function() {
                    // We don't want to jump the whole width, since an image
                    // might be cut at the edge
                    //var width = context.nav_display_width - 50;
                    var height = context.nav_display_height - 50;
                    if(context.settings.scroll_jump > 0) {
                        //var width = context.settings.scroll_jump;
                        var height = context.settings.scroll_jump;
                    };
                    if($(this).is('.ad-forward')) {
                        //var left = context.thumbs_wrapper.scrollLeft() + width;
                        var top = context.thumbs_wrapper.scrollTop() + height;
                    } else {
                        //var left = context.thumbs_wrapper.scrollLeft() - width;
                        var top = context.thumbs_wrapper.scrollTop() - height;
                    };
                    if(context.settings.slideshow.stop_on_scroll) {
                        context.slideshow.stop();
                    };
                    //context.thumbs_wrapper.animate({scrollLeft: left +'px'});
                    context.thumbs_wrapper.animate({
                        scrollTop: top +'px'
                        });
                    return false;
                }
                ).css('opacity', 0.6).hover(
                function() {
                    //var direction = 'left';
                    var direction = 'top';
                    if($(this).is('.ad-forward')) {
                        //direction = 'right';
                        direction = 'bottom';
                    };
                    thumbs_scroll_interval = setInterval(
                        function() {
                            has_scrolled++;
                            // Don't want to stop the slideshow just because we scrolled a pixel or two
                            if(has_scrolled > 30 && context.settings.slideshow.stop_on_scroll) {
                                context.slideshow.stop();
                            };
                            //var left = context.thumbs_wrapper.scrollLeft() + 1;
                            var top = context.thumbs_wrapper.scrollTop() + 1;
                            //if(direction == 'left') {
                            if(direction == 'top') {
                                //left = context.thumbs_wrapper.scrollLeft() - 1;
                                top = context.thumbs_wrapper.scrollTop() - 1;
                            };
                            //context.thumbs_wrapper.scrollLeft(left);
                            context.thumbs_wrapper.scrollTop(top);
                        },
                        10
                        );
                    $(this).css('opacity', 1);
                },
                function() {
                    has_scrolled = 0;
                    clearInterval(thumbs_scroll_interval);
                    $(this).css('opacity', 0.6);
                }
                );
        },
        _afterShow: function() {
            this.gallery_info.html((this.current_index + 1) +' / '+ this.images.length);
            if(!this.settings.cycle) {
                // Needed for IE
                this.prev_link.show().css('height', this.image_wrapper_height);
                this.next_link.show().css('height', this.image_wrapper_height);
                if(this.current_index == (this.images.length - 1)) {
                    this.next_link.hide();
                };
                if(this.current_index == 0) {
                    this.prev_link.hide();
                };
            };
            this.fireCallback(this.settings.callbacks.afterImageVisible);
        },
        /**
     * Checks if the image is small enough to fit inside the container
     * If it's not, shrink it proportionally
     */
        _getContainedImageSize: function(image_width, image_height) {
            if(image_height > this.image_wrapper_height) {
                var ratio = image_width / image_height;
                image_height = this.image_wrapper_height;
                image_width = this.image_wrapper_height * ratio;
            };
            if(image_width > this.image_wrapper_width) {
                var ratio = image_height / image_width;
                image_width = this.image_wrapper_width;
                image_height = this.image_wrapper_width * ratio;
            };
            return {
                width: image_width,
                height: image_height
            };
        },
        /**
     * If the image dimensions are smaller than the wrapper, we position
     * it in the middle anyway
     */
        _centerImage: function(img_container, image_width, image_height) {
            img_container.css('top', '0px');
            if(image_height < this.image_wrapper_height) {
                var dif = this.image_wrapper_height - image_height;
                img_container.css('top', (dif / 2) +'px');
            };
            img_container.css('left', '0px');
            if(image_width < this.image_wrapper_width) {
                var dif = this.image_wrapper_width - image_width;
                img_container.css('left', (dif / 2) +'px');
            };
        },
        _getDescription: function(image) {
            var desc = false;
            if(image.desc.length || image.title.length) {
                var title = '';
                if(image.title.length) {
                    title = '<strong class="ad-description-title">'+ image.title +'</strong>';
                };
                var desc = '';
                if(image.desc.length) {
                    desc = '<span>'+ image.desc +'</span>';
                };
                desc = $('<p class="ad-image-description">'+ title + desc +'</p>');
            };
            return desc;
        },
        /**
     * @param function callback Gets fired when the image has loaded, is displaying
     *                          and it's animation has finished
     */
        showImage: function(index, callback) {
            if(this.images[index] && !this.in_transition) {
                var context = this;
                var image = this.images[index];
                this.in_transition = true;
                if(!image.preloaded) {
                    this.loading(true);
                    this.preloadImage(index, function() {
                        context.loading(false);
                        context._showWhenLoaded(index, callback);
                    });
                } else {
                    this._showWhenLoaded(index, callback);
                };
            };
        },
        /**
     * @param function callback Gets fired when the image has loaded, is displaying
     *                          and it's animation has finished
     */
        _showWhenLoaded: function(index, callback) {
            if(this.images[index]) {
                var context = this;
                var image = this.images[index];
                var img_container = $(document.createElement('div')).addClass('ad-image');
                var img = $(new Image()).attr('src', image.image);
                img_container.append(img);
                this.image_wrapper.prepend(img_container);
                var size = this._getContainedImageSize(image.size.width, image.size.height);
                img.attr('width', size.width);
                img.attr('height', size.height);
                img_container.css({
                    width: size.width +'px',
                    height: size.height +'px'
                    });
                this._centerImage(img_container, size.width, size.height);
                var desc = this._getDescription(image, img_container);
                if(desc) {
                    img_container.append(desc);
                    var width = size.width - parseInt(desc.css('padding-left'), 10) - parseInt(desc.css('padding-right'), 10);
                    desc.css('width', width +'px');
                };
                this.highLightThumb(this.nav.find('.ad-thumb'+ index));

                var direction = 'right';
                if(this.current_index < index) {
                    direction = 'left';
                };
                this.fireCallback(this.settings.callbacks.beforeImageVisible);
                if(this.current_image || this.settings.animate_first_image) {
                    var animation_speed = this.settings.animation_speed;
                    var easing = 'swing';
                    var animation = this.animations[this.settings.effect].call(this, img_container, direction, desc);
                    if(typeof animation.speed != 'undefined') {
                        animation_speed = animation.speed;
                    };
                    if(typeof animation.easing != 'undefined') {
                        easing = animation.easing;
                    };
                    if(this.current_image) {
                        var old_image = this.current_image;
                        old_image.animate(animation.old_image, animation_speed, easing,
                            function() {
                                old_image.remove();
                            }
                            );
                    };
                    img_container.animate(animation.new_image, animation_speed, easing,
                        function() {
                            context.current_index = index;
                            context.current_image = img_container;
                            context.in_transition = false;
                            context._afterShow();
                            context.fireCallback(callback);
                        }
                        );
                } else {
                    this.current_index = index;
                    this.current_image = img_container;
                    this.in_transition = false;
                    context._afterShow();
                    this.fireCallback(callback);
                };
            };
        },
        nextIndex: function() {
            if(this.current_index == (this.images.length - 1)) {
                if(!this.settings.cycle) {
                    return false;
                };
                var next = 0;
            } else {
                var next = this.current_index + 1;
            };
            return next;
        },
        nextImage: function(callback) {
            var next = this.nextIndex();
            if(next === false) return false;
            this.preloadImage(next + 1);
            this.showImage(next, callback);
            return true;
        },
        prevIndex: function() {
            if(this.current_index == 0) {
                if(!this.settings.cycle) {
                    return false;
                };
                var prev = this.images.length - 1;
            } else {
                var prev = this.current_index - 1;
            };
            return prev;
        },
        prevImage: function(callback) {
            var prev = this.prevIndex();
            if(prev === false) return false;
            this.preloadImage(prev - 1);
            this.showImage(prev, callback);
            return true;
        },
        preloadAll: function() {
            var context = this;
            var i = 0;
            function preloadNext() {
                if(i < context.images.length) {
                    i++;
                    context.preloadImage(i, preloadNext);
                };
            };
            context.preloadImage(i, preloadNext);
        },
        preloadImage: function(index, callback) {
            if(this.images[index]) {
                var image = this.images[index];
                if(!this.images[index].preloaded) {
                    var img = $(new Image());
                    img.attr('src', image.image);
                    if(!this.isImageLoaded(img[0])) {
                        this.preloads.append(img);
                        var context = this;
                        img.load(
                            function() {
                                image.preloaded = true;
                                image.size = {
                                    width: this.width,
                                    height: this.height
                                };
                                context.fireCallback(callback);
                            }
                            ).error(
                            function() {
                                image.error = true;
                                image.preloaded = false;
                                image.size = false;
                            }
                            );
                    } else {
                        image.preloaded = true;
                        image.size = {
                            width: img[0].width,
                            height: img[0].height
                        };
                        this.fireCallback(callback);
                    };
                } else {
                    this.fireCallback(callback);
                };
            };
        },
        isImageLoaded: function(img) {
            if(typeof img.complete != 'undefined' && !img.complete) {
                return false;
            };
            if(typeof img.naturalWidth != 'undefined' && img.naturalWidth == 0) {
                return false;
            };
            return true;
        },
        highLightThumb: function(thumb) {
            this.thumbs_wrapper.find('.ad-active').removeClass('ad-active');
            thumb.addClass('ad-active');
            if(this.settings.thumb_opacity < 1) {
                this.thumbs_wrapper.find('a:not(.ad-active) img').fadeTo(300, this.settings.thumb_opacity);
                thumb.find('img').fadeTo(300, 1);
            };
            //var left = thumb[0].parentNode.offsetLeft;
            //left -= (this.nav_display_width / 2) - (thumb[0].offsetWidth / 2);
            //this.thumbs_wrapper.animate({scrollLeft: left +'px'});
            var top = thumb[0].parentNode.offsetTop;
            top -= (this.nav_display_height / 2) - (thumb[0].offsetHeight / 2);
            this.thumbs_wrapper.animate({
                scrollTop: top +'px'
                });
        },
        fireCallback: function(fn) {
            if($.isFunction(fn)) {
                fn.call(this);
            };
        }
    };

    function AdGallerySlideshow(nextimage_callback, settings) {
        this.init(nextimage_callback, settings);
    };
    AdGallerySlideshow.prototype = {
        start_link: false,
        stop_link: false,
        countdown: false,
        controls: false,

        settings: false,
        nextimage_callback: false,
        enabled: false,
        running: false,
        countdown_interval: false,
        init: function(nextimage_callback, settings) {
            var context = this;
            this.nextimage_callback = nextimage_callback;
            this.settings = settings;
        },
        create: function() {
            this.start_link = $('<span class="ad-slideshow-start">'+ this.settings.start_label +'</span>');
            this.stop_link = $('<span class="ad-slideshow-stop">'+ this.settings.stop_label +'</span>');
            this.countdown = $('<span class="ad-slideshow-countdown"></span>');
            this.controls = $('<div class="ad-slideshow-controls"></div>');
            this.controls.append(this.start_link).append(this.stop_link).append(this.countdown);
            this.countdown.hide();

            var context = this;
            this.start_link.click(
                function() {
                    context.start();
                }
                );
            this.stop_link.click(
                function() {
                    context.stop();
                }
                );
            $(document).keydown(
                function(e) {
                    if(e.keyCode == 83) {
                        // 's'
                        if(context.running) {
                            context.stop();
                        } else {
                            context.start();
                        };
                    };
                }
                );
            return this.controls;
        },
        disable: function() {
            this.enabled = false;
            this.stop();
            this.controls.hide();
        },
        enable: function() {
            this.enabled = true;
            this.controls.show();
        },
        toggle: function() {
            if(this.enabled) {
                this.disable();
            } else {
                this.enable();
            };
        },
        start: function() {
            if(this.running || !this.enabled) return false;
            var context = this;
            this.running = true;
            this.controls.addClass('ad-slideshow-running');
            this._next();
            this.fireCallback(this.settings.onStart);
            return true;
        },
        stop: function() {
            if(!this.running) return false;
            this.running = false;
            this.countdown.hide();
            this.controls.removeClass('ad-slideshow-running');
            clearInterval(this.countdown_interval);
            this.fireCallback(this.settings.onStop);
            return true;
        },
        _next: function() {
            var context = this;
            var pre = this.settings.countdown_prefix;
            var su = this.settings.countdown_sufix;
            clearInterval(context.countdown_interval);
            this.countdown.show().html(pre + (this.settings.speed / 1000) + su);
            var slide_timer = 0;
            this.countdown_interval = setInterval(
                function() {
                    slide_timer += 1000;
                    if(slide_timer >= context.settings.speed) {
                        var whenNextIsShown = function() {
                            // A check so the user hasn't stoped the slideshow during the
                            // animation
                            if(context.running) {
                                context._next();
                            };
                            slide_timer = 0;
                        };
                        if(!context.nextimage_callback(whenNextIsShown)) {
                            context.stop();
                        };
                        slide_timer = 0;
                    };
                    var sec = parseInt(context.countdown.text().replace(/[^0-9]/g, ''), 10);
                    sec--;
                    if(sec > 0) {
                        context.countdown.html(pre + sec + su);
                    };
                },
                1000
                );
        },
        fireCallback: function(fn) {
            if($.isFunction(fn)) {
                fn.call(this);
            };
        }
    };
})(jQuery);
