/*
 * GroovyZoom - A zoomer plugin for jQuery
 * Written by Matt Rink, based loosely on jqzoom
 *
 * jQuery() is used rather than $() to ensure compatability
 */
 
 (function($) {
	 var groovyZoomEnabled;
	 
	 $.fn.groovyZoom = function(options) {
	 
	 	// Setup the default settings
	 	var settings = $.extend({
			zoomWidth: 150,
			zoomHeight: 150,
			followMouse: false,
			xOffset: 0,
			yOffset: 0,
			displayPreloader: false,
			parentElement: 'body'
	 	}, options);
	 	
	 	// globals
	 	var aTitle;
	 	var largeImg;
	 	var largeImgPath;
	 	var smallImg;
	 	var smallImgTitle;
	 	var zoomHolder;
	 	var preloaderHolder;
	 	var wasOverSmallImg = false;
	 	var imageLoaded = false;
	 	
	 	groovyZoomEnabled = true;
	 	
	 	// Setup each matching element
	 	return this.each(function() {
	 		
	 		function mouseEnterHandler(e) {
	 			if (zoomHolder == undefined) {
	 				zoomHolder = $('<div />')
	 					.addClass('groovyZoom')
	 					.css('width', settings.zoomWidth + 'px')
	 					.css('height', settings.zoomHeight + 'px')
	 					.css('position', 'absolute')
	 					.css('overflow', 'hidden')
	 					.css('zIndex', 100)
	 					.css('backgroundColor', '#ffffff');
	 				zoomHolder.append('<img src="' + largeImgPath + '" />');
	 				$(settings.parentElement).append(zoomHolder);
	 				largeImg = zoomHolder.children('img');
	 				largeImg.css('position', 'absolute')
	 					.css('top', '0px')
	 					.css('left', '0px');
	 			} else {
	 				zoomHolder.css('display', 'block');
	 				if (!settings.followMouse) {
	 					zoomHolder.css('position', 'absolute')
	 						.css('top', settings.yOffset + 'px')
	 						.css('left', settings.xOffset + 'px');
	 				}
	 			}
	 			
	 			if (settings.displayPreloader && !imageLoaded) {
	 				// Preload the image
	 				zoomHolder.css('display', 'none');
	 				
	 				preloaderHolder = $('<div />')
	 					.addClass('groovyZoomPreloader');
	 				preloaderHolder.insertAfter(smallImg);
	 				
	 				var preloadImg = $('<img>').css('display', 'none')
	 					.load(function() {
		 					zoomHolder.css('display', 'block');
		 					preloaderHolder.remove();
	
		 					var smallImgPos = smallImg.offset();
		 					var largeImgOffset = calculateLargeImgOffset(smallImgPos.top + (smallImg.height() / 2),
		 						smallImgPos.left + (smallImg.width() / 2));
			 				
			 				largeImg.css('top', largeImgOffset.top + 'px')
				 			largeImg.css('left', largeImgOffset.left + 'px')
				 			
				 			imageLoaded = true;
		 				});
	 				preloadImg.attr('src', largeImgPath);
	 			}
	 		};
	 		
	 		function mouseOutHandler(e) {
	 			zoomHolder.css('display', 'none');
	 			wasOverSmallImg = false;
	 		};
	 		
	 		function mouseMoveHandler(e) {
	 			
	 			if (!groovyZoomEnabled)
	 				return;
	 			
	 			var smallImgPos = smallImg.offset();
	 			
	 			var isOverSmallImg = false;
	 			
	 			if (e.pageY >= smallImgPos.top && e.pageX >= smallImgPos.left && 
	 					e.pageY <= smallImgPos.top + smallImg.height() && e.pageX <= smallImgPos.left + smallImg.width()) {
	 				isOverSmallImg = true;
	 			}
	 			
	 			if (!wasOverSmallImg && isOverSmallImg) {
	 				mouseEnterHandler(e);
	 			}
	 			
	 			if (wasOverSmallImg && !isOverSmallImg) {
	 				mouseOutHandler(e);
	 			}
	 			
	 			if (isOverSmallImg && settings.followMouse && zoomHolder != undefined) {
	 				var newSmallTop = e.pageY - Math.ceil(settings.zoomHeight / 2);
	 				var newSmallLeft = e.pageX - Math.ceil(settings.zoomWidth / 2);
	 				
	 				// top
	 				if (newSmallTop < smallImgPos.top)
	 					newSmallTop = smallImgPos.top;
	 				if (newSmallTop + settings.zoomHeight > smallImgPos.top + smallImg.height())
	 					newSmallTop = (smallImgPos.top + smallImg.height()) - settings.zoomHeight;
	 				
	 				// left
	 				if (newSmallLeft < smallImgPos.left)
	 					newSmallLeft = smallImgPos.left;
	 				if (newSmallLeft + settings.zoomWidth > smallImgPos.left + smallImg.width())
	 					newSmallLeft = (smallImgPos.left + smallImg.width()) - settings.zoomWidth;
	 				
	 				zoomHolder.css('top', newSmallTop + 'px');
	 				zoomHolder.css('left', newSmallLeft + 'px')
 				}
	 			
	 			if (largeImg != undefined) {
	 				var largeImgOffset = calculateLargeImgOffset(e.pageY, e.pageX);
	 				
	 				largeImg.css('top', largeImgOffset.top + 'px')
		 			largeImg.css('left', largeImgOffset.left + 'px')
		 			
		 			if (isOverSmallImg)
		 				wasOverSmallImg = true;
	 			}
	 		};
	 		
	 		function calculateLargeImgOffset(mouseTop, mouseLeft) {
	 			var widthRatio = smallImg.width() / largeImg.width();
	 			var heightRatio = smallImg.height() / largeImg.height();
	 			
	 			var smallImgPos = smallImg.offset();
	 			
	 			var newLargeTop = (Math.ceil((mouseTop - smallImgPos.top) / widthRatio) - settings.zoomWidth / 2);
	 			var newLargeLeft = (Math.ceil((mouseLeft - smallImgPos.left) / heightRatio) - settings.zoomWidth / 2);
	 			
	 			// top
	 			if (newLargeTop < 0)
	 				newLargeTop = 0;
	 			if (newLargeTop + settings.zoomHeight > largeImg.height())
	 				newLargeTop = largeImg.height() - settings.zoomHeight;
	 			
	 			// left
	 			if (newLargeLeft < 0)
	 				newLargeLeft = 0;
	 			if (newLargeLeft + settings.zoomWidth > largeImg.width())
	 				newLargeLeft = largeImg.width() - settings.zoomWidth;
	 			
	 			return { top: 0 - newLargeTop, left: 0 - newLargeLeft };
	 		}
	 			
	 		var a = $(this);
	 		// We only work with anchors
	 		if (a[0].nodeName.toLowerCase() == 'a') {
				aTitle = a.attr('title');
				a.removeAttr('title');
				a.css('outline-style','none');
				
				// Prevent the anchor/image being clickable
				a.bind('click', function(e) { return false; });
				
				largeImgPath = a.attr('href');
				
				smallImg = $('img', this);
				smallImgTitle = smallImg.attr('title');
				smallImg.removeAttr('title');
				
				// Setup events to display/hide/update the zoomer 
				$(settings.parentElement).bind('mousemove', function(e) { mouseMoveHandler(e); });
	 		}
	 	});
	 
	 };
	 
	 $.fn.disableGroovyZoom = function() {
		 groovyZoomEnabled = false;
	 };
	 
	 $.fn.enableGroovyZoom = function() {
		 groovyZoomEnabled = true;
	 };
})(jQuery);
 
