﻿/*
(c) 2011 McKenna Consultants.

Licenced under the MIT:
http://www.opensource.org/licenses/mit-license.php

**************************************/
(function ($)
{

	$.fn.mclZoomer = $.fn.MclZoomer = function (variables)
	{
		var defaults =
		{
			dsetting:
				{
					defaultpower: 2,
					powerrange: [2, 7],
					magnifiersize: [200, 200],
					currentPower: 2
				},

			mousewheelevt: (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel", //FF doesn't recognize mousewheel as of FF3.x
			popupContainer: null,
			navigationContainer: null,
			imageContainer: null,
			magnifier: null,
			maginfierImage: null,
			activeimage: null,
			biggerImage: null,
			imageOffset: null,
			imageScaledSize: null,
			thumbReplace: { src: '', dst: '' },
			debug: false,
			srcImageList: null,
			srcImages: new Array(),
			srcImageIndex: 0
		};

		var options = $.extend(defaults, variables);

		//////////////// INIT //////////////// 
		init = function (zoomWrapper)
		{
			options.currentPower = options.defaultpower;

			var master = $(zoomWrapper);

			if (options.debug)
			{
				master.append("<div id='mclzoomer-debug-" + zoomWrapper.id + "' class='mclzoomer-debug'>Debug</div>");
			}

			var srcImg = $($.getImages(zoomWrapper));

			// fit srcImage into its parent container
			var imgContainer = srcImg.parent();
			$.fitImage(zoomWrapper, imgContainer, srcImg, srcImg.width(), srcImg.height())

			// create the two main image sections
			$.createOverlays(zoomWrapper);

			// mouse clicks etc
			$.hookUpEvents(zoomWrapper);

			// setup image
			$.setup(zoomWrapper, srcImg);
		}

		//////////////// GET IMAGES FROM SOURCES //////////////// 
		$.getImages = function (zoomWrapper)
		{
			// extract source images, if there are some add on clicks
			if (options.srcImageList != null)
			{
				options.srcImages = options.srcImageList.find('img');
			}

			if (options.srcImages == null)
			{
				options.srcImages = new Array();
			}

			// See if there is a source image already defined
			var images = $(zoomWrapper).find('img');
			var srcImg;
			$.each(images, function (i, item)
			{
				srcImg = item;
			});

			options.biggerImage = srcImg;

			if (options.biggerImage.src.length <= 0)
			{
				options.biggerImage.src = options.srcImages[0].src.replace(options.thumbReplace.src, options.thumbReplace.dst);
			}

			// nope, use first in list
			if (srcImg == null && options.srcImages != null)
			{
				srcImg = options.srcImages[0];
			}

			// find it in list
			options.srcImageIndex = -1;
			$.each(options.srcImages, function (i, item)
			{
				if (srcImg != null)
				{
					var itemSrc = item.src.replace(options.thumbReplace.src, options.thumbReplace.dst);
					var srcImgSrc = srcImg.src.replace(options.thumbReplace.src, options.thumbReplace.dst);

					if (itemSrc == srcImgSrc)
					{
						options.srcImageIndex = i;
						// exists in list so need to make "main" image clickable
						$.attachImage(zoomWrapper, i, srcImg);
					}
				}
			});

			if (options.srcImageIndex == -1)
			{
				options.srcImageIndex = 0;
				options.srcImages.splice(0, 0, srcImg);
			}

			return srcImg;
		}

		//////////////// The popup overlay //////////////// 
		$.createOverlays = function (zoomWrapper, srcImg)
		{
			var master = $(zoomWrapper);

			master.css({ 'z-index': 10000 });

			master.append("<div id='mclzoomer-popup-" + zoomWrapper.id + "' class='mclzoomer-overlay'></div>");

			options.popupContainer = $('#mclzoomer-popup-' + zoomWrapper.id);
			options.popupContainer.hide();

			// add the background 
			options.popupContainer.append("<div id='mclzoomer-background-" + zoomWrapper.id + "' class='mclzoomer-background'></div>");


			// add the container
			options.popupContainer.append("<div id='mclzoomer-container-" + zoomWrapper.id + "' class='mclzoomer-container'></div>");

			var container = $('#mclzoomer-container-' + zoomWrapper.id);
			container.append("<div id='mclzoomer-imagecontainer-" + zoomWrapper.id + "' class='mclzoomer-imagecontainer'></div>");

			///////////////// the image
			$.addTheImage(zoomWrapper);

			$.addControls(zoomWrapper, container)

			//////////////// MAGNIFIER
			$.addMagnifier(zoomWrapper);
		}

		//////////////// ADD IMAGE //////////////// 
		$.addTheImage = function (zoomWrapper)
		{
			options.imageContainer = $('#mclzoomer-imagecontainer-' + zoomWrapper.id);
			options.imageContainer.append("<img id='mclzoomer-showimage-" + zoomWrapper.id + "' class='mclzoomer-showimage' />");

			options.activeimage = $('#mclzoomer-showimage-' + zoomWrapper.id);
		}

		//////////////// BUTTONS //////////////// 
		$.addControls = function (zoomWrapper, container)
		{
			container.append("<div id='mclzoomer-instruction-" + zoomWrapper.id + "' class='mclzoomer-instructions'>Move mouse over image to magnify. Mouse wheel zoom -/+</div>");

			// close button
			container.append("<div id='mclzoomer-closebtn-" + zoomWrapper.id + "' class='mclzoomer-closebtn'></div>");
			// prev next btns
			container.append("<div id='mclzoomer-nextprevcontainer-" + zoomWrapper.id + "' class='mclzoomer-nextprevcontainer'></div>");

			options.navigationContainer = $('#mclzoomer-nextprevcontainer-' + zoomWrapper.id);

			options.navigationContainer.append("<div id='mclzoomer-prevbtn-" + zoomWrapper.id + "' class='mclzoomer-prevbtn'></div>");
			options.navigationContainer.append("<div id='mclzoomer-nextbtn-" + zoomWrapper.id + "' class='mclzoomer-nextbtn'></div>");
		}

		//////////////// Magnifier //////////////// 
		$.addMagnifier = function (zoomWrapper)
		{
			var magnifier = $("<div class='mclzoomer-magnifier' id='mclzoomer-maginfier-outer-" + zoomWrapper.id + "' />")
							.appendTo(document.body);

			magnifier.css({ 'z-index': 10001 });

			magnifier.append("<img class='mclzoomer-magnifier-image' id='mclzoomer-maginfier-image-" + zoomWrapper.id + "' />");

			options.magnifier = magnifier;
			options.magnifierImage = $("#mclzoomer-maginfier-image-" + zoomWrapper.id);

			magnifier.css(
			{
				'width': options.magnifiersize[0],
				'height': options.magnifiersize[1]
			});

			magnifier.hide();
		}

		//////////////// Aspect fit the image to the parent container //////////////// 
		$.fitImage = function (zoomWrapper, container, theImage, imgWidth, imgHeight)
		{
			var targetWidth = container.width() - 2;
			var targetHeight = container.height() - 2;


			$.debugWriteLine(zoomWrapper, 'Container width: ' + targetWidth + ' height: ' + targetHeight);
			$.debugWriteLine(zoomWrapper, 'Image width: ' + imgWidth + ' height: ' + imgHeight);

			// ok now fit image to box
			if (imgWidth > 0 && imgHeight > 0 && targetHeight > 0 && targetWidth > 0)
			{
				var X = targetWidth / imgWidth;
				var Y = targetHeight / imgHeight;

				// how much to scale down by if anything
				var Scale = Math.min(X, Y);

				var finalHeight = parseInt(imgHeight * Scale);
				var finalWidth = parseInt(imgWidth * Scale);

				var deltaWidth = Math.max(targetWidth - finalWidth, 0) / 2;
				var deltaHeight = Math.max(targetHeight - finalHeight, 0) / 2;

				// within tolerance of 10px?
				if (deltaWidth <= 10)
				{
					deltaWidth = 0;
					finalWidth = targetWidth;
				}

				if (deltaHeight <= 10)
				{
					deltaHeight = 0;
					finalHeight = targetHeight;
				}

				theImage.css(
						{
							/*'position': 'absolute',*/
							'left': deltaWidth,
							'top': deltaHeight,
							'width': finalWidth,
							'height': finalHeight
						});

				$.debugWriteLine(zoomWrapper, 'fit w: ' + finalWidth + ' h: ' + finalHeight + ' left: ' + deltaWidth + ' top: ' + deltaHeight);

				options.imageOffset = theImage.offset();
				options.imageScaledSize = { width: finalWidth, height: finalHeight };
			}


		}

		//////////////// hookup events ///////////////////////////////////////
		$.hookUpEvents = function (zoomWrapper)
		{
			$(document).unbind('mousemove.trackmagnifier').bind('mousemove.trackmagnifier', function (e)
			{
				$.moveMagnifier(zoomWrapper, e)
			});

			options.magnifier.bind(options.mousewheelevt, function (e)
			{
				//bind mousewheel event to magnifier
				var delta = e.detail ? e.detail * (-120) : e.wheelDelta //delta returns +120 when wheel is scrolled up, -120 when scrolled down
				if (delta <= -120)
				{
					options.currentPower = Math.max(options.currentPower - 0.5, options.powerrange[0]);
				}
				else
				{ //zoom in
					options.currentPower = Math.min(options.currentPower + 0.5, options.powerrange[1]);
				}

				e.preventDefault();
				$.moveMagnifier(zoomWrapper, e)
			});

			$('#mclzoomer-prevbtn-' + zoomWrapper.id).click(function ()
			{
				$.prevImage(zoomWrapper);
			});

			$('#mclzoomer-nextbtn-' + zoomWrapper.id).click(function ()
			{
				$.nextImage(zoomWrapper);
			});

			$('#mclzoomer-closebtn-' + zoomWrapper.id).click(function ()
			{
				$.closePopup(zoomWrapper);
			});

			$.each(options.srcImages, function (i, item)
			{
				$.attachImage(zoomWrapper, i, item);
			});
		}

		//////////////// MOVE AND ZOOM ///////////////////////////////////////
		$.attachImage = function (zoomWrapper, i, item)
		{
			$(item).css(
				{
					cursor: 'pointer'
				});

			$(item).click(function ()
			{
				$.showImage(zoomWrapper, i);
			});

			$(item).mouseover(function ()
			{
				$.hoverImage(zoomWrapper, i);
			})
		}

		//////////////// MOVE AND ZOOM ///////////////////////////////////////
		$.moveMagnifier = function (zoomWrapper, e)
		{
			var mag = options.magnifier;

			if (options.popupContainer.is(":visible"))
			{
				var magImage = options.magnifierImage;
				var pos = options.imageOffset;
				var tol = 5;

				var inside = $.pointContains(e.pageX, e.pageY, pos.left - tol, pos.top - tol, options.imageScaledSize.width + tol * 2, options.imageScaledSize.height + tol * 2);

				var navPos = options.navigationContainer.offset();
				var insideNav = $.pointContains(e.pageX, e.pageY, navPos.left, navPos.top, options.navigationContainer.width(), options.navigationContainer.height());

				var closeBtn = $('#mclzoomer-closebtn-' + zoomWrapper.id);
				var closePos = closeBtn.offset();
				var insideClose = $.pointContains(e.pageX, e.pageY, closePos.left, closePos.top, closeBtn.width(), closeBtn.height());
				if (inside && !insideNav && !insideClose)
				{
					var boxWidth = options.magnifiersize[0] / 2;
					var boxHeight = options.magnifiersize[1] / 2;

					var tx = (e.pageX - pos.left);
					var ty = (e.pageY - pos.top);

					var imgWidth = options.imageScaledSize.width * options.currentPower;
					var imgHeight = options.imageScaledSize.height * options.currentPower;

					tx *= options.currentPower;
					ty *= options.currentPower;

					tx -= boxWidth;
					ty -= boxHeight;

					mag.css(
					{
						left: (e.pageX - boxWidth) + 'px',
						top: (e.pageY - boxHeight) + 'px'
					}).show();

					magImage.css(
					{
						left: -tx + 'px',
						top: -ty + 'px',
						width: imgWidth,
						height: imgHeight
					});

					//	$.debugWriteLine(zoomWrapper,  'tx: ' + tx + ' ty: ' + ty);
				}
				else
				{
					mag.hide();
				}
			}
			else
			{
				mag.hide();
			}
		}


		////////////////  SHOW NEXT IMAGE //////////////// 
		$.showImage = function (zoomWrapper, i)
		{
			options.srcImageIndex = i;

			options.popupContainer.show();

			$.setup(zoomWrapper, options.srcImages[options.srcImageIndex]);
		}

		////////////////  SHOW NEXT IMAGE //////////////// 
		$.hoverImage = function (zoomWrapper, i)
		{
			options.srcImageIndex = i;

			if (options.biggerImage != null)
			{
				var srcImg = options.srcImages[options.srcImageIndex];

				var urlSrc = srcImg.src.replace(options.thumbReplace.src, options.thumbReplace.dst);

				$(options.biggerImage).attr('src', urlSrc);

				var imgContainer = $(options.biggerImage).parent();
				$.fitImage(zoomWrapper, imgContainer, $(options.biggerImage), $(srcImg).width(), $(srcImg).height());
			}
		}

		////////////////  SHOW NEXT IMAGE //////////////// 
		$.nextImage = function (zoomWrapper)
		{
			options.srcImageIndex = (options.srcImageIndex + 1) % options.srcImages.length;

			$.setup(zoomWrapper, options.srcImages[options.srcImageIndex]);
		}

		////////////////  SHOW PREV IMAGE //////////////// 
		$.prevImage = function (zoomWrapper)
		{
			if (options.srcImageIndex > 0)
			{
				options.srcImageIndex = (options.srcImageIndex - 1) % options.srcImages.length;
			}
			else
			{
				options.srcImageIndex = options.srcImages.length - 1;
			}

			$.setup(zoomWrapper, options.srcImages[options.srcImageIndex]);
		}

		////////////////  SHOW NEXT IMAGE //////////////// 
		$.closePopup = function (zoomWrapper)
		{
			options.popupContainer.hide();
		}

		////////////////  sets up the two main screens //////////////// 
		$.setup = function (zoomWrapper, srcImg)
		{
			if (srcImg.src != null)
			{
				var urlSrc = srcImg.src.replace(options.thumbReplace.src, options.thumbReplace.dst);
				$.debugWriteLine(zoomWrapper, 'Setup Image : ' + urlSrc);
				options.magnifierImage.attr('src', urlSrc);
				options.activeimage.attr('src', urlSrc);

				$.fitImage(zoomWrapper, options.imageContainer, options.activeimage, $(srcImg).width(), $(srcImg).height());

				var multi = false;
				if (options.srcImages != null)
				{
					if (options.srcImages.length > 1)
					{
						multi = true;
					}
				}

				if (multi)
				{
					options.navigationContainer.show();
				}
				else
				{
					options.navigationContainer.hide();
				} 
			}
		}

		//////////////// 
		$.debugWriteLine = function (zoomWrapper, txt)
		{
			if (options.debug)
			{
				var dbg = $('#mclzoomer-debug-' + zoomWrapper.id);
				dbg.append('<br/>' + txt);
			}
		}

		////////////////  Test to see if a point is inside an element //////////////// 
		$.pointContains = function (posX, posY, targetX, targetY, width, height)
		{
			return (posX >= targetX && posX <= (targetX + width)
					&& posY >= targetY && posY <= (targetY + height));
		}

		this.each(function () { init(this); });
	};

})(jQuery);
	
