/**
 * @author Huy Dinh
 * @date Sept 2008
 * @version 0.3
 * 
 * A plug in to show a magnify effect on images
 * 
 * 0.4 (Jun 2009)
 * Zooming doesn't end if the mouse rolls off one image onto another within .5 second
 * 
 * 0.3 (Feb 2009):
 * Zooming only end when mouse leaves the zoom window
 * 
 * 0.2 (Jan 2009):
 * Sensor padding added - allows the zoom to stay active longer
 * Zoomed image doesn't move beyond window edges
 * 
 * 0.1 (Sept 2008):
 * Initial release
 * 
 */

(function ($) {
	var config,
		sensorPaddingX,
		sensorPaddingY,
		zoomImageContainerHeight,
		zoomImageContainerWidth,
		thumbImageOffsetX,
		thumbImageOffsetY,
		thumbImageWidth,
		thumbImageHeight,
		sensorWidth,
		sensorHeight,
		sensorOffsetX,
		sensorOffsetY,
		sensorRight,
		sensorBottom,
		zoomImageWidth,
		zoomImageHeight,
		doc = $(document),
		win = $(window),
		scrollLeft,
		scrollTop,
		scrollBottom,
		scrollRight,
		timer,
		doOutro = function() {
			if ($.browser.safari && $.browser.version.split('.')[0] < 530) {
				// Animation breaks zoomImageContainer's overflow=hidden in Safari 3.
				zoomImageContainer.hide();
			} else {
				zoomImageContainer.animate({
					width:0,
					height:0,
					left:zoomImageContainer.offset().left + zoomImageContainerWidth * .5,
					top:zoomImageContainer.offset().top + zoomImageContainerHeight * .5,
					opacity:0
				}, {
					complete:function() {
						$(this).hide();
					}
				});
				
				zoomImage.animate({
					width:0,
					height:0,
					left:0,
					top:0,
				});
 			}
			sensor.hide();
			timer = undefined;
		},
		loader = $('<div id="huy-loader" style="display:none;position:absolute;"><div id="huy-loader-screen" style="position:absolute;display:block;width:100%;height:100%;"></div><div id="huy-loader-anim" style="position:absolute;display:block;width:100%;height:100%;"></div></div>').mouseleave(function() {
			loader.hide();
		}),
		zoomImage = $("<img style='position:absolute'/>"),
		zoomImageContainer = $("<div id='huy-magnifier' style='overflow:hidden;position:absolute;display:none;z-index:9997'></div>").append(zoomImage),
		sensor = $("<div style='position:absolute;top:0;left:0;background-color:#0f0;opacity:0;filter:Alpha(Opacity=0);z-index:9999;'></div>").mousemove(function(e) {
			var left = e.pageX - (zoomImageContainerWidth*.5),
				top = e.pageY - (zoomImageContainerHeight*.5),
				right = left + zoomImageContainerWidth,
				bottom = top + zoomImageContainerHeight,
				zoomImageLeft = ((e.pageX - thumbImageOffsetX) / thumbImageWidth) * -(zoomImageWidth - zoomImageContainerWidth),
				zoomImageTop = ((e.pageY - thumbImageOffsetY) / thumbImageHeight) * -(zoomImageHeight - zoomImageContainerHeight);

//			$("#error").text('');
			if ((scrollLeft > sensorOffsetX) && (scrollLeft > left)) {
				left = scrollLeft;
			} else if (left < sensorOffsetX) {
				left = sensorOffsetX;
			} else if ((sensorRight > scrollRight) && (right > scrollRight)) {
				left = scrollRight - zoomImageContainerWidth;
			} else if (right > sensorRight) {
				left = sensorRight - zoomImageContainerWidth;
			}
			
			if ((scrollTop > sensorOffsetY) && (scrollTop > top)) {
				top = scrollTop;
			} else if (top < sensorOffsetY) {
				top = sensorOffsetY;
			} else if ((sensorBottom > scrollBottom) && (bottom > scrollBottom)) {
				top = scrollBottom - zoomImageContainerHeight;
			} else if (bottom > sensorBottom) {
				top = sensorBottom - zoomImageContainerHeight;
			}
			
			if (e.pageX < thumbImageOffsetX) {
				zoomImageLeft = 0;
			} else if (e.pageX > thumbImageOffsetX + thumbImageWidth) {
				zoomImageLeft = zoomImageContainerWidth - zoomImageWidth;
			}
			if (e.pageY < thumbImageOffsetY) {
				zoomImageTop = 0;
			} else if (e.pageY > thumbImageOffsetY + thumbImageHeight) {
				zoomImageTop = zoomImageContainerHeight - zoomImageHeight;
			}
			zoomImageContainer.css({
				left:left + "px",
				top:top + "px"
			});
			zoomImage.css({
				left:zoomImageLeft + "px",
				top:zoomImageTop + "px"
			});
		}).mouseenter(function() {
			if (timer) {
				clearTimeout(timer);
				timer = undefined;
			}
		}).mouseleave(function() {
			timer = setTimeout(doOutro, config.hideDelay);
		});
	$(function() {
		$(window).scroll(refresh).resize(refresh);
		$("body").append(zoomImageContainer).append(sensor).append(loader);
		if (0 == zoomImageContainerWidth || 0 == zoomImageContainerHeight) {
			zoomImageContainer.css({
				width:300,
				height:200
			});
		}
		zoomImageContainerWidth = zoomImageContainer.width();
		zoomImageContainerHeight = zoomImageContainer.height();
		refresh();
	});
	refresh = function(){
		scrollLeft = doc.scrollLeft();
		scrollTop = doc.scrollTop();
		scrollRight = scrollLeft + win.width();
		scrollBottom = scrollTop + win.height();
	};
	initImage = function(thumbImage, img) {
		var
			fullWidth = img.width,
			fullHeight = img.height,
			thumbContainer = thumbImage.parent().css({
				position:"relative"
			});
		thumbImage.data("fullWidth", fullWidth),
		thumbImage.data("fullHeight", fullHeight);
		thumbImage.attr("alt","").attr("title","").mouseenter(function(){
			$('#error').text(thumbImage.attr("src"));
			thumbImageWidth = thumbImage.width();
			thumbImageHeight = thumbImage.height();
			thumbImageOffsetX = thumbImage.offset().left;
			thumbImageOffsetY = thumbImage.offset().top;
//			$('#error').text(sensorPaddingX + 1);
			sensorWidth = thumbImageWidth + sensorPaddingX + sensorPaddingX;
			sensorHeight = thumbImageHeight + sensorPaddingY + sensorPaddingY;
			sensorOffsetX = thumbImageOffsetX - sensorPaddingX;
			sensorOffsetY = thumbImageOffsetY - sensorPaddingY;
			sensorRight = sensorOffsetX + sensorWidth;
			sensorBottom = sensorOffsetY + sensorHeight;
			zoomImageWidth = thumbImage.data("fullWidth");
			zoomImageHeight = thumbImage.data("fullHeight");
			zoomImage.attr("src", img.src).css({
				width:zoomImageWidth,
				height:zoomImageHeight,
				opacity:1
			});
			sensor.css({
				width:sensorWidth + "px",
				height:sensorHeight + "px",
				left:sensorOffsetX + "px",
				top:sensorOffsetY + "px"
			}).show();
			if (timer) {
				clearTimeout(timer);
				timer = undefined;
			} else {
				if ($.browser.safari && $.browser.version.split('.')[0] < 530) {
					// Animation breaks zoomImageContainer's overflow=hidden in Safari 3.
					zoomImageContainer.show();
				} else {
					zoomImage.stop();
					zoomImageContainer.stop(true, true).css({
						width:zoomImageContainerWidth+'px',
						height:zoomImageContainerHeight+'px',
						opacity:0
					}).show().animate({
						opacity:1
					});
				}
			}
		});
		var thumbWidth = thumbImage.width(),
			thumbHeight = thumbImage.height(),
			thumbContainerWidth = thumbContainer.width(),
			thumbContainerHeight = thumbContainer.height();
		if (thumbWidth > thumbHeight) {
			thumbImage.css({
				width:thumbContainerWidth,
				height:thumbHeight / (thumbWidth / thumbContainerWidth),
				bottom:0
			});
		} else if (thumbWidth == fullWidth && thumbHeight == fullHeight) {
			var newThumbWidth = thumbWidth / (thumbHeight / thumbContainerHeight);
			thumbImage.css({
				width:newThumbWidth,
				height:thumbContainerHeight,
				marginLeft:((thumbContainerWidth - newThumbWidth) * 0.5) + "px"
			});
		} else {
			thumbImage.css({
				marginLeft:((thumbContainerWidth - thumbWidth) * 0.5) + "px"
			});
		}
	};
	$.fn.magnify = function(init) {
		config = {
			paddingX:"50%", // enables the image to stay visible while the mouse is over the zoom window
			paddingY:"50%", // accepts absolute pixels or a percentage of the loupe window's width/height (max:50%)
			hideDelay:300 // in milliseconds (1000 = 1 second)
		};
		if (init) {
			for (i in init) {
				config[i] = init[i];
			}
		}
		sensorPaddingX = parseInt(config.paddingX);
		if (isNaN(config.paddingX)) {
			if (isNaN(sensorPaddingX)) {
				sensorPaddingX = 0;
			} else if ('%' == config.paddingX.charAt(config.paddingX.length-1)) {
				sensorPaddingX = zoomImageContainerWidth * (sensorPaddingX>50?50:sensorPaddingX) / 100;
			}
		}
		sensorPaddingY = parseInt(config.paddingY);
		if (isNaN(config.paddingY)) {
			if (isNaN(sensorPaddingY)) {
				sensorPaddingY = 0;
			} else if ('%' == config.paddingY.charAt(config.paddingY.length-1)) {
				sensorPaddingY = zoomImageContainerHeight * (sensorPaddingY>50?50:sensorPaddingY) / 100;
			}
		}
		var thumb = this;
		var img = new Image();
		if ('a' == thumb.parent().get(0).tagName.toLowerCase()) {
			thumb.attr("alt","").attr("title","").mouseenter(function() {
				loader.css({
					width:thumb.width(),
					height:thumb.height(),
					left:thumb.offset().left,
					top:thumb.offset().top
				}).show();
			}).parent().click(function() {
				return false;
			});
			$(img).load(function() {
				initImage(thumb.unbind(), img);
			});
			img.src = thumb.parent().attr('href');
		} else {
			img.src = thumb.attr('src');
			initImage(thumb, img);
		}
		return this;
	};
})(jQuery);
