/**
 * eXoZoom
 *
 * par  Alexandre D'Eschambeault et
 *      Olivier Cléroux
 *
 * pour eXolnet SENC <http://www.exolnet.com>
 *
 * le   10 septembre 2009
 **/


var Exozoom = new Class({
	Implements: [Events, Options],
	options:  {
		overlayOpacity: 0.7,
		
		animate: true,
		resizeDuration: 500,
		overlayDuration: 500,
		
		borderSize: 10,
		
		labelImage: "Image",
		labelOf: "of"
	},

    /**
     * Constructeur de Exozoom. Se charge d'initialiser les options, les 
     * Ã©vÃ¨nements ainsi que les diffÃ©rents composants qui seront utilÃ©s
     * par la librarie
     * @param options  Options pour initialiser la librarie
     **/
	initialize: function(options) {
	   this.setOptions(options);
	   
	   this.updateImageList();
	   
	   this.keyboardAction = this.keyboardAction.bindWithEvent(this);
	   
	   if (this.options.resizeSpeed < 1)  {
	       this.options.resizeSpeed = 1;
	   }
	   
	   if (this.options.overlayDuration < 1)  {
	       this.options.overlayDuration = 1;
	   }
	   
	   
        // Here is the HTML code that represent the Exozoom. It will be
        // injected at the end of the document's body.
        //
        //  <div id="overlay"></div>
        //  <div id="exozoom">
        //      <div id="outerImageContainer">
        //          <div id="imageContainer">
        //              <img id="lightboxImage">
        //              <div style="" id="hoverNav">
        //                  <a href="#" id="prevLink"></a>
        //                  <a href="#" id="nextLink"></a>
        //              </div>
        //              <div id="loading">
        //                  <a href="#" id="loadingLink">
        //                      <img src="images/loading.gif">
        //                  </a>
        //              </div>
        //          </div>
        //      </div>
        //      <div id="imageDataContainer">
        //          <div id="imageData">
        //              <div id="imageDetails">
        //                  <span id="caption"></span>
        //                  <span id="numberDisplay"></span>
        //              </div>
        //              <div id="bottomNav">
        //                  <a href="#" id="bottomNavClose">
        //                      <img src="images/close.gif">
        //                  </a>
        //              </div>
        //          </div>
        //      </div>
        //  </div>
        
        new Element('div', {'id': 'overlay'})
            .adopt([
                new Element('div', {'id': 'loading'}).adopt([
                    new Element('a', {
                        'id': 'loadingLink',
                        'href': '#',
                        'text': 'loading...'
                    })
                ])
            ])
            .inject(document.body);
        
        this.exozoom = new Element('div', {'id': 'exozoom'}).adopt([
            new Element('div', {
                'id': 'outerImageContainer'
            }).adopt([
                new Element('div', {'id': 'imageContainer'}).adopt([
                    new Element('img', {
                        'id': 'exozoomImage'
                    }),
                    new Element('div', {
                        'id': 'hoverNav'
                    }).adopt([
                        new Element('a', {
                            'id': 'prevLink',
                            'href': '#'
                        }),
                        new Element('a', {
                            'id': 'nextLink',
                            'href': '#'
                        })
                    ])
                ])
            ]),
            
            new Element('div', {
                'id': 'imageDataContainer'
            }).adopt([
                new Element('div', {'id': 'imageData'}).adopt([
                    new Element('div', {'id': 'imageDetails'}).adopt([
                        new Element('span', {'id': 'caption'}),
                        new Element('div', {
                            'id': 'numberDisplay'
                        })
                    ]),
                    new Element('div', {'id': 'bottomNav'}).adopt([
                        new Element('a', {
                            'id': 'bottomNavClose',
                            'href': '#',
                            'text': "Close"
                        })
                    ])
                ])
            ])
        ])
        .inject(document.body);
        
        $('overlay').setStyle('display', 'none')
                    .addEvent('click', (function() { this.end(); }).bind(this));
                    
        $('exozoom').setStyle('display', 'none')
                    .addEvent('click', (function(event) {
                        if (event.target.get('id') == 'exozoom') {
                            this.end(); 
                        }
                    }).bind(this));
                    
        $('prevLink').addEvent('click', (function(event) {
            event.stop();
            this.changeImage(this.activeImage - 1);
        }).bindWithEvent(this));
        
        $('nextLink').addEvent('click', (function(event) {
            event.stop();
            this.changeImage(this.activeImage + 1);
        }).bindWithEvent(this));
        
        $('loadingLink').addEvent('click', (function(event) {
            event.stop();
            this.end();
        }).bind(this));
        
        $('bottomNavClose').addEvent('click', (function(event) {
            event.stop();
            this.end();
        }).bind(this));
        
        
        var ids = 'overlay exozoom outerImageContainer imageContainer '+     
                  'exozoomImage hoverNav prevLink nextLink loading '+ 
                  'loadingLink imageDataContainer imageData imageDetails '+ 
                  'caption numberDisplay bottomNav bottomNavClose';  

        ids.split(' ').each((function(id) {
            this[id] = $(id);
        }).bind(this));
	},
	
	updateImageList: function() {
        this.updateImageList = $empty;

        document.addEvent('click', (function(event) {
            var elems = new Elements(
                $A([$(event.target)]).extend($(event.target).getParents())
            );
        
            var target = elems.filter('a[rel^=exozoom]')
                .extend(elems.filter('area[rel^=exozoom]'));

            if (target.length > 0) {
                event.stop();

                this.start(target[0]);
            }
        }).bind(this));
	},
	
	start: function(imageLink) {
	    $$('select', 'object', 'embed').each(function(node) {
	        node.setStyle('visibility', 'hidden');
	    });

		this.loading.setStyle('display', 'none');

        this.overlay.setStyles({
            'display': 'block',
            'opacity': 0
        });
        
        var compatibleOverlay = Browser.Engine.trident4;
        if (compatibleOverlay) {
        	this.overlay.setStyles({
        		'position': 'absolute',
        		'opacity': 1,
				'width': document.body.offsetWidth,
            	'height': document.body.offsetHeight
        	});
        }
	   
        new Fx.Morph(this.overlay, {
                'duration': this.options.overlayDuration
        }).start({
            'opacity': this.options.overlayOpacity
        });

        this.imageArray = [];
        var imageNum = 0;
        
        if ((imageLink.rel == 'exozoom')) {
            this.imageArray.push([imageLink.href, imageLink.title]); 
        } else {
            // if image is part of a set..
            $$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]')
                .each((function(anchor) {
                    this.imageArray.push([anchor.href, anchor.title]);
                }).bind(this));
            
            while (this.imageArray[imageNum][0] != imageLink.href) {
                imageNum++;
            }
        }

        this.changeImage(imageNum);
	},
	
	changeImage: function(imageNum) {
        this.activeImage = imageNum;

        if (this.options.animate) {
        	this.loading.setStyle('display', 'block');
        	
        	if (this.overlay.getStyle('position') == 'absolute') {
				this.loading.setStyles({
					'top': document.getScroll().y + document.getSize().y/2,
					'left': document.getScroll().x + document.getSize().x/2
				});
        	}
        }
        

        this.exozoomImage.setStyle('display', 'none');
        this.hoverNav.setStyle('display', 'none');
        this.prevLink.setStyle('display', 'none');
        this.nextLink.setStyle('display', 'none');
        
        this.imageDataContainer.setStyle('opacity', 0);
        this.numberDisplay.setStyle('display', 'none');

        var imgPreloader = new Image();
        
        imgPreloader.onload = (function() {
            this.exozoomImage.set('src', this.imageArray[this.activeImage][0]);
            this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
        }).bind(this);

        imgPreloader.src = this.imageArray[this.activeImage][0];
	},
	
	resizeImageContainer: function(imgWidth, imgHeight) {
        this.exozoom.setStyles({
            'display': 'block',
            'opacity': 0,
            'top': document.getScroll().y +
                   (document.getSize().y - imgHeight) / 2,
            'left': document.getScroll().x +
                    (document.getSize().x - imgWidth) /2,
            'width': imgWidth,
            'height': imgHeight
        });
        
        
        new Fx.Morph(this.exozoom, {
                'duration': this.options.resizeDuration,
                'onComplete': (function() {
                    //this.prevLink.setStyle('height', imgHeight);
                    //this.nextLink.setStyle('height', imgHeight);
                    //this.imageDataContainer.setStyle('width', widthNew);
        
                    this.showImage();
                }).bind(this)
        }).start({
            'opacity': 1
        });
	},
	
	showImage: function() {
        this.loading.setStyle('display', 'none');

        this.exozoomImage.setStyles({
            'display': 'inline',
            'opacity': 0
        });
        
        new Fx.Morph(this.exozoomImage, {
                'duration': this.options.resizeDuration,
                'onComplete': (function() {
                    this.updateDetails();
                }).bind(this)
        }).start({
            'opacity': 1
        });

        this.preloadNeighborImages();
	},
	
	updateDetails: function() {
        // if caption is not null and image is part of set display 'Image x of x'
        if (this.imageArray[this.activeImage][1] != "" && this.imageArray.length > 1) {
            this.caption.set('html', this.imageArray[this.activeImage][1])
                .setStyle('display', 'block');
            this.numberDisplay
                .set('text', '(' + this.options.labelImage + ' ' + 
                    (this.activeImage + 1) + ' ' + this.options.labelOf + '  ' + 
                    this.imageArray.length + ')')
                .setStyle('display', 'block');
        }
        
        else {
        	this.caption.set('html', this.imageArray[this.activeImage][1]);
			this.numberDisplay
				.set('text', '(' + this.options.labelImage + ' ' + 
					(this.activeImage + 1) + ' ' + this.options.labelOf + '  ' + 
					this.imageArray.length + ')');
        }
        
        this.imageDataContainer.setStyles({
            'display': 'block',
            'opacity': 0
        });
        
        new Fx.Morph(this.exozoom, {
                'duration': this.options.resizeDuration,
                'onComplete': (function() {
                    new Fx.Morph(this.imageDataContainer, {
                            'duration': this.options.resizeDuration,
                            'onComplete': (function() {
                                // update overlay size and update nav
                                //this.overlay.setStyle('height', 
                                //    document.getSize().y);
                                this.updateNav();
                            }).bind(this)
                    }).start({
                        'opacity': 1
                    });
                }).bind(this)
        }).start({
            'height': (this.exozoom.getStyle('height').toInt() + 
                      this.imageDataContainer.getSize().y)
        });
	},
	
	updateNav: function() {
        this.hoverNav.setStyle('display', 'block');

        // if not first image in set, display prev image button
        if (this.activeImage > 0) {
            this.prevLink.setStyle('display', 'block');
        }

        // if not last image in set, display next image button
        if (this.activeImage < (this.imageArray.length - 1)) {
            this.nextLink.setStyle('display', 'block');
        }
        
        this.enableKeyboardNav();
	},
	
	/**
	 * Enable the keydown listening
	 **/
	enableKeyboardNav: function() {
	   document.addEvent('keydown', this.keyboardAction); 
	},
	
	/**
	 * Disable the keydown listening
	 **/
	disableKeyboardNav: function() {
	   document.removeEvent('keydown', this.keyboardAction); 
	},
	
	keyboardAction: function(event) {
        // do nothing
	},
	
	preloadNeighborImages: function(){
        var preloadNextImage, preloadPrevImage;
        if (this.imageArray.length > this.activeImage + 1){
            preloadNextImage = new Image();
            preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
        }
        if (this.activeImage > 0){
            preloadPrevImage = new Image();
            preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
        }
	},
	
	end: function() {
        this.disableKeyboardNav();
        this.exozoom.setStyle('display', 'none');

        new Fx.Morph(this.overlay, {
                'duration': this.options.overlayDuration
        }).start({
            'opacity': 0
        });

        $$('select', 'object', 'embed').each(function(node){
            node.setStyle('visibility', 'visible');
        });
	},
	
	// Une fonction de MooTools existe dÃ©jÃ  pour faire Ã§a
	//getPageSize: function() {}
	
	// Variables
	imageArray: [],
	activeImage: undefined
});

var exozoom = undefined;
document.addEvent('domready', function() { exozoom = new Exozoom(); });
