// Effect parameters
var slideshowIsRunning   = false; // Indicated whether the slideshow is running (some actions depend on this)
var currentPendingAction = null; // Used to store the currently delayed function (called by the slideshow to keep scrolling between pictures)
var fadeInDuration       = 0.75;
var fadeOutDuration      = 0.75;
var nbAdjacentFrames     = 5;

// Global variable that stores the currently called frame
// This variable ensures that, when several frames are being loaded simultaneously, only the last one called is displayed (because resources may arrive in a different order than the one they were called)
var currentIndex;

// Trim function
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g, '');
}

// Move to a frame
// This method is called by the user clicks
var toFrame = function(index) {

    // Update the current index
    currentIndex = index;

    // Get the frame information
    var resourceIdentifier    = '#resource' + index;
//    var resourceId            = $$(resourceIdentifier + ' .resource_id')[0].innerHTML;
    var type                  = $$(resourceIdentifier + ' .type')[0].innerHTML;
    var number                = $$(resourceIdentifier + ' .number')[0].innerHTML;
    var title                 = $$(resourceIdentifier + ' .title')[0].innerHTML;
    var previousIndex         = $$(resourceIdentifier + ' .previous_index')[0].innerHTML.trim();
    var nextIndex             = $$(resourceIdentifier + ' .next_index')[0].innerHTML.trim();
    var resourceStatusElement = $$(resourceIdentifier + ' .loading_status')[0];
    var resourceStatus        = resourceStatusElement.innerHTML.trim();

    // 1 - Modify the previous and next links so that the user can keep navigating even if the frame is not loaded yet
    // Update the current frame number
    $('current_frame_number').update(index);
    // Update the previous and next links as well as the previous and next indexes
    if (previousIndex.length > 0) {
        $('previous_index').update(previousIndex);
        $('link_previous').update('<div class="page"><a href="#"><img src="' + configStaticImagesPath + 'previous.gif" /></a></div>');
        var linkPrevious = $$('#link_previous a');
        linkPrevious[0].stopObserving('click');
        linkPrevious[0].observe('click', function() {stopZoom(); stopSlideshow(); javascript:toFrame(previousIndex);});
    } else {
        $('previous_index').update('');
        $('link_previous').update('<div class="page"></div>');
    }
    if (nextIndex.length > 0) {
        $('next_index').update(nextIndex);
        $('link_next').update('<div class="page"><a href="#"><img src="' + configStaticImagesPath + 'next.gif" /></a></div>');
        var linkNext = $$('#link_next a');
        linkNext[0].stopObserving('click');
        linkNext[0].observe('click', function() {stopZoom(); stopSlideshow(); javascript:toFrame(nextIndex);});
    } else {
        $('next_index').update('');
        $('link_next').update('<div class="page"></div>');
    }

    // 2 - Show the title of the new frame so that the user can follow where he is
    var newTitle = '';
    if (type == 'image') {
        newTitle = number + '/' + $('nb_images').innerHTML.trim() + '&nbsp;-&nbsp;';
    }
    newTitle = newTitle + title;
    $('detail_title').update(newTitle); // Write the new title

    // 3 - Update the HTML document title
    document.title = title;

    // 4 - Display the frame according to its current status
    // If already loaded, display it and preload the adjacent frames
    if (resourceStatus == 2) {
        displayFrame(index);
        loadAdjacentFrames(index, nbAdjacentFrames);
    // Otherwise, load it and display it when it is loaded via a custom observer, with one condition: by the time it is loaded, it must still be the frame that matches the current index. Along with displaying it, preload the adjacent frames
    } else {
        $('loading').show();
        resourceStatusElement.observe('status:change', function() {
            if ((resourceStatusElement.innerHTML == 2) && (index == currentIndex)) {
                displayFrame(index);
                loadAdjacentFrames(index, nbAdjacentFrames);
            }
        });
        loadFrame(index);
    }

}

// Load a specified number of adjacent frames
var loadAdjacentFrames = function(index, number) {

    // 
    if (number == 0) {
        return;
    }

    // Do nothing if the frame is not defined
    if (!$('resource' + index)) {
        return;
    }

    loadNextFrames(index, number);
    loadPreviousFrames(index, number);
}

// Load a specified number of previous frames
var loadPreviousFrames = function(index, number) {

    // 
    if (number == 0) {
        return;
    }

    // Do nothing if the frame is not defined
    if (!$('resource' + index)) {
        return;
    }

    // Get the frame information
    var resourceIdentifier    = '#resource' + index;
    var previousIndex         = $$(resourceIdentifier + ' .previous_index')[0].innerHTML.trim();

    loadFrame(previousIndex);
    loadPreviousFrames(previousIndex, number - 1);
}

// Load a specified number of next frames
var loadNextFrames = function(index, number) {

    // 
    if (number == 0) {
        return;
    }

    // Do nothing if the frame is not defined
    if (!$('resource' + index)) {
        return;
    }

    // Get the frame information
    var resourceIdentifier    = '#resource' + index;
    var nextIndex             = $$(resourceIdentifier + ' .next_index')[0].innerHTML.trim();

    loadFrame(nextIndex);
    loadNextFrames(nextIndex, number - 1);
}

// Load a frame
var loadFrame = function(index) {

    // Do nothing if the frame is not defined
    if (!$('resource' + index)) {
        return;
    }

    // Get the frame information
    var resourceIdentifier    = '#resource' + index;
    var resourceId            = $$(resourceIdentifier + ' .resource_id')[0].innerHTML;
    var resourceStatusElement = $$(resourceIdentifier + ' .loading_status')[0];
    var resourceStatus        = resourceStatusElement.innerHTML;
    var language              = $('language').innerHTML;

    // Do nothing if the resource is already loading or loaded
    if (resourceStatus != 0) {
        return;
    }

    // Set the status as "loading"
    resourceStatusElement.update(1);

    // Load the next resource through an Ajax request
    new Ajax.Request(configApplicationPath + 'resource.php', {
        method: 'get',
        parameters: 'language=' + language + '&resource_id=' + resourceId,
        onSuccess: function(response) {
            // Insert the new frame into the document, only if it has not been done yet (this test should be unnecessary)
            if (!$('resource_contents' + resourceId)) {
                $('frame_contents').insert({'bottom': response.responseText});
            }

            // In the case of an image, it is not considered loaded until the image itself is completely loaded
            var image = $('resource_contents' + resourceId).down('img');
            if (image)
            {
                image.observe('load', function() {
                    image.stopObserving('load');
                    resourceStatusElement.update(2);
                    resourceStatusElement.fire('status:change');
                });
                // Workaround for Opera: the load event is never fired on Opera if the observer has not been declared before the image source is modified. To solve this problem, after the contents have been retrieved by the ajax call, the observer is declared and then the image source is emptied and reset to its original value, to simulate a modification in the source, therefore properly triggering the load event. This is only useful for Opera, as the other browsers do not have this issue.
                imageSrcBackup = image.readAttribute('src');
                image.writeAttribute('src', '');
                image.writeAttribute('src', imageSrcBackup);
            // In the case of a text, it is immediately loaded
            } else {
                resourceStatusElement.update(2);
                resourceStatusElement.fire('status:change');
            }
        }
    });

};

// Switch the display to a specified frame
var displayFrame = function(index) {

    // Cancel all running effects
    var scope = Effect.Queues.get('detail');
    scope.each(function(effect) {effect.cancel();});

    // Hide the loading indicator
    $('loading').hide();

    // Get the frame information
    var resourceIdentifier    = '#resource' + index;
    var resourceId            = $$(resourceIdentifier + ' .resource_id')[0].innerHTML;
    var type                  = $$(resourceIdentifier + ' .type')[0].innerHTML;
    var orientation           = $$(resourceIdentifier + ' .orientation')[0].innerHTML;
    var src                   = $$(resourceIdentifier + ' .src')[0].innerHTML;
    var img                   = $$(resourceIdentifier + ' .img')[0].innerHTML;
    var contents              = $$(resourceIdentifier + ' .contents')[0].innerHTML;
    var number                = $$(resourceIdentifier + ' .number')[0].innerHTML;
    var title                 = $$(resourceIdentifier + ' .title')[0].innerHTML;
    //var zoomLink              = $$(resourceIdentifier + ' .zoom_link')[0].innerHTML;
    var resourceStatusElement = $$(resourceIdentifier + ' .loading_status')[0];
    var resourceStatus        = resourceStatusElement.innerHTML;

    // Hide the image frame
    new Effect.Morph('detail', {
        queue: {scope: 'detail'},
        style: 'background-color: #2e2e2e;',
        duration: fadeOutDuration
    });
    new Effect.Morph('frame', {
        queue: {scope: 'detail'},
        style: 'background-color: #2e2e2e;',
        duration: fadeOutDuration
    });

    // Hide the contents zone first
    new Effect.Fade('frame_contents', {
        queue: {scope: 'detail'},
        duration: 1.0,
        afterFinish: function(effect) {
            /*
            // Stop the effects if the current frame is not the one with the specified index
            if (index != currentIndex) {
                return;
            }
            */

            // Update the contents according to the resource type
            if (type == 'image') {

                // For an image, the class depends on the orientation
                $('detail').className = 'image_detail_' + orientation;

                // Mask every resource container
                $$('#frame_contents div').each(function(element) {element.hide();});
                // Then redisplay only the appropriate one
                $('resource_contents' + resourceId).show();

                // Redisplay the frame
                new Effect.Morph('detail', {
                    queue: {scope: 'detail'},
                    style: 'background-color: #000000;',
                    duration: 1.0
                });
                new Effect.Morph('frame', {
                    queue: {scope: 'detail'},
                    style: 'background-color: #ffffff;',
                    duration: fadeInDuration
                });
            } else {

                // For a text, the class name is fixed
                $('detail').className = 'text_detail';

                // Mask every resource container
                $$('#frame_contents div').each(function(element) {element.hide();});
                // Then redisplay only the appropriate one
                $('resource_contents' + resourceId).show();

                // Redisplay the frame
                new Effect.Morph('detail', {
                    queue: {scope: 'detail'},
                    style: 'background-color: #ffffff;',
                    duration: fadeInDuration
                });
                new Effect.Morph('frame', {
                    queue: {scope: 'detail'},
                    style: 'background-color: #ffffff;',
                    duration: fadeInDuration
                });
            }

            // Redisplay the contents zone
            new Effect.Appear('frame_contents');
        }
    });

}

// Display the next frame - this method is automatically called, not triggered by the user, therefore its instructions are executed only if the slideshow is running
var displayNextFrame = function() {
    if (slideshowIsRunning) {
        var linkNext = $$('#link_next a');
        var nextIndex = $('next_index').innerHTML;
        if (linkNext[0]) { // Display the next frame
            toFrame(nextIndex);
        } else { // Unless it is already the final frame, in which case return to the first one
            toFrame(1);
        }
        // Clear the potentially pending action and reschedule the next call
        // Without this process, toggling several times in succession the slideshow would cause several slideshow timelines to coexist and therefore several pictures being scrolled at the same time
        window.clearTimeout(currentPendingAction);
        currentPendingAction = displayNextFrame.delay($('display_period').innerHTML);
    }
}

// Start the slideshow
var startSlideshow = function() {
    stopZoom(); // Stop the zoom action if necessary
    if (!slideshowIsRunning) {
        slideshowIsRunning = true;
        displayNextFrame();
        // Update the slideshow link to show the stop message
        $('detail_slideshow').update('<div><div id="slider" style="float: left; width: 40px; height: 15px; margin-left: 30px;"><div id="slider_track" style="background: url(' + configStaticImagesPath + 'slider.gif) no-repeat; width:40px; height:15px;"><div id="slider_handler" style="background: url(' + configStaticImagesPath + 'handle.gif) no-repeat; width:6px; height:15px; cursor: ew-resize;"></div></div></div><div style="float: left; margin-left: 10px;"><a href="#" onClick="javascript:stopSlideshow()">' + $('slideshow_stop_label').innerHTML + '</a></div></div>');
        //$('detail_slideshow').update('<div><div style="margin-left: 30px; margin-right: 30px;"><div style="float: left; width: 40px; height: 15px; text-align: right;"><div id="slider_track" style="background: url(slider.gif) no-repeat; width:40px; height:15px;"><div id="slider_handler" style="background: url(handle.gif) no-repeat; width:6px; height:15px; cursor: ew-resize;"></div></div></div><div style="float: left; margin-left: 10px; width: 25px; text-align: left;"><a href="#" onClick="javascript:stopSlideshow()">' + $('slideshow_stop_label').innerHTML + '</a></div></div></div>');
        new Control.Slider('slider_handler', 'slider_track', {
            range: $R(7, 3),
            values: [7, 6, 5, 4, 3],
            sliderValue: $('display_period').innerHTML, // Reuse the last value set by the user
            onSlide: function(value) {$('display_period').innerHTML = value;},
            onChange: function(value) {$('display_period').innerHTML = value;}
        });
    }
};

// Stop the slideshow
var stopSlideshow = function() {
    if (slideshowIsRunning) {
        slideshowIsRunning = false;
        // Update the slideshow link to show the slider and stop message
        $('detail_slideshow').update('<a href="#" onClick="javascript:startSlideshow()">' + $('slideshow_start_label').innerHTML + '</a>');
    }
}

//Initial DOM manipulation
document.observe('dom:loaded', function() {

    // Initialize the previous and next links if they exist
    var linkPrevious = $$('#link_previous a');
    var previousIndex = $('previous_index').innerHTML;
    if (linkPrevious[0]) {
        linkPrevious[0].href = '#';
        linkPrevious[0].observe('click', function() {javascript:stopZoom(); javascript:stopSlideshow(); toFrame(previousIndex);});
    }
    var linkNext = $$('#link_next a');
    var nextIndex = $('next_index').innerHTML;
    if (linkNext[0]) {
        linkNext[0].href='#';
        linkNext[0].observe('click', function() {javascript:stopZoom(); javascript:stopSlideshow(); toFrame(nextIndex);});
    }

    // Preload the adjacent frames
    loadAdjacentFrames($('current_frame_number').innerHTML, nbAdjacentFrames);

    // Initialize the slideshow link
    $('detail_slideshow').update('<a href="#" onClick="javascript:startSlideshow()">' + $('slideshow_start_label').innerHTML + '</a>');

});
