function init_image_viewer(images, start, url_prefix, thumb_url_prefix) {
    var scroll_timeout = null;
    var cur_n = 0;

    $(window).resize(function() {
        var size = calcsize(cur_n);
        $('#shot')
            .attr('width', size[0])
            .attr('height', size[1])
        if (scroll_timeout)
            clearTimeout(scroll_timeout);
        scroll_timeout = setTimeout(function() { scroll_to(cur_n); }, 100);
    });

    set_image(start);

    var $container = $('#thumbnails div');
    for (var i = 0; i < images.length; i++) {
        var image = images[i];
        $container.append(
            $('<img>')
                .addClass('thumb')
                .attr('id', i + 1)
                .attr('src', thumb_url_prefix + image[0])
                .attr('alt', '')
                .attr('width', image[3][0])
                .attr('height', image[3][1])
                .hover(
                    function() {
                        $(this).css('opacity', 0.8).css('-moz-opacity', 0.8);
                    },
                    function() {
                        $(this).css('opacity', 1.0).css('-moz-opacity', 1.0);
                    })
                .click(function() {
                    set_image(this.id);
                })
            );
    }

    if ($.browser.opera)
        /* For whatever reason, opera does not propertly adjust the thumbnails
         * div height to reflect the just-added images, so the images don't show.
         * This lame hack here somehow triggers a reflow on the div to make it
         * resize.
         */
        $container.append(' ');

    if ($.browser.msie)
        // IE eats into the div height for the scrollbar.
        $container.css('padding-bottom', '16px');

    scroll_to(start);

    function calcsize(n) {
        var w = document.documentElement.clientWidth - 250;
        var size = images[n - 1][2];
        if (size[0] < w)
            return size;
        return [w, parseInt(w * (size[1] / size[0]))];
    }


    function scroll_to(n) {
        var $thumb = $('#' + n);
        if ($thumb.size() == 0)
            return;

        var $thumbnails = $('#thumbnails')
        var first = $('#1').get(0).offsetLeft;
        var left = ($thumb.get(0).offsetLeft - first) - ($thumbnails.width() / 2) + ($thumb.width() / 2);
        if (scroll_timeout) {
            clearTimeout(scroll_timeout);
            scroll_timeout = null;
        }
        if (cur_n > 0)
            $('#' + cur_n).css({border: '1px solid black', margin: '4px'})
        $thumb.css({border: '3px solid #f45', margin: '2px'})

        $thumbnails.stop();
        $thumbnails.animate({scrollLeft: left}, 500, 'swing');
    }

    function set_image(n) {
        scroll_to(n);
        cur_n = n;
        var image = images[n - 1];
        var src = url_prefix + image[0];
        var size = calcsize(n);
        $('#shot').replaceWith(
            $('<img>')
                .attr('id', 'shot')
                .attr('src', src)
                .css('border', '1px solid black')
                .attr('width', size[0])
                .attr('height', size[1])
            );
        $('#caption').html(image[1] || "&nbsp;");
        $('#cur_n').text(n);
        //$('#link').attr('href', '?shot=' + n);
    }
}
