//
// File:       utilities.js
//
// Abstract:   Sample utilities for JavaScript
//
// Version:    1.1
//
// Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Inc. ("Apple")
//             in consideration of your agreement to the following terms, and your use,
//             installation, modification or redistribution of this Apple software
//             constitutes acceptance of these terms.  If you do not agree with these
//             terms, please do not use, install, modify or redistribute this Apple
//             software.
//
//             In consideration of your agreement to abide by the following terms, and
//             subject to these terms, Apple grants you a personal, non - exclusive
//             license, under Apple's copyrights in this original Apple software ( the
//             "Apple Software" ), to use, reproduce, modify and redistribute the Apple
//             Software, with or without modifications, in source and / or binary forms;
//             provided that if you redistribute the Apple Software in its entirety and
//             without modifications, you must retain this notice and the following text
//             and disclaimers in all such redistributions of the Apple Software. Neither
//             the name, trademarks, service marks or logos of Apple Inc. may be used to
//             endorse or promote products derived from the Apple Software without specific
//             prior written permission from Apple.  Except as expressly stated in this
//             notice, no other rights or licenses, express or implied, are granted by
//             Apple herein, including but not limited to any patent rights that may be
//             infringed by your derivative works or by other works in which the Apple
//             Software may be incorporated.
//
//             The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
//             WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
//             WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
//             PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
//             ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
//
//             IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
//             CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//             SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//             INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
//             AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
//             UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
//             OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright ( C ) 2010 Apple Inc. All Rights Reserved.
//

Function.prototype.bind = function(thisObject)
{
    var func = this;
    var args = Array.prototype.slice.call(arguments, 1);
    return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))) };
}

/* ==================== Element Extensions ==================== */

Element.prototype.removeAllChildren = function ()
{
  while (this.firstChild) {
    this.removeChild(this.firstChild);
  }
};

/**
 *  Indicates whether the element has a given class name within its class attribute.
 */
Element.prototype.hasClassName = function (className) {
  return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(this.className);
};

/**
 *  Adds the given class name to the element's class attribute if it's not already there.
 */
Element.prototype.addClassName = function (className) {
  if (!this.hasClassName(className)) {
    this.className = [this.className, className].join(' ').replace(/^\s*|\s*$/g, "");
  }
};

/**
 *  Removes the given class name from the element's class attribute if it's there.
 */
Element.prototype.removeClassName = function (className) {
  if (this.hasClassName(className)) {
    var curClasses = this.className;
    this.className = curClasses.replace(new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g'), ' ').replace(/^\s*|\s*$/g, "");
  }
};

function Lightbox()
{
    this.isiPad = (navigator.userAgent.indexOf('iPad') != -1);
    this.lightboxContainers = document.querySelectorAll('.image-lightbox');
    this.setupEventHandlers();
}

// Add event handlers for all the image-container elements on the page
Lightbox.prototype.setupEventHandlers = function()
{
    for (var i = 0; i < this.lightboxContainers.length; ++i) {
        var curContainer = this.lightboxContainers[i];
        if (this.isiPad)
              curContainer.addEventListener('touchend', this.containerClicked.bind(this, curContainer), false);
        else
              curContainer.addEventListener('click', this.containerClicked.bind(this, curContainer), false);
    }
}

Lightbox.prototype.containerClicked = function(container)
{
    switch (event.type) {
        case 'click':
            this.slowMode = event.shiftKey;
            this.enterLightbox(container);
            break;
            
        case 'touchend':
            this.slowMode = container == this.lightboxContainers[0];
            this.enterLightbox(container);
            break;
    }
}

// Enter the lightbox
Lightbox.prototype.enterLightbox = function(container)
{
    this.makeOverlay();
    this.adaptOverlay(container);
    this.showOverlay();
}

// Create the overlay and the elements in it
Lightbox.prototype.makeOverlay = function()
{
    if (this.overlay)
        return;

    // The overlay itself
    this.overlay = document.createElement('div');
    this.overlay.id = 'lightbox-overlay';
    this.overlay.style.height = document.height + 'px';
    this.overlay.addEventListener('webkitTransitionEnd', this, false);

    // The box to host the content
    this.overlayBox = document.createElement('div');
    this.overlayBox.id = 'overlay-box';
    this.overlay.appendChild(this.overlayBox);

    // The loading indicator
    this.loadIndicator = document.createElement('div');
    this.loadIndicator.className = 'load-indicator';
    this.overlayBox.appendChild(this.loadIndicator);

    // The container for the content to be displayed
    this.overlayContents = document.createElement('div');
    this.overlayContents.className = 'overlay-contents';
    this.overlayBox.appendChild(this.overlayContents);

    // The button to close the lightbox
    this.overlay.closeButton = document.createElement('div');
    this.overlay.closeButton.id = 'close-button';
    this.overlayBox.appendChild(this.overlay.closeButton);

    // Add the event handler for the close button
    var self = this;
    this.overlay.closeButton.addEventListener('click', function() {
        self.hideOverlay();
    }, false);
}

// Start the image loading and show the loading indicator
Lightbox.prototype.adaptOverlay = function(container)
{
    this.overlayContents.removeAllChildren()

    if (this.slowMode)
        this.overlay.addClassName('slow-mode');
    else
        this.overlay.removeClassName('slow-mode');
    
    // Grab the image
    var originalImage = container.querySelectorAll('img')[0];
    var highResImageURL = originalImage.getAttribute('class');
    if (!highResImageURL)
        highResImageURL = originalImage.src;

    // Create the image element and add the event handlers
    this.overlayImage = new Image();
    this.overlayImage.addEventListener('load', this, false);
    this.overlayImage.addEventListener('error', this, false);

    this.imageLoaded = false;
    
    var self = this;
    window.setTimeout(function() {
                      self.overlayImage.src = highResImageURL;
                      }, this.slowMode ? 3000 : 1500);
                      
 /*
    // Copy the caption
    var originalCaption = container.querySelectorAll('.caption')[0];
    this.overlayContents.overlayCaption = originalCaption.cloneNode(true);  // Deep clone.
	*/
}

// Show the overlay
Lightbox.prototype.showOverlay = function()
{
    document.body.appendChild(this.overlay);
    this.overlayBox.style.marginTop = document.body.scrollTop + 250 + 'px';
    this.overlay.transitionInProgress = true;
    this.overlayBox.addClassName('loading');

    // Start the transition
    var self = this;
    window.setTimeout(function() {
                      self.overlay.addClassName('visible');
                      }, 200);
}

// Handle the transition to show the image
Lightbox.prototype.fitToImage = function()
{
    if (this.overlayBox.hasClassName('final'))
        return;
    
    this.overlayBox.removeClassName('loading');
    this.overlayContents.appendChild(this.overlayImage);
    //this.overlayContents.appendChild(this.overlayContents.overlayCaption);
    this.overlayBox.style.marginTop = document.body.scrollTop + 50 + 'px';
    this.overlay.closeButton.addClassName('visible');

    var self = this;
    window.setTimeout(function() {
                      self.overlayBox.addClassName('final');
                      }, 0);
}

// Hide the overlay
Lightbox.prototype.hideOverlay = function()
{
    this.overlay.className = '';
    this.overlayBox.removeClassName('initial');
    this.overlayBox.removeClassName('final');
    this.overlay.closeButton.removeClassName('visible');
}

// Remove the overlay from the document
Lightbox.prototype.removeOverlay = function()
{
    document.body.removeChild(this.overlay);
}

// Handle the overlay transitions
Lightbox.prototype.transitionDone = function()
{
    if (this.overlay.hasClassName('visible')) {
        // Start the transitions to shrink the loading indicator
        var self = this;
        window.setTimeout(function() {
                      self.overlayBox.addClassName('initial');
                      }, 0);
    } else
        this.removeOverlay();
}

// Event handler for the lightbox class
Lightbox.prototype.handleEvent = function(event)
{
    switch (event.type)
    {
    case 'webkitTransitionEnd':
        if (event.target == this.overlayBox) {
            // Handle transitions on the overlay box
            this.fitToImage();
            break;
        }
            
        if (event.target == this.overlay) {
            // The overlay trasition has completed
            this.overlay.transitionInProgress = false;
            if (this.imageLoaded)
                this.transitionDone();
        }
        break;
    
    case 'error':
        // Something went wrong when trying to load the image. Remove the overlay.
        this.removeOverlay();
        break;

    case 'load':
        this.imageLoaded = true;
        if (!this.transitionInProgress)
            this.transitionDone();
        break;            
  }
}

// Resize the overlay when the window size changes
Lightbox.prototype.repositionLightbox = function()
{
    if (this.overlay)
        this.overlay.style.height = document.height + 'px';
}

var gLightbox;
function positionLightbox()
{
    gLightbox.repositionLightbox();
}
function setupLightbox()
{
    gLightbox = new Lightbox();
}

window.addEventListener('load', setupLightbox, false);
