// --------------------------------------------------------------------------------
//
//	ImgZoom v2.08
//	by plan p. GmbH - http://www.plan-p.de/
//	Last Modification: 15. Jul 2009
//
//  Inspired by a lot of similar scripts!
//
// --------------------------------------------------------------------------------


//
//  ImgZoom Configuration
//
var ImgZoomOptions = Object.extend({
    overlayOpacity: 	0.50, 		// transparency of shadow overlay
	overlayDuration: 	0.25,		// the duration of displaying overlay before and after image visible
	overlayDelay: 		0.10,		// delay before displaying overlay
    resizeDuration: 	0.50, 		// the duration of the image resizing animation (0.00 <= X <= 3.00)
    boxAppearDuration: 	0.75, 		// the duration needed by the box to appear after click
    boxDynStartPos: 	true, 		// if true, the box will appear at the object that was clicked. false = center of viewport
    minimizeAtEnd: 		true, 		// if true, the box will minimize when closed
	initImgSize: 		72,			// initial size (height & width) of image before resizing
	closeImgDuration: 	0.25,		// duration of the close image to fade ind and out
	closeImgDelay: 		0.25		// delay of the close image to display (both ways)
}, window.ImgZoomOptions || {});


//
//  ImgZoom Class
//
var ImgZoom = Class.create();

ImgZoom.prototype = {
    imageArray: [],
    activeImage: undefined,
    imageDisplayed: false,
    isActive: false,
    
	//
    // initialize()
    // Constructor runs on completion of the DOM loading.
	//
    initialize: function() {
		// collect the imgzoom-rels
		this.updateImageList();
        
		// register event listener for the keyboard
		this.keyboardAction = this.keyboardAction.bindAsEventListener(this);

		// check the config
        if (ImgZoomOptions.resizeDuration > 3) ImgZoomOptions.resizeDuration = 3;
        if (ImgZoomOptions.resizeDuration < 0)  ImgZoomOptions.resizeDuration = 0;

        if (ImgZoomOptions.overlayDuration > 1.5) ImgZoomOptions.overlayDuration = 1.5;
        if (ImgZoomOptions.overlayDuration < 0)  ImgZoomOptions.overlayDuration = 0;

        if (ImgZoomOptions.initImgSize > 500) ImgZoomOptions.initImgSize = 500;
        if (ImgZoomOptions.initImgSize < 1)  ImgZoomOptions.initImgSize = 1;
        var size = ImgZoomOptions.initImgSize + 'px';

		// insert the elements into the dom
		var objBody = document.getElementsByTagName("body").item(0);

		var objOverlay = document.createElement("div");
		objOverlay.setAttribute('id','overlay');
		objOverlay.style.display = 'none';
		objBody.appendChild(objOverlay);
		
		var objImgZoom = document.createElement("div");
		objImgZoom.setAttribute('id','imgZoom');
		objImgZoom.style.display = 'none';
		objBody.appendChild(objImgZoom);

		var objOuterImageContainer = document.createElement("div");
		objOuterImageContainer.setAttribute('id','outerImageContainer');
		objImgZoom.appendChild(objOuterImageContainer);		

		var objShadow_shdw_top = document.createElement("div");
		objShadow_shdw_top.setAttribute('class','shdw_top');
		objOuterImageContainer.appendChild(objShadow_shdw_top);

		var objShadow_shdw_top_div = document.createElement("div");
		objShadow_shdw_top.appendChild(objShadow_shdw_top_div);

		var objShadow_shdw_top_div2 = document.createElement("div");
		objShadow_shdw_top_div.appendChild(objShadow_shdw_top_div2);

		var objShadow_shdw_mid = document.createElement("div");
		objShadow_shdw_mid.setAttribute('class','shdw_mid');
		objOuterImageContainer.appendChild(objShadow_shdw_mid);

		var objShadow_shdw_row = document.createElement("div");
		objShadow_shdw_row.setAttribute('class','row');
		objShadow_shdw_mid.appendChild(objShadow_shdw_row);

		var objShadow_shdw_left = document.createElement("div");
		objShadow_shdw_left.setAttribute('class','shdw_left');
		objShadow_shdw_row.appendChild(objShadow_shdw_left);

		var objShadow_inhalt = document.createElement("div");
		objShadow_inhalt.setAttribute('class','inhalt');
		objShadow_shdw_row.appendChild(objShadow_inhalt);

		var objImageContainer = document.createElement("div");
		objImageContainer.setAttribute('id','imageContainer');
		objShadow_inhalt.appendChild(objImageContainer);

		var objCloseLink = document.createElement("a");
		objCloseLink.setAttribute('id','closeLink');
		objImageContainer.appendChild(objCloseLink);

		var objImgZoomImage = document.createElement("img");
		objImgZoomImage.setAttribute('id','imgZoomImage');
		objImageContainer.appendChild(objImgZoomImage);

		var objHoverNav = document.createElement("div");
		objHoverNav.setAttribute('id','hoverNav');
		objImageContainer.appendChild(objHoverNav);

		var objPrevLink = document.createElement("a");
		objPrevLink.setAttribute('id','prevLink');
		objHoverNav.appendChild(objPrevLink);

		var objNextLink = document.createElement("a");
		objNextLink.setAttribute('id','nextLink');
		objHoverNav.appendChild(objNextLink);

		var objShadow_shdw_right = document.createElement("div");
		objShadow_shdw_right.setAttribute('class','shdw_right');
		objShadow_shdw_row.appendChild(objShadow_shdw_right);

		var objShadow_shdw_bottom = document.createElement("div");
		objShadow_shdw_bottom.setAttribute('class','shdw_bottom');
		objOuterImageContainer.appendChild(objShadow_shdw_bottom);

		var objShadow_shdw_bottom_div = document.createElement("div");
		objShadow_shdw_bottom.appendChild(objShadow_shdw_bottom_div);

		var objShadow_shdw_bottom_div2 = document.createElement("div");
		objShadow_shdw_bottom_div.appendChild(objShadow_shdw_bottom_div2);

		// setup observers
		$('overlay').hide().observe('click', (function() { this.end(); }).bind(this));
		$('imgZoom').hide().observe('click', (function(event) { if (event.element().id == 'imgZoom') this.end(); }).bind(this));
		$('prevLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this));
		$('nextLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this));
		$('closeLink').hide().observe('click', (function() { this.end(); }).bind(this));

        var th = this;
        (function(){
            var ids = 'overlay imgZoom outerImageContainer imageContainer imgZoomImage hoverNav prevLink nextLink closeLink';   
            $w(ids).each(function(id){ th[id] = $(id); });
        }).defer();

    },

    //
    // updateImageList()
    // Loops through anchor tags looking for 'imgzoom' references and applies onclick events to appropriate links.
    //
    updateImageList: function() {   
        this.updateImageList = Prototype.emptyFunction;

        document.observe('click', (function(event){
            var target = event.findElement('a[rel^=imgzoom]') || event.findElement('area[rel^=imgzoom]');
            if (target) {
                event.stop();
				if(!this.isActive)
				{
					this.isActive = true;
                	this.start(target);
				}
            }
        }).bind(this));
    },
    
    //
    //  start()
    //  Display overlay and imgZoom. If image is part of a set, add siblings to imageArray.
    //
    start: function(imageLink) {
		// fix for objects that sticky on top of z-index
		$$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });

        this.imageArray = [];
        var imageNum = 0;       

        if ((imageLink.rel == 'imgzoom')){
            // if image is NOT part of a set, add single image to imageArray
            this.imageArray.push([imageLink.href, imageLink.title]);         
        } else {
            // if image is part of a set..
            this.imageArray = 
                $$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]').
                collect(function(anchor){ return [anchor.href, anchor.title]; }).
                uniq();
            
            while (this.imageArray[imageNum][0] != imageLink.href) { imageNum++; }
        }

        // calculate top and left offset etc.
		var arrayPageViewport = document.viewport.getDimensions();
        var arrayPageScroll = document.viewport.getScrollOffsets();
        var imgZoomTop = arrayPageScroll.top + ((arrayPageViewport.height - ImgZoomOptions.initImgSize) / 2);
        var imgZoomLeft = arrayPageScroll.left + ((arrayPageViewport.width - ImgZoomOptions.initImgSize) / 2);

		// position the element
		var elemTop = imageLink.cumulativeOffset().top;
		var elemLeft = imageLink.cumulativeOffset().left;
		if( elemTop>0 && elemLeft>0 
			&& ImgZoomOptions.boxDynStartPos===true )
		{
			this.imgZoom.setStyle({ top: (elemTop - 11) + 'px', left: (elemLeft - 11) + 'px' });
		}
		else
		{
			this.imgZoom.setStyle({ top: imgZoomTop + 'px', left: imgZoomLeft + 'px' });
		}
        this.outerImageContainer.setStyle({ height: (imageLink.getHeight() +0) + 'px', width: (imageLink.getWidth() +26) + 'px' }).show();
        new Effect.Appear(this.imgZoom, { duration: ImgZoomOptions.boxAppearDuration, from: 0.0, to: 1.0 });

		this.changeImage(imageNum, true);

		(function(){
	        new Effect.Appear(this.closeLink, { duration: ImgZoomOptions.closeImgDuration, from: 0.0, to: 1.0, queue: 'end', delay: ImgZoomOptions.closeImgDelay });
		}).bind(this).delay(ImgZoomOptions.overlayDuration);
    },

    //
    //  changeImage()
    //  Hide most elements and preload image in preparation for resizing image container.
    //
    changeImage: function(imageNum, start) {
        this.activeImage = imageNum; 	// update global var

		this.imageDisplayed = false;

        // hide elements during transition
		this.hoverNav.hide();
		this.prevLink.hide();
		this.nextLink.hide();

		if(!start)
		{
			var tmp_delay = 0.25;
			new Effect.Fade(this.imgZoomImage, { duration: tmp_delay, from: 1.0, to: 0.0, queue: 'end' });
		}
		
        var fnc_delayed = (function(){
			this.imgZoomImage.hide();
			
	        // once image is preloaded, resize image container
			var imgPreloader = new Image();
	        imgPreloader.onload = (function(){
				this.imgZoomImage.src = this.imageArray[this.activeImage][0];
				this.resizeImageContainer(imgPreloader.width, imgPreloader.height, start);
				this.imageDisplayed = true;
	        }).bind(this);
	        imgPreloader.src = this.imageArray[this.activeImage][0];
		}).bind(this).delay(tmp_delay);
    },

	//
	//  resizeImageContainer()
	//
	resizeImageContainer: function(imgWidth, imgHeight, start) {
		if(start)
		{
			// stretch overlay to fill page and fade in
			$('overlay').setStyle({ width: '100%', height: '100%' });
			new Effect.Appear(this.overlay, { duration: ImgZoomOptions.overlayDuration, from: 0.0, to: ImgZoomOptions.overlayOpacity, delay: ImgZoomOptions.overlayDelay });
		}
		else
		{
			new Effect.Appear(this.overlay, { duration: 0.0, from: ImgZoomOptions.overlayOpacity, to: ImgZoomOptions.overlayOpacity, delay: ImgZoomOptions.overlayDelay });
		}

		// get current width and height of old image and current viewport
		var widthCurrent  = this.outerImageContainer.getWidth();
		var heightCurrent = this.outerImageContainer.getHeight();
		var arrayPageViewport = document.viewport.getDimensions();
        var arrayPageScroll = document.viewport.getScrollOffsets();

		// check for to large images
		if( imgWidth>(arrayPageViewport.width-50) || imgHeight>(arrayPageViewport.height-50) )
		{
			var wScale = (arrayPageViewport.width-50) / imgWidth;
			var hScale = (arrayPageViewport.height-50) / imgHeight;
			if(wScale<hScale)
			{
				imgWidth = imgWidth * wScale;
				imgHeight = imgHeight * wScale;
			}
			else
			{
				imgWidth = imgWidth * hScale;
				imgHeight = imgHeight * hScale;				
			}
		}
		
		// calculate top and left offset etc.
		var imgZoomTop = arrayPageScroll.top + ((arrayPageViewport.height - imgHeight) / 2) - 10;
		var imgZoomLeft = arrayPageScroll.left + ((arrayPageViewport.width - imgWidth) / 2) - 10;
		//var imgZoomLeft = arrayPageScroll.left;

		// set new width and height
		this.imgZoomImage.setStyle({ width: imgWidth + 'px', height: imgHeight + 'px' });

		// calculate size difference between new and old image, and resize if necessary
		var wDiff = widthCurrent - (imgWidth+26);
		var hDiff = heightCurrent - (imgHeight+0);

		// save new size into object
		var newImgStyleObj = new Object();
		newImgStyleObj.width = (imgWidth+26) + 'px';
		newImgStyleObj.height = (imgHeight+0) + 'px';
		
		// save new offsets into object
		var newRootStyleObj = new Object();
		newRootStyleObj.top = imgZoomTop + 'px';
		newRootStyleObj.left = imgZoomLeft + 'px';
		
		// morph to new offset and size
		new Effect.Parallel([
				new Effect.Morph(this.imgZoom, { style: newRootStyleObj	}),
				new Effect.Morph(this.outerImageContainer, { style: newImgStyleObj })
			], {
				duration: ImgZoomOptions.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 ((hDiff == 0) && (wDiff == 0)){
			timeout = 100;
			if (Prototype.Browser.IE) timeout = 250;   
		}

		(function(){
			this.prevLink.setStyle({ height: (imgHeight+11) + 'px' });
			this.nextLink.setStyle({ height: (imgHeight+11) + 'px' });
			this.showImage();
		}).bind(this).delay(timeout / 1000);
	},
	
	//
	//  showImage()
	//  Display image and begin preloading neighbors.
	//
	showImage: function(){
		new Effect.Appear(this.imgZoomImage, { 
			duration: ImgZoomOptions.resizeDuration, 
			queue: 'end', 
			afterFinish: (function(){ this.updateNav(); }).bind(this) 
		});
		(function(){
			this.imgZoom.show();
			this.imgZoom.setOpacity(1.0);
		}).bind(this).delay(ImgZoomOptions.resizeDuration);
		this.preloadNeighborImages();
	},

	//
	//  updateNav()
	//  Display appropriate previous and next hover navigation.
	//
	updateNav: function() {
        this.hoverNav.show();               

		// if not first image in set, display prev image button
		if (this.activeImage > 0) this.prevLink.show();
		// if not last image in set, display next image button
		if (this.activeImage < (this.imageArray.length - 1)) this.nextLink.show();
        
		this.enableKeyboardNav();
	},

	//
	//  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
			this.end();
		} else if ((key == 'p') || (keycode == 37)){ 	// display previous image
			if (this.activeImage != 0){
				this.disableKeyboardNav();
				this.changeImage(this.activeImage - 1);
			}
		} else if ((key == 'n') || (keycode == 39)){ 	// display next image
			if (this.activeImage != (this.imageArray.length - 1)){
				this.disableKeyboardNav();
				this.changeImage(this.activeImage + 1);
			}
		}
	},

	//
	//  preloadNeighborImages()
	//  Preload previous and next images
	//
	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()
	//
	end: function() {
		if(!this.isActive) { return; }
		this.isActive = false;
		
		this.disableKeyboardNav();
		new Effect.Fade(this.closeLink, { duration: ImgZoomOptions.overlayDuration, delay: 0.0 });
		new Effect.Fade(this.imgZoom, { duration: (ImgZoomOptions.overlayDuration *2), delay: 0.0 });
		new Effect.Fade(this.overlay, { duration: (ImgZoomOptions.overlayDuration *2), delay: (ImgZoomOptions.overlayDuration *2) });

		if(this.imageDisplayed  && ImgZoomOptions.minimizeAtEnd)
		{
			var arrayPageViewport = document.viewport.getDimensions();
	        var arrayPageScroll = document.viewport.getScrollOffsets();

			var endSizeWidth = this.imgZoomImage.width / 3;
			var endSizeHeight = this.imgZoomImage.height / 3;

			// calculate top and left offset etc.
			var imgZoomTop = arrayPageScroll.top + ((arrayPageViewport.height - endSizeHeight) / 2) - 10;
			var imgZoomLeft = arrayPageScroll.left + ((arrayPageViewport.width - endSizeWidth) / 2) - 10;

			// save new size into object
			var newImgStyleObj = new Object();
			newImgStyleObj.width = (endSizeWidth+26) + 'px';
			newImgStyleObj.height = (endSizeHeight+0) + 'px';

			// save new offsets into object
			var newRootStyleObj = new Object();
			newRootStyleObj.top = imgZoomTop + 'px';
			newRootStyleObj.left = imgZoomLeft + 'px';

			// morph to new offset and size
			new Effect.Parallel([
					new Effect.Morph(this.imgZoom, { style: newRootStyleObj }),
					new Effect.Morph(this.imgZoomImage, { style: newImgStyleObj }),
					new Effect.Morph(this.outerImageContainer, { style: newImgStyleObj })
				], {
					duration: (ImgZoomOptions.overlayDuration *3)
				}
			);
		}
		this.imageDisplayed = false;

		(function(){
			this.outerImageContainer.setStyle({ width: ImgZoomOptions.initImgSize + 'px', height: ImgZoomOptions.initImgSize + 'px' }); 
			this.closeLink.hide(); 
		}).bind(this).delay(ImgZoomOptions.overlayDuration *4);

		// undo: fix for sticky (z-indexed) elements
		$$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });
    }

}
document.observe('dom:loaded', function () { var myImgZoom = new ImgZoom(); });
