/*
 * Copyright (C) 2010, Evert Bauwens, All rights reserved.
 * http://evertbauwens.net/
 */

function Slideshow(dialogUrl)
{
    var s = this;


    s.images = {};
    s.current = null;
    s.frame = null;
    s.layer = null;
    s.labels = {};


    s.open = function(name)
    {
        // gather info on configured images...
        var p, i = 0;
        for(var n in s.images)
        {
            s.images[n].name = n;
            s.images[n].number = ++ i;
            // reset next and previous to null (for if ever the list of images was changed)
            s.images[n].next = s.images[n].previous = null;
            if(p)
            {
                p.next = s.images[n];
                s.images[n].previous = p;
            }
            p = s.images[n];
        }
        s.numImages = i;

        // create iframe that will contain the slideshow dialog
        s.frame = $('<iframe scrolling="no" frameborder="no"></iframe>');
        s.frame.css(
        {
            position: 'absolute',
            zIndex: 102,
            display: 'none' // not shown as long as the exact dimensions (can
            // only be known once the first image is loaded) haven't been set
        });
        $(document.body).append(s.frame);
        s.frame.attr('src', dialogUrl);
        s.frame.load(function()
        {
            // put a reference to this slideshow object in the frame
            this.contentWindow.slideshow = s;

            // document object of the frame
            var frameDoc = $(this.contentWindow.document);

            // set key shortcut handler both in parent and frame window!
            $(document).keyup(s.handleKey);
            frameDoc.keyup(s.handleKey);

            // load labels
            $('#frontImg', frameDoc).attr('title', s.labels.next);
            $('#prev', frameDoc).attr('title', s.labels.prev);
            $('#next', frameDoc).attr('title', s.labels.next);
            $('#full', frameDoc).html(s.labels.full);
            $('#close', frameDoc).attr('title', s.labels.close);

            // create background "smoke" layer
            s.layer = $('<div></div>');
            s.layer.css(
            {
                position: 'absolute',
                left: 0,
                top: 0,
                zIndex: 101,
                opacity: 0.7,
                backgroundColor: 'black',
                display: 'none' // not shown as long as the exact dimension haven't been set
            });
            $(document.body).append(s.layer);

            // when the user clicks outside the slideshow frame, it must be closed
            s.layer.click(s.close);

            // whenever the window is resized we need to recenter the frame and
            // resize the background layer so that it covers the entire document
            // We also resize the frame in this function because it may have an
            // influence on the document size, which is required to find the new
            // layer size. Therefore we always perform these operations together.
            // NOTE that this won't work in some browsers as long as the frame
            // hasn't been shown because it's dimensions are then undifined (or 0)
            $(window).resize(function()
            {
                // this is a trick to make the frame discard additional space
                // beyond the actual extends of it's content that may have been
                // added by a previous larger image
                s.frame.width(1); s.frame.height(1);

                // resize the frame to the correct dimensions
                var w = frameDoc.width(), h = frameDoc.height();
                s.frame.width(w); s.frame.height(h);
                
                // recenter the frame
                s.frame.offset(
                {
                    left: Math.max(0, Math.round(($(window).width() - w)/2.0) + $(document).scrollLeft()),
                     top: Math.max(0, Math.round(($(window).height() - h)/2.0) + $(document).scrollTop())
                });
                
                s.layer.width($(document).width());
                s.layer.height($(document).height());
                s.layer.show();
            });

            // the image onLoad handlers are defined here once. They will be
            // triggered whenever the back image's source is changed (changing
            // it to the front image's source is the first step in changing
            // the current image to show.
            var front = $('#frontImg', frameDoc);
            var back = $('#backImg', frameDoc);
            back.load(function()
            {
                front.hide();
                front.attr('src', s.current.large);
            });
            front.load(function()
            {
                // we need to show the frame now, otherwise some browser's wont
                // give the correct image dimensions. Unfortunately the frame
                // still has the wrong dimensions, but this will be corrected
                // quickly by triggering window.resize() below...
                s.frame.show();
                // For the same reasons, wel also need to start showing the
                // frontal image before we can reliably get it's dimensions
                front.fadeIn('slow', 'linear', function()
                {
                    back.show();
                    // indicate we're ready with the image transition (see below)
                    s.changingImage = false;
                });
                // set the dimensions of the image area and back image to match
                // the front image
                var area = $('#imgArea', frameDoc);
                area.width(this.width); area.height(this.height);
                back.width(this.width); back.height(this.height);
                $(window).resize();
            });

            // start loading current image
            s.changeImage(s.images[name]);
        });
    }

    s.next = function()
    {
        if(s.current && s.current.next)
            s.changeImage(s.current.next);
    }


    s.previous = function()
    {
        if(s.current && s.current.previous)
            s.changeImage(s.current.previous);
    }


    s.changeImage = function(image)
    {
        // if an image transition is still in progress -> ignore this request
        // we could do all kinds of fancy tricks to buffer these request
        // or what not but that would easily get pretty complicated and you
        // wouldn't really gain that much.
        if(s.changingImage) return;
        s.changingImage = true;

        s.current = image;
        
        var frameDoc = $(s.frame.attr('contentWindow').document);
        var front = $('#frontImg', frameDoc);
        var back = $('#backImg', frameDoc);

        // check if the frontal image is already loaded (i.e. has a valid source)
        var oldUrl = front.attr('src');
        if(oldUrl) back.attr('src', oldUrl); // if so change the back source to it
        else back.load(); // otherwise just trigger back.load manually

        // load title etc...
        $('#title', frameDoc).html(image.title);
        $('#full', frameDoc).attr('href', image.full);
        $('#imgNum', frameDoc).html(image.number + '/' + s.numImages);
        $('#prev',  frameDoc).css('display',  image.previous ? 'inline' : 'none');
        $('#next',  frameDoc).css('display',  image.next     ? 'inline' : 'none');
        $('#first', frameDoc).css('display', !image.previous ? 'inline' : 'none');
        $('#last',  frameDoc).css('display', !image.next     ? 'inline' : 'none');

        // preload next and previous images
        s.preload(image.next);
        s.preload(image.previous);
    }


    s.close = function()
    {
        s.changingImage = false;
        s.frame.remove();
        s.layer.remove();
        $(document).unbind('keyup', s.handleKey);
    }


    s.preload = function(image)
    {
        if(image)
        {
            image.preload = new Image();
            image.preload.src = image.large;
        }
    }


    s.handleKey = function(e)
    {
        switch(e.which)
        {
            case 27:
                // escape
                s.close();
                e.preventDefault();
                break;
            case 37:
                // left
                s.previous();
                e.preventDefault();
                break;
            case 39:
                // right
                s.next();
                e.preventDefault();
                break;
        }
    }
}
