/*
---
description: MooZoom

license:
  MIT-style

authors:
  - Luke Ehresman (http://luke.ehresman.org)

requires:
  core:1.2.1: '*'

provides: [MooZoom]

...
*/
var MooZoom = new Class({
	Implements: Options,

	elements: null,
	options: {
		linkSelector: "a",
		imageSelector: "img",
		imageRoot: "/images/",
		transition: Fx.Transitions.linear.easeOut,
		duration: 250,
		close: "top-left"
	},

	/**
	 * Method: initialize
	 *
	 * Discover all the thumbnail images that match the selector patterns
	 * and rework them in the DOM so they use the MooZoom niftiness.
	 */
	initialize: function(options) {
		this.setOptions(options);
		if (this.options.imageRoot[this.options.imageRoot.length-1] != "/")
			this.options.imageRoot += "/";

		this.elements = document.getElements(this.options.linkSelector);
		this.elements.each(function(a) {
			a.getElements(this.options.imageSelector).each(function(img) {
				this.setupImage(a, img);
			}.bind(this));
		}.bind(this));
	},

	/**
	 * Method: setupImage
	 *
	 * Given a link to a big image (a) and a thumbnail image (img), do
	 * the magic necessary to make the MooZoom thing work.
	 */
	setupImage: function(a, img) {
		
		var href = a.getProperty("href");
		a.setProperty("href", null);

		// preload the close icon
		if (this.options.close) {
			var close = new Element("img", {
				src: this.options.imageRoot+"moozoom_close.png",
				'class': 'close moozoom',
				title: 'Hide Large Image',
				styles: {
					"opacity": 0,
					"top": -99999,
					"left": -99999,
					"position": "absolute",
					"cursor": "pointer"
				}
			}).inject(document.body); // preload the image
		}

		var container = null;
		var bigCoords = null;
		var smallCoords = null;
		var options = this.options;

		// grow the thumbnail
		a.addEvent("click", function(e) {
			
			// Add wait cursor while loading
			e.target.getParent().addClass('wait');
			
			
			// Hide all other zoomed images
			$$('.photo_zoom.moozoom').each(function(el){
				el.destroy();
			});
			
			// Hide closed images
			$$('.close.moozoom').each(function(el){
				el.setStyle('visibility','hidden');
			});
			
			container = Asset.image(href, {
				title: 'Hide Large Image',
				'class': 'photo_zoom moozoom',
				styles: {
					"opacity": 0,
					"top": -99999,
					"left": -99999,
					"position": "absolute",
					// "cursor": "pointer",
					"border": "1px solid #000"
				},
				onLoad: function(e){
				
				// Remove the wait cursor (if it was set)
				$$('a.photo.wait').each(function(el){
					el.removeClass('wait');
				});
				
				// Hide closed images
				$$('.close.moozoom').each(function(el){
					el.setStyle('visibility','hidden');
				});
				
				// Start loading the values once the image has vinished loading.
				if (!bigCoords) bigCoords = {width: container.width, height: container.height};
				if (!smallCoords) smallCoords = img.getCoordinates();

				var startWidth = (smallCoords.width/bigCoords.width) * bigCoords.width;
				var startHeight = (smallCoords.height/bigCoords.height) * bigCoords.height;
				var bodyElem = document.id(document.body);
				var endTop = bodyElem.getScroll().y + (bodyElem.getHeight() - bigCoords.height)/2;
				var endLeft = bodyElem.getScroll().x + (bodyElem.getWidth() - bigCoords.width)/2;

				// handle the close icon if it's supposed to be displayed.
				// this.options.close will be null if it shouldn't be displayed.
				if (zoom.options.close) {
					// define the location of the close button
					var closeTop = endTop - 10;
					var closeLeft = endLeft - 10;
					switch (zoom.options.close) {
						case "bottom-right":
							closeTop = endTop + bigCoords.height - 14;
							closeLeft = endLeft + bigCoords.width - 14;
							break;
						case "bottom-left":
							closeTop = endTop + bigCoords.height - 14;
							break;
						case "top-right":
							closeLeft = endLeft + bigCoords.width - 14;
							break;
					}

					// set initial placement of the close icon
					close.setStyles({
						"top": smallCoords.top,
						"left": smallCoords.left,
						"opacity": 0,
						"width": 1,
						"height": 1
					});
					// start the close icon growing animation
					new Fx.Morph(close, {
						transition: zoom.options.transition,
						duration: zoom.options.duration
					}).start({
						height: 24,
						width: 24,
						opacity: 1,
						top: closeTop,
						left: closeLeft
					});
				}

				// set initial placement of the image
				container.setStyles({
					"position": "absolute",
					"top": smallCoords.top,
					"left": smallCoords.left,
					"opacity": 0,
					"width": startWidth,
					"height": startHeight
				});
				// start the image growing animation
				new Fx.Morph(container, {
					transition: zoom.options.transition,
					duration: zoom.options.duration,
					onComplete: function(e) {
						// when the animation is complete, display the shadow.
						// this is done at the end for performance reasons because
						// the animation with the shadow is dog-slow on all browsers.
						container.setStyles({
							"-moz-box-shadow": "0px 2px 15px #000",
							"-webkit-box-shadow": "0px 2px 15px #000"
						});
					}.bind(this)
				}).start({
					height: bigCoords.height,
					width: bigCoords.width,
					opacity: 1,
					top: endTop,
					left: endLeft
				});

				// attach the shrink event to the various elements
				container.addEvent("click", closeEvent);
				
				
				}
			}).inject(document.body);
			
			
			return true;
			
		}.bind(this));

		// create the event handler to shring the displayed image preview
		var closeEvent = function(e) {
			// lazy load these values, if they haven't already been set
			if (!bigCoords) bigCoords = {width: container.width, height: container.height};
			if (!smallCoords) smallCoords = img.getCoordinates();

			var endWidth = (smallCoords.width/bigCoords.width) * bigCoords.width;
			var endHeight = (smallCoords.height/bigCoords.height) * bigCoords.height;

			// turn off the shadows, because they slow down the animation
			container.setStyles({
				"-moz-box-shadow": "none",
				"-webkit-box-shadow": "none"
			});

			// star the close icon shrinking animation
			if (this.options.close) {
				new Fx.Morph(close, {
					transition: this.options.transition,
					duration: this.options.duration,
					onComplete: function() {
						close.setStyles({
							"top": -99999,
							"left": -99999
						});
					}
				}).start({
					width: 1,
					height: 1,
					opacity: 0,
					top: smallCoords.top,
					left: smallCoords.left
				});
			}

			// start the image shrinking animation
			new Fx.Morph(container, {
				transition: this.options.transition,
				duration: this.options.duration,
				onComplete: function() {
					container.destroy();
				}
			}).start({
				width: endWidth,
				height: endHeight,
				opacity: 0,
				top: smallCoords.top,
				left: smallCoords.left
			});

			e.stopPropagation();
		}.bind(this);

		if (this.options.close) {
			close.addEvent("click", closeEvent);
		}
	}
});

