/**
 * IMove - Derivato da Lightbox
 * 
 * alfredo.cerutti@intercom.it
 * 
 * USAGE
 * 	
 * 
 *	document.observe('dom:loaded', function () { 
 * 		new IMove({
 *			width:500,
 *			height:400,
 *			step: 100		
 *		}); 	 
 *	});
 *
 * NOTE: only one <a rel='imove' .... > ACCEPTED!!!
 *  
 */


IMoveOptions = Object.extend({
    fileLoadingImage:        '/images/imove/loading.gif',	
	fileBottomNavCloseImage: '/images/imove/close.jpg',
	fileBottomZoomOutImage: '/images/imove/zoomout.jpg',
	fileBottomZoomInImage: '/images/imove/zoomin.jpg',
	fileBottomFitView :  '/images/imove/fitview.jpg',	
    overlayOpacity: 0.8, 
    animate: true, 
    borderSize: 10, 
	controlsStep : 40, // how many pixel to move image 
	zoomDuration: 0.4,
	moveDuration : 1.0,
	hideFitButton : false,
	allowMouseScroll: true
}, window.IMoveOptions || {});



var IMove = Class.create();

IMove.prototype = {
    
    initialize: function(conf) {    
        
        this.getImoveImage();
        
        this.keyboardAction = this.keyboardAction.bindAsEventListener(this);
	    this.overlayDuration = IMoveOptions.animate ? 0.2 : 0;
		this.controlsStep = IMoveOptions.controlsStep;
		this.zoomDuration = IMoveOptions.zoomDuration;
		this.moveDuration = IMoveOptions.moveDuration;
		this.hideFitButton = IMoveOptions.hideFitButton;
		this.allowMouseScroll = IMoveOptions.allowMouseScroll;
		
		/**
		 * configuration
		 */		
		if (conf) {
			this.max_width = conf.width || null;
			this.max_height = conf.height || null;
			this.controlsStep = conf.controlsStep || this.controlsStep;
			this.zoomDuration = conf.zoomDuration || this.zoomDuration;
			this.moveDuration = conf.moveDuration || this.moveDuration;						
			this.hideFitButton = conf.hideFitButton || this.hideFitButton;
			this.allowMouseScroll = conf.allowMouseScroll || this.allowMouseScroll; 				
			this.top = conf.top || null; // se settato evita l'autocentramento anche dell'asse y
			
			// installo controlli ed effetti
			this.control = conf.control || new IMoveControlBase(this);
			this.control._setParent(this); // referenzio in modo da avervi accesso
			this.openEffect = conf.openEffect || new IMoveOpenEffectBase(this);
			this.openEffect._setParent(this); // referenzio in modo da avervi accesso			
		}
		 
		var styleFitButton = (this.hideFitButton) ? 'display:none;' : '';
		
		/**
		 * nodes
		 */
        var objBody = $$('body')[0];
		objBody.appendChild(Builder.node('div',{id:'imove_overlay'}));	
        objBody.appendChild(Builder.node('div',{id:'imove'}, [
            Builder.node('div',{id:'imove_outerImageContainer'}, 
                Builder.node('div',{id:'imove_imageContainer'}, [
					Builder.node('div',{id:'imove_Image_div'}, 
						Builder.node('img',{id:'imove_image'})),  
                      
                    Builder.node('div',{id:'imove_hoverNav'}, [
						Builder.node('a',{id:'imove_nord', href: '#' }),
                        Builder.node('a',{id:'imove_est', href: '#' }),				
                        Builder.node('a',{id:'imove_ovest', href: '#' }),
                        Builder.node('a',{id:'imove_sud', href: '#' })
                    ]),
                    Builder.node('div',{id:'imove_loading'}, 
                        Builder.node('a',{id:'imove_loadingLink', href: '#' }, 
                            Builder.node('img', {src: IMoveOptions.fileLoadingImage})
                        )
                    )
                ])
            ),
            
			Builder.node('div', {id:'imove_imageDataContainer'},				
                Builder.node('div',{id:'imove_imageData'}, [
                    Builder.node('div',{id:'imove_imageDetails'}, [
                        Builder.node('span',{id:'imove_caption'}),
                        Builder.node('span',{id:'imove_numberDisplay'})
                    ]),					
                    Builder.node('div',{id:'imove_bottomNav'}, [
						Builder.node('a', { id: 'imove_bottomFitView', href: '#', style: styleFitButton  }, 
							Builder.node('img', { src: IMoveOptions.fileBottomFitView })
						),
						
                        Builder.node('a',{id:'imove_bottomNavClose', href: '#' },
                            Builder.node('img', { src: IMoveOptions.fileBottomNavCloseImage })
                        )
						]
                    )
					
                ])
            )
        ]));

		// append controls
		this.control._appendControls();
		this.control._addEvents();
		
		// effect on loading?
	    this.resizeDuration = IMoveOptions.animate ? ((11 - this.resizeSpeed) * 0.15) : 0;
		
		/**
		 * events
		 */
		$('imove_overlay').hide().observe('click', (function() { this.end(); }).bind(this));
		$('imove').hide().observe('click', (function(event) { if (event.element().id == 'imove') this.end(); }).bind(this));		

		$('imove_nord').observe('click', (function(event) { event.stop(); this.control.move('nord'); }).bindAsEventListener(this));
		$('imove_est').observe('click', (function(event) { event.stop(); this.control.move('est'); }).bindAsEventListener(this));		
		$('imove_ovest').observe('click', (function(event) { event.stop(); this.control.move('ovest'); }).bindAsEventListener(this));
		$('imove_sud').observe('click', (function(event) { event.stop(); this.control.move('sud'); }).bindAsEventListener(this));
		
		$('imove_loadingLink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
		$('imove_bottomNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
		$('imove_bottomFitView').observe('click', (function(event) { event.stop(); this.fitView(); }).bind(this));		
				
		// set starting box size
		$('imove_outerImageContainer').setStyle({ width: this.openEffect.startSize.width+'px', height: this.openEffect.startSize.height+'px' });
		
		/**
		 * reference
		 */
        var th = this;
        (function(){
            var ids = 
                'imove_overlay imove imove_outerImageContainer imove_imageContainer imove_image imove_Image_div imove_hoverNav imove_sud imove_est imove_nord imove_ovest imove_loading imove_loadingLink ' + 
                'imove_imageDataContainer imove_imageData imove_imageDetails imove_caption imove_bottomNav imove_bottomNavClose imove_bottomZoomIn imove_bottomZoomOut imove_bottomFitView';   
            $w(ids).each(function(id){ th[id] = $(id); });
        }).defer();
		
		/**
		 * observers
		 */
		if (this.allowMouseScroll) {	
			Event.observe('imove_image', 'DOMMouseScroll', (this.wheel).bind(this)); // mozilla					
			Event.observe('imove_image', 'mousewheel', (this.wheel).bind(this)); // IE/Opera
		}					
    },

    
    getImoveImage: function() {	
		this.getImoveImage = Prototype.emptyFunction;
			
        document.observe('click', (function(event){
			var target = event.findElement('a[rel=imove]'); 
	        if (target) {	
				event.stop();
				this.imove_image_reference = [target.href, target.title];
	            this.start();							
	        }
    	}).bind(this));
    },
    

    start: function() {    

        $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });

        // stretch overlay to fill page and fade in
        var arrayPageSize = this.getPageSize();
        this.imove_overlay.setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });

        // calculate top and left offset for the lightbox 
        var arrayPageScroll = document.viewport.getScrollOffsets();
		
		if (this.top) { // avoid full autocenter
			var ImoveTop = this.top;
		} else {
			var ImoveTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);	
		}        
        var ImoveLeft = arrayPageScroll[0];
        this.imove.setStyle({ top: ImoveTop + 'px', left: ImoveLeft + 'px' }).show();
        
		this.hideCursors(); // before loading hide cursors...
		this.control.reset(); // resetto eventuali controlli per la gestione dell'immagine		
        this.openImage();
    },

    openImage: function() {          
        // hide elements during transition
        if (IMoveOptions.animate) this.imove_loading.show();
        this.imove_image.hide();
        this.imove_hoverNav.hide();
        
		// HACK: Opera9 does not currently support scriptaculous opacity and appear fx
        this.imove_imageDataContainer.setStyle({opacity: .0001});             
        
        var imgPreloader = new Image();
        
        // once image is preloaded, apply effect to image container
        imgPreloader.onload = (function(){
			this.imove_image.setStyle({ width: '', height: '' }); //, top:'0px', left:'0px'}); // reset			
            this.imove_image.src = this.imove_image_reference[0];
			
			// check if thereis a special fitView from control plugin
			if (typeof this.control.fitView == 'undefined') {
				this.fitView();
			} else {
				this.control.fitView();
			}
			
			
            this.openEffect.run(imgPreloader.width, imgPreloader.height);
        }).bind(this);
        imgPreloader.src = this.imove_image_reference[0];
    },

	centerImage: function() {
		var dim = this.imove_image.getDimensions();
		
		if (dim.height > this.max_height) {
			var t =  -(Math.ceil( dim.height - this.max_height) / 2 );
		} else {
			var t = (this.max_height - dim.height) /2;
		}
		if (dim.width > this.max_width) {
			var l =  -(Math.ceil( dim.width - this.max_width) / 2 );
		} else {
			var l = 0;
		}
		this.imove_image.setStyle({top: t+'px', left: l+'px'});
	},
        
    showImage: function(){
        this.imove_loading.hide();
        new Effect.Appear(this.imove_image, { 
            duration: this.resizeDuration, 
            queue: 'end', 
            afterFinish: (function(){ if (this.openEffect.showDetails) this.updateDetails(); }).bind(this) 
        });
		
		if (!this.drag) {
			this.drag = new Draggable(this.imove_image); 
		}
    },

    updateDetails: function() {
    
        // if caption is not null
        if (this.imove_image_reference[1] != ""){
            this.imove_caption.update(this.imove_image_reference[1]).show();
        }
		
		// corret width
		w = this.imove_imageDataContainer.getWidth();
		w = w + IMoveOptions.borderSize * 2;
		this.imove_imageDataContainer.setStyle({width: w+'px'});
		
		var effects = new Array();
		
		if (this.openEffect.animateDetails) {
			effects.push(new Effect.SlideDown(this.imove_imageDataContainer, { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }));
		}
		effects.push(new Effect.Appear(this.imove_imageDataContainer, { sync: true, duration: this.resizeDuration }) );

        new Effect.Parallel(effects, 
            { 
                duration: this.resizeDuration, 
                afterFinish: (function() {
	                // update overlay size and update nav
	                var arrayPageSize = this.getPageSize();
	                this.imove_overlay.setStyle({ height: arrayPageSize[1] + 'px' });
					this.imove_hoverNav.show();
        			this.enableKeyboardNav();
                }).bind(this)
            } 
        );
    },

	fitView: function() {		
		if (this.max_height >= this.max_width) {
			this.imove_image.setStyle({width : this.max_width+'px', height: ''}); // height will follow :-)	
		} else {
			this.imove_image.setStyle({height : this.max_height+'px', width: ''}); // width will follow :-)			
		}
		this.centerImage();
		this.hideCursors();					
	},

	showCursors: function() {		
		this.imove_nord.show();
		this.imove_sud.show();
		this.imove_ovest.show();
		this.imove_est.show();	
	},
	
	hideCursors: function() {
		this.imove_nord.hide();
		this.imove_sud.hide();
		this.imove_ovest.hide();
		this.imove_est.hide();		
	},
	
	wheel: function (event){
		var delta = 0;
		if (!event) /* For IE. */
			event = window.event;
		if (event.wheelDelta) { /* IE/Opera. */
			delta = event.wheelDelta/120;
			/** In Opera 9, delta differs in sign as compared to IE. */
			if (window.opera)
				delta = -delta;
		} else if (event.detail) { /** Mozilla case. */
			/** In Mozilla, sign of delta is different than in IE.
			* Also, delta is multiple of 3.
			*/
			delta = -event.detail/3;
		}
	
		/** If delta is nonzero, handle it.
		* Basically, delta is now positive if wheel was scrolled up,
		* and negative, if wheel was scrolled down.
		*/
		if (delta) {
			this.control.wheelFn(delta);			
		}
				
		/** Prevent default actions caused by mouse wheel.
		* That might be ugly, but we handle scrolls somehow
		* anyway, so don't bother here..
		*/
		if (event.preventDefault)
			event.preventDefault();
		
		event.returnValue = false;
	},

    //
    //  enableKeyboardNav()
    //
    enableKeyboardNav: function() {
        document.observe('keydown', this.keyboardAction); 
    },

    //
    //  disableKeyboardNav()
    //
    disableKeyboardNav: function() {
        document.stopObserving('keydown', this.keyboardAction); 
    },

    //
    //  keyboardAction()
    //
    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 imove
            this.end();
        }
    },

    //
    //  end()
    //
    end: function() {
        this.disableKeyboardNav();
        this.imove.hide();
        new Effect.Fade(this.imove_overlay, { duration: this.overlayDuration });
        $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });
    },

    //
    //  getPageSize()
    //
    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];
	}
}


/*
 * Controllo base - nel caso non venga esplicitato altro verra' usato questo 
 */

var IMoveControlBase = Class.create();

IMoveControlBase.prototype = {

	initialize: function(){ },
	
	_setParent:function(parent) {	
		this.parent = parent;
	},
	
	_appendControls: function() {
			
        $('imove_bottomNav').insert({ top: 
			Builder.node('a', { id: 'imove_bottomZoomOut', href: '#'}, 
				Builder.node('img', { src: IMoveOptions.fileBottomZoomOutImage})
		)});
		 
		$('imove_bottomNav').insert({ top: 
			Builder.node('a', { id: 'imove_bottomZoomIn', href: '#'}, 
				Builder.node('img', { src: IMoveOptions.fileBottomZoomInImage})
		)});
		
	},
	
	_addEvents: function () {
		$('imove_bottomZoomIn').observe('click', (function(event) { event.stop(); this.zoom('in'); }).bind(this));
		$('imove_bottomZoomOut').observe('click', (function(event) { event.stop(); this.zoom('out'); }).bind(this));
	},
	
	move : function(direction) {
		var offset = this.parent.imove_image.positionedOffset(); //cumulativeOffset();
		
		if (direction == 'sud') {
			move = {
				x: 0,
				y: -this.parent.controlsStep
			};
			if (offset[1] <= 0) {				
				move.y  = -(this.parent.imove_image.getDimensions().height - this.parent.controlsStep + offset[1]);
			}
			
		}
		if (direction == 'nord') {
			move = {
				x: 0,
				y: this.parent.controlsStep
			};
			if ((offset[1] - this.parent.controlsStep) < 0) {
				move.y = -offset[1];
			}
		}
		if (direction == 'est') {
			move = {
				x: -this.parent.controlsStep,
				y: 0
			};
			if (offset[0] <= 0) {				
				move.x  = -(this.parent.imove_image.getDimensions().width - (this.parent.controlsStep*2) + offset[0]);
			}			
		}
		if (direction == 'ovest') {
			move = {
				x: this.parent.controlsStep,
				y: 0
			};
			if ((offset[0] - this.parent.controlsStep) < 0) {
				move.x = -offset[0];
			}
		}
		
		//console.log(this.parent.imove_image.positionedOffset(), this.parent.imove_image.viewportOffset())

		options = { queue: 'end', duration: this.parent.moveDuration, frequency: 3 };
		new Effect.Move(this.parent.imove_image, { x: move.x , y:move.y }, options);
	},
		
	zoom: function(direction) {
		if (direction == 'in') var z = 150;
		if (direction == 'out') var z = 50;
		
		new Effect.Scale(this.parent.imove_image, z, {
			queue: 'end',
			scaleFrom: 100.0,
			scaleFromCenter: true,
			duration: this.parent.zoomDuration,
			afterUpdate : (function() {
				this.parent.centerImage();
			}).bind(this)
		});		
	},	
	
	wheelFn: function(delta) {
		if (delta > 0) {
			this.zoom('in');
			this.showCursors();
		} else {
			this.zoom('out');
		}
	},
	
	reset : function() {}
	
	
}   

/*
 * Effetto apertura base - nel caso non venga esplicitato altro verra' usato questo 
 */

IMoveOpenEffectBaseOptions = Object.extend({
	resizeSpeed: 7,
	showDetails: true,
	animateDetails: false
});
	
var IMoveOpenEffectBase = Class.create();

IMoveOpenEffectBase.prototype = {

	initialize: function(conf){ 
		if (IMoveOpenEffectBaseOptions.resizeSpeed > 10) IMoveOpenEffectBaseOptions.resizeSpeed = 10;
        if (IMoveOpenEffectBaseOptions.resizeSpeed < 1)  IMoveOpenEffectBaseOptions.resizeSpeed = 1;
	
		if (typeof conf == 'undefined') conf = {};
		this.resizeSpeed = conf.resizeSpeed || IMoveOpenEffectBaseOptions.resizeSpeed;			
		this.showDetails = conf.showDetails || IMoveOpenEffectBaseOptions.showDetails;
		this.animateDetails = conf.animateDetails || IMoveOpenEffectBaseOptions.animateDetails;
	},
	
	_setParent:function(parent) {	
		this.parent = parent;
		
		this.parent.resizeSpeed = this.resizeSpeed;
		this.startSize = {
			height: this.parent.max_height,
			width: this.parent.max_width
		}; // set the same as the final dimensions			
		this.parent.startSize = this.startSize;		
	},
	
	run: function(width, height) {        		
		
        var widthCurrent  = this.parent.imove_outerImageContainer.getWidth();
        var heightCurrent = this.parent.imove_outerImageContainer.getHeight();

		if (this.parent.max_height && this.parent.max_width) {			
	        width = this.parent.max_width;
	        height = this.parent.max_height;	
		}
		
        // get new width and height
    	var widthNew  = (width  + IMoveOptions.borderSize * 2);
    	var heightNew = (height + IMoveOptions.borderSize * 2);

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

        new Effect.Scale(this.parent.imove_outerImageContainer, yScale, {scaleX: false, duration: this.parent.resizeDuration, queue: 'front'}); 
        new Effect.Scale(this.parent.imove_outerImageContainer, xScale, {scaleY: false, duration: this.parent.resizeDuration, delay: this.parent.resizeDuration}); 
			
        // 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 (Prototype.Browser.IE) timeout = 250;   
        
	
        (function(){
			// posiziono i controlli
			var nord_sud = {
				height: '13',
				width: '21'
			};
			var ovest_est = {
				height: '21',
				width: '13'
			};

            this.parent.imove_ovest.setStyle({ 
				top: Math.ceil((this.parent.max_height - (ovest_est.height/2)) /2) + 'px',
				left: (1+ IMoveOptions.borderSize)+'px'		
			});
            this.parent.imove_est.setStyle({ 
				top: Math.ceil((this.parent.max_height - (ovest_est.height/2)) /2) + 'px',
				right:(ovest_est.width/2)+'px'				 
			});			
			this.parent.imove_nord.setStyle({ 
				left: Math.ceil((this.parent.max_width - nord_sud.width) /2) + 'px',
				top: (1 +IMoveOptions.borderSize)+'px'
			});
			this.parent.imove_sud.setStyle({ 
				bottom: (1+(nord_sud.height/2)) +'px',
				left: Math.ceil((this.parent.max_width - (nord_sud.width/2)) /2) + 'px'
			});			


            this.parent.imove_imageDataContainer.setStyle({ width: this.startSize.width + 'px' });

			this.parent.imove_Image_div.setStyle({height: height +'px', width: width +'px'});

            this.parent.showImage();
        }).bind(this).delay(timeout / 1000);		
	}	
}
