/**
* LightBox V3
*
* This script will create an lightbox for each link who contain the rel attribute set to a
* specific function present in this script
*
* @author		David Zeller 
*/

LightboxOptions = Object.extend({
	fileLightboxPath: "/js/lightbox",
	
	borderSize: 10,
	labelImage: "Image",
	labelOf: "sur"
}, window.LightboxOptions || {});

var Lightbox = Class.create({
	version: '3.0',
	imageArray: [],
	activeImage: 0,
	objLink: 0,
	
	/**
	* Class constructor (first element executed on lightbox call)
	*
	* @param		void
	*/
	initialize: function(){
		
		this.updateLinks();
		
		this.keyboardAction = this.keyboardAction.bindAsEventListener(this);
		
		var objBody = $$('body')[0];

		objBody.appendChild(Builder.node('div',{id:'overlay'}));

        objBody.appendChild(Builder.node('div',{id:'lightbox'}, [
            Builder.node('div',{id:'lbOuterContainer'}, 
                Builder.node('div',{id:'lbContainer'}, [
                    Builder.node('div',{id:'lbContent'}), 
                    Builder.node('div',{id:'lbHoverNav'}, [
                        Builder.node('a',{id:'lbPrevLink', href: '#' }),
                        Builder.node('a',{id:'lbNextLink', href: '#' })
                    ]),
                    Builder.node('div',{id:'lbLoading'}, 
                        Builder.node('img', {src: LightboxOptions.fileLightboxPath + "/loading.gif"})
                    )
                ])
            ),
            Builder.node('div', {id:'lbDataContainer'},
                Builder.node('div',{id:'lbData'}, [
                    Builder.node('div',{id:'lbDetails'}, [
                        Builder.node('span',{id:'lbCaption'}),
                        Builder.node('span',{id:'lbNumberDisplay'})
                    ]),
                    Builder.node('div',{id:'lbBottomNav'},
						Builder.node('img', {id:'lbBottomNavClose', src: LightboxOptions.fileLightboxPath + "/closelabel.gif"})
                    )
                ])
            )
        ]));
		
		$('overlay').hide();
		$('lightbox').hide();
		$('lbOuterContainer').setStyle({ width: "250px", height: "250px" });
		$('lbPrevLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this));
		$('lbNextLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this));
		$('lbBottomNavClose').observe('click', (function(event) { event.stop(); this.close(); }).bind(this));
		
		var th = this;
        (function(){
            var ids = 
                'overlay lightbox lbOuterContainer lbContainer lbContent lbHoverNav lbPrevLink lbNextLink lbLoading ' + 
                'lbDataContainer lbData lbDetails lbCaption lbNumberDisplay lbBottomNav lbBottomNavClose';   
            $w(ids).each(function(id){ th[id] = $(id); });
        }).defer();
	},
	
	/**
	* Update the link to load the lightbox on click
	*
	* @param		void
	*/
	updateLinks: function() {   
        this.updateLinks = Prototype.emptyFunction;

        document.observe('click', (function(event){
            var target = event.findElement('a[rel^=image]') || event.findElement('a[rel^=youtube]') || event.findElement('a[rel^=inline]') || event.findElement('a[rel^=external]') || event.findElement('button[rel^=inline]');
            if (target) {
                event.stop();
                this.open(target);
            }
        }).bind(this));
    },
	
	/**
	* Show the lightbox
	*
	* @param		object	objLink		The link element
	*/
	open: function(objLink){
		
		$$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });
		
		// stretch overlay to fill page and fade in
        var arrayPageSize = this.getPageSize();
        $('overlay').setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });
		
		new Effect.Appear(this.overlay, { duration: 0.2 });
		
		var relParameter = objLink.readAttribute('rel').split("[");
		
		this.imageArray = [];
		
		this.objLink = objLink;
		
		switch(relParameter[0])
		{
			case "image":
				this.image(objLink);
			break;
			
			case "youtube":
				this.youtube(objLink);
			break;
			
			case "inline":
				this.inline(objLink);
			break;
			
			case "external":
				this.external(objLink);
			break;
		}
	},
	
	/**
	* Load an image or an image gallery
	*
	* @param		object	objLink		The link element
	*/
	image: function(objLink){      
		
		var imageNum = 0; 
		 
        if ((objLink.readAttribute('rel') == 'image')){
            // if image is NOT part of a set, add single image to imageArray
            this.imageArray.push([objLink.href, objLink.title]);         
        } else {
            // if image is part of a set..
            this.imageArray = 
                $$(objLink.tagName + '[href][rel="' + objLink.readAttribute('rel') + '"]').
                collect(function(anchor){ return [anchor.href, anchor.title]; }).
                uniq();
            
            while (this.imageArray[imageNum][0] != objLink.href) { imageNum++; }
        }
		
		this.placeLightbox();
        this.changeImage(imageNum);
	},
	
	/**
	* Load an image or an image gallery
	*
	* @param		object	objLink		The link element
	*/
	youtube: function(objLink){
		
		this.placeLightbox();
		this.hideElements();
		
		var size = this.getSize(objLink.readAttribute('rel'));
		
		var lb_youtube_link = objLink.href.replace("http://www.youtube.com/watch?v=", "")
		this.lbContent.innerHTML = '<object width="' + size[0] + '" height="' + size[1] + '"><param name="movie" value="http://www.youtube.com/v/' + lb_youtube_link + '&hl=fr&rel=0"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/' + lb_youtube_link + '&hl=fr&rel=0" type="application/x-shockwave-flash" wmode="transparent" width="' + size[0] + '" height="' + size[1] + '"></embed></object>';
		
		this.resizeContainer(size[0], size[1]);
	},
	
	/**
	* Load an inline content in the lightbox
	*
	* @param		object	objLink		The link element
	*/
	inline: function(objLink){
		
		this.placeLightbox();
		this.hideElements();
		
		var size = this.getSize(objLink.readAttribute('rel'));
		
		this.lbContent.setStyle({ overflow: "auto", height: size[1] + "px" });
		
		new Ajax.Request( objLink.href ,{ 
						 
			method: 'get',
			onComplete: (function(transport) {
				
				var content = transport.responseText;
				this.lbContent.update(content);
				
			}).bind(this)
		});

		this.resizeContainer(size[0], size[1]);
	},
	
	/**
	* Load an external link in the lightbox
	*
	* @param		object	objLink		The link element
	*/
	external: function(objLink){
		
		this.placeLightbox();
		this.hideElements();
		
		var size = this.getSize(objLink.readAttribute('rel'));
		
		var lw_iframe = document.createElement("iframe");
		lw_iframe.setAttribute('id','lbIframe');
		lw_iframe.style.border = 0;
		
		this.lbContent.setStyle({ height: size[1] + "px" });
		
		// FOR IE
		lw_iframe.onreadystatechange = (function(){
			
			if (lw_iframe.readyState == "interactive"){
				
				this.resizeContainer(size[0], size[1]);
			}
		}).bind(this);
			
		// FOR FF
		lw_iframe.onload = (function(){
			
			this.resizeContainer(size[0], size[1]);
		}).bind(this);
		
		lw_iframe.src = objLink.href;
		
		lw_iframe.style.width = size[0] + "px";
		lw_iframe.style.height = size[1] + "px";
		
		this.lbContent.appendChild(lw_iframe);
	},
	
	/**
	* Load an image or an image gallery
	*
	* @param		integer	imageNum		The image number
	*/
    changeImage: function(imageNum) {   
        
		if (imageNum < 0){
			
			imageNum = this.imageArray.length - 1;
		}
		
		if (imageNum > this.imageArray.length - 1){
			
			imageNum = 0;
		}
		
        this.activeImage = imageNum; // update global var

        this.hideElements();
		
		var lb_image = document.createElement("img");
		lb_image.setAttribute('id','lbImage');
		this.lbContent.appendChild(lb_image);

        var imgPreloader = new Image();
        
        // once image is preloaded, resize image container
        imgPreloader.onload = (function(){
            $('lbImage').src = this.imageArray[this.activeImage][0];
			this.resizeImage(imgPreloader, $('lbImage'));
        }).bind(this);
        
		imgPreloader.src = this.imageArray[this.activeImage][0];
    },
	
	/**
	* Load an image or an image gallery
	*
	* @param		object	objImage		The image element
	*/
	resizeImage: function(objImage){
		
		var width, height, viewportSize, windowWidth, windowHeight, diviser;
		
		width = objImage.width;
		height = objImage.height;
		
		viewportSize = this.getViewportSize();
		
		windowWidth = viewportSize[0];
		windowHeight = viewportSize[1];
		
		if (width > windowWidth){
			
			diviser = width / (windowWidth - (Math.round(windowWidth / 4)));
			
			width = width / diviser;
			height = height / diviser;
		}
		
		if ((height + 40) > windowHeight){
			
			diviser = height / (windowHeight - (Math.round(windowHeight / 4)));
			
			width = width / diviser;
			height = height / diviser;
		}
		
		$('lbImage').style.width = Math.round(width) + "px";
		$('lbImage').style.height = Math.round(height) + "px";

		this.resizeContainer(Math.round(width), Math.round(height));
	},
	
	/**
	* Resize the lightbox
	*
	* @param		object	objLink		The link element
	*/
	resizeContainer: function(width, height) {
		
		width = parseInt(width);
		height = parseInt(height);
		
        // get current width and height
        var widthCurrent  = this.lbOuterContainer.getWidth();
        var heightCurrent = this.lbOuterContainer.getHeight();

        // get new width and height
        var widthNew  = (width  + LightboxOptions.borderSize * 2);
        var heightNew = (height + LightboxOptions.borderSize * 2);

        // scalars based on change from old to new
        var xScale = (widthNew  / widthCurrent)  * 100;
        var yScale = (heightNew / heightCurrent) * 100;

        // calculate size difference between new and old image, and resize if necessary
        var wDiff = widthCurrent - widthNew;
        var hDiff = heightCurrent - heightNew;

        if (hDiff != 0) new Effect.Scale(this.lbOuterContainer, yScale, {scaleX: false, duration: 0.5, queue: 'front'}); 
        if (wDiff != 0) new Effect.Scale(this.lbOuterContainer, xScale, {scaleY: false, duration: 0.5, delay: 0.5}); 

        // if new and old image are same size and no scaling transition is necessary, 
        // do a quick pause to prevent image flicker.
        var timeout = 0;
        if ((hDiff == 0) && (wDiff == 0)){
            timeout = 100;
            if (Prototype.Browser.IE) timeout = 250;   
        }

        (function(){
            this.lbPrevLink.setStyle({ height: height + 'px' });
            this.lbNextLink.setStyle({ height: height + 'px' });
            this.lbDataContainer.setStyle({ width: widthNew + 'px' });

            this.showContent();
        }).bind(this).delay(timeout / 1000);
    },
	
	/**
	* Show the content
	*
	* @param		void
	*/
	showContent: function(){
		
		this.lbLoading.hide();
        new Effect.Appear(this.lbContent, { 
            duration: 0.2, 
            queue: 'end', 
            afterFinish: (function(){ this.updateDetails(); }).bind(this) 
        });
	},
	
	/**
	* Update the details
	*
	* @param		void
	*/
	updateDetails: function(){
		
		// if caption is not null
		if (this.imageArray[this.activeImage]){
	        
			if (this.imageArray[this.activeImage][1] != ""){
	            this.lbCaption.update(this.imageArray[this.activeImage][1]).show();
	        }
	        
	        // if image is part of set display 'Image x of x' 
	        if (this.imageArray.length > 1){
	            this.lbNumberDisplay.update( LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + '  ' + this.imageArray.length).show();
	        }
		} else {
			
			this.lbCaption.update(this.objLink.title).show();
		}

        new Effect.Parallel(
            [ 
                new Effect.SlideDown(this.lbDataContainer, { sync: true, duration: 0.2, from: 0.0, to: 1.0 }), 
                new Effect.Appear(this.lbDataContainer, { sync: true, duration: 0.2 }) 
            ], 
            { 
                duration: 0.2, 
                afterFinish: (function() {
	                // update overlay size and update nav
	                var arrayPageSize = this.getPageSize();
	                this.overlay.setStyle({ height: arrayPageSize[1] + 'px' });
	                this.updateNav();
                }).bind(this)
            } 
        );
	},
	
	/**
	* Update the details
	*
	* @param		void
	*/
	updateNav: function(){
		
		if (this.imageArray.length >= 1){
			
			this.lbHoverNav.show();
			this.lbPrevLink.show();
			this.lbNextLink.show();
			
			this.enableKeyboardNav();
		}
	},
	
	/**
	* Hide the lightbox
	*
	* @param		void
	*/
	close: function(){
		
		this.disableKeyboardNav();
		this.lbNumberDisplay.hide();
		this.lbCaption.hide();
		this.lightbox.hide();
        new Effect.Fade(this.overlay, { duration: 0.2 });
        $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });
		this.lbContent.setStyle({ height: "inherit", overflow: "none" });
	},
	
	/**
	* Get the size of the viewport
	*
	* @param		void
	*/
	getViewportSize: function(){
		
		var windowWidth, windowHeight;
		
		if (self.innerHeight) {	// all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	

		arrayPageSize = new Array(windowWidth,windowHeight) 
		return arrayPageSize;
	},
	
	/**
	* Get the page size
	*
	* @param		void
	*/
	getPageSize: function(){
	        
	    var xScroll, yScroll;
		
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = window.innerWidth + window.scrollMaxX;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}
		
		var windowWidth, windowHeight;
		
		if (self.innerHeight) {	// all except Explorer
			if(document.documentElement.clientWidth){
				windowWidth = document.documentElement.clientWidth; 
			} else {
				windowWidth = self.innerWidth;
			}
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	
		
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}
	
		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = xScroll;		
		} else {
			pageWidth = windowWidth;
		}

		return [pageWidth,pageHeight];
	},

	/**
	* Enable the keyboard events
	*
	* @param		void
	*/
	enableKeyboardNav: function(){
        
		document.observe('keydown', this.keyboardAction); 
    },

	/**
	* Disable the keyboard events
	*
	* @param		void
	*/
    disableKeyboardNav: function(){
        
		document.stopObserving('keydown', this.keyboardAction); 
    },

	/**
	* Keyboard action
	*
	* @param		event	event		The keyboad event
	*/
    keyboardAction: function(event) {
        var keycode = event.keyCode;

        var escapeKey;
        if (event.DOM_VK_ESCAPE) {  // mozilla
            escapeKey = event.DOM_VK_ESCAPE;
        } else { // ie
            escapeKey = 27;
        }

        var key = String.fromCharCode(keycode).toLowerCase();
        
        if (key.match(/x|o|c/) || (keycode == escapeKey)){ // close lightbox
            this.close();
        } else if ((key == 'p') || (keycode == 37)){ // display previous image
            this.disableKeyboardNav();
            this.changeImage(this.activeImage - 1);
        } else if ((key == 'n') || (keycode == 39)){ // display next image
            this.disableKeyboardNav();
            this.changeImage(this.activeImage + 1);
        }
    },
	
	/**
	* Clean the html in lbContent
	*
	* @param		void
	*/
	clean: function(){
		
		this.lbContent.innerHTML = '';
	},
	
	/**
	* Hide elements during transition 
	*
	* @param		void
	*/
	hideElements: function(){
		
        this.lbLoading.show();
        this.lbContent.hide();
        this.lbHoverNav.hide();
        this.lbPrevLink.hide();
        this.lbNextLink.hide();
		// HACK: Opera9 does not currently support scriptaculous opacity and appear fx
        this.lbDataContainer.setStyle({opacity: .0001});
        this.lbNumberDisplay.hide();      
        
		this.clean();
	},
	
	/**
	* Calculate top and left offset for the lightbox 
	*
	* @param		void
	*/
	placeLightbox: function(){
		
		// calculate top and left offset for the lightbox 
        var arrayPageScroll = document.viewport.getScrollOffsets();
        var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
        var lightboxLeft = arrayPageScroll[0];
        this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
	},
	
	/**
	* Hide elements during transition 
	*
	* @param		string	rel		The rel of the link
	*/
	getSize: function(rel){
		
		var pagesize = this.getViewportSize();
		var t = rel.split("[");
		var size = new Array();

		if (t[1]){
			
			var t1 = t[1].replace("]", "");
			size = t1.split(",");
		} else {
			
			switch(rel){
				
				case "youtube":
					size[0] = 425;
					size[1] = 355;
					break;
					
				case "external":
					size[0] = pagesize[0] - (Math.round(pagesize[0] / 4));
					size[1] = pagesize[1] - (Math.round(pagesize[1] / 4));
					break;
					
				default:
					size[0] = 640;
					size[1] = 480;
					break;
			}
		}
		
		return size;
	}
});

// Load the class on document load
document.observe('dom:loaded', function () { new Lightbox(); });