//**************************************************************
//svZoom v1.0 is an extention of jQzoom coupled with a separate extended
//zoom for zoom within window and popup zoom both with mousecroll
//functionality.
//
//Requires: jQuery1.4+ and jquery.mousewheel by Brandon Aaron (http://brandonaaron.net)
//
//Author: Andrew Keats - 09 Oct 2010
//
// jQZoom allows you to realize a small magnifier window,close
// to the image or images on your web page easily.
//
// jqZoom version 2.2 (modified)
// Author Doc. Ing. Renzi Marco(www.mind-projects.it)
// First Release on Dec 05 2007
// i'm looking for a job,pick me up!!!
// mail: renzi.mrc@gmail.com

// modified 13 Aug 2010 AAK - added hotspot
//**************************************************************

				
(function($){

        $.fn.svZoom = function(options) {
		
        var settings = {
                lens: true,         //zooming lens over the image,by default is 1;
                preload: true,      // option to preload zoom image
                hideElement: "",    // selector for element to hide using visibility: hidden
                bigImage: null,     // optional URL to large image (will guess otherwise)
				showType: "show",	// this determines how the zoom image appears; options are "show" and "fade"
				ZoomPup: "cursor",	// this determines whether the zoom pop up appears; options are "shadow" and "cursor"
				Mousewheel: false,	// determines whether mousewheel scroll is used for the zoom
				Zoomable: true,		// determines if the image can be zoomed via popup of mousewheel
				HotSpot: false,		// determines whether a hot spot is used for the zoom
				HotSpotMsg: "Hover over to start zoom",	//deafault message inside a hotspot
				MainImage: this,
				ThumbnailsContainer: $('.images > ul'),
				ImageValues: {
					format: 'jpg',
					thumb: '_st',
					standard: '_p',
					zoom: '_z'
				}
            };					

			// modifying the settings
			if(options) {
				$.extend(settings, options);
			}

			// setting up global variables
            var noalt='',
				HotSpotHovered = false,
				HotSpotMsg = settings.HotSpotMsg,
				MainImage = settings.MainImage,
				bigImage = settings.bigImage,
				targetImage = $(MainImage)[0].tagName == 'IMG' ? $(MainImage): $(MainImage).find('img').eq(0),
				thumbExt = settings.ImageValues.thumb + '.' + settings.ImageValues.format,
				standardExt = settings.ImageValues.standard + '.' + settings.ImageValues.format,
				zoomExt = settings.ImageValues.zoom + '.' + settings.ImageValues.format;
				
				
			//helper functions
			
			function createZoomDiv(elem) {
				var zoomDiv = $(elem).parent().find('.zoomdiv');
				if(zoomDiv.get().length == 0) {
					zoomDiv = $("<div class='zoomdiv'><img class='bigimg' src='"+bigImage+"'/></div>").insertAfter(elem);
					$(elem).append("<div class='jqZoomPup'>&nbsp;</div>");
				}
				return zoomDiv;
			}

			function showZoomDiv(elem) {
				switch(settings.showType) {
				case "show":
					elem.show();
					break;
				case "fade":
					elem.fadeIn("slow");
					break;
				}
			}
			
			function hideZoomDiv(elem, callback) {
				var funcHolder;
				if (typeof callback == 'function') {
					funcHolder = callback;
				} else { funcHolder = null }
				switch(settings.showType) {
				case "show":
					elem.hide(0, funcHolder);
					break;
				case "fade":
					elem.fadeOut('fast', funcHolder);
					break;
				}
			}
			
			
			function hideElementsToHide() {
				$(settings.hideElement).blur();
				
				if($.browser.msie) {
					$(settings.hideElement).css("visibility", "hidden");
				} else {
					$(settings.hideElement).css("opacity",.3);
				}
			}

			function showElementsToHide() {
				if($.browser.msie) {
					$(settings.hideElement).css('visibility', 'visible');
				} else {
					$(settings.hideElement).fadeTo("normal",1);
				}
			}

			
			//set up conditions
			
			if (!bigImage) {
				var imageSrc = $(this).children("img").attr("src");
				bigImage = imageSrc.replace(RegExp(standardExt,'i'), zoomExt);
			};

			if (settings.HotSpot){
				var ImageCover = $('<div class="image-cover"/>');
				var HotSpotElem = $('<div class="hotspot"/>');
				$('<p>' + HotSpotMsg + '</p>').appendTo(HotSpotElem);
				ImageCover.hover(function(e){
					e.stopPropagation();
				},function(e){
					e.stopPropagation();
				});
				HotSpotElem.hoverIntent(function(){
					HotSpotHovered = true;
					HotSpotElem.fadeOut();
					ImageCover.hide();
					$(MainImage).mouseover();
				}, function() {});

				if ($.browser.msie) {
					this.parent().prepend(ImageCover, HotSpotElem);
				} else {
					this.prepend(ImageCover, HotSpotElem);
				}
			}
			
			if (settings.Mousewheel && $.fn.mousewheel) {
			
				settings.ThumbnailsContainer.find('img').unbind('click');
			
				function ZoomController(zoomWindow, image) {
					//image = image || targetImage;
					//zoomWindow = zoomWindow || MainImage;
					if (!(this instanceof arguments.callee)) {  
						return new ZoomController(zoomWindow, image);  
					}
					//var objInstance = this; ? maybe this will separate the to instances, so they don't share the constructor values as a reference
					objInstance = this;
						objInstance.zoomWindow = zoomWindow;
						objInstance.image = {
							originalImageObj: image,
							originalImage: image[0],
							originalHeight: image[0].height,
							originalWidth: image[0].width,
							zoomableImage: myImage
						};
						objInstance.counter = 0;
						objInstance.wasCounter = 0;
						objInstance.calculatedSteps = function () {
							var zoomToOriginalRatio = (objInstance.image.zoomableImage.height/objInstance.image.originalHeight);
							return (Math.round(zoomToOriginalRatio.toFixed(2) * 4));
						};
						objInstance.maxSteps = objInstance.calculatedSteps();
						objInstance.createIncrements = function() {
							incCounter = 0;
							incSteps = objInstance.maxSteps;
							dHeight = objInstance.image.zoomableImage.height - objInstance.image.originalHeight;
							dWidth = objInstance.image.zoomableImage.width - objInstance.image.originalWidth;
							dHIncrement = (dHeight/incSteps).toFixed(3);
							dWIncrement = (dWidth/incSteps).toFixed(3);
							dIncrements = [dHIncrement, dWIncrement];
							dIncrementObj = {
								hArr: [],
								wArr:[]
							};
							while (incCounter < incSteps) {
								if (incCounter == 0) {
									dIncrementObj.hArr.push(objInstance.image.originalHeight);
									dIncrementObj.wArr.push(objInstance.image.originalWidth);
								} else {
									dIncrementObj.hArr.push(objInstance.image.originalHeight + Math.round(incCounter * dHIncrement));
									dIncrementObj.wArr.push(objInstance.image.originalWidth + Math.round(incCounter * dWIncrement));
								}
								incCounter++;
							}
							dIncrementObj.hArr[incSteps] = objInstance.image.zoomableImage.height;
							dIncrementObj.wArr[incSteps] = objInstance.image.zoomableImage.width;
							deltas = [dHeight, dWidth];
							return {deltas:deltas, deltaIncrements:dIncrementObj};
						};
						objInstance.imageCycling = function() {
							imgCycInstance = this;
							imgCycInstance.images = null;
							imgCycInstance.changeImage = $(objInstance.image.originalImage);
							imgCycInstance.collectionPos = 0;
							imgCycInstance.imageSwap = function(hitImage, changeImage) {
									changeImage = changeImage || imgCycInstance.changeImage;
									imgCycInstance.images.removeClass('current');
									$(hitImage).addClass('current');
									changeImage.attr({ 'src': hitImage.src.replace(RegExp(thumbExt, 'i'), standardExt),
										'alt': this.alt
									});
									objInstance.update();
									objInstance.reset();
								};
							imgCycInstance.setup = function(collectionContainer, changeImage) {
								if (!$('img', collectionContainer.selector).length) {
									return;
								}
								changeImage = changeImage || imgCycInstance.changeImage;//image;
								imgCycInstance.images = $('img', collectionContainer.selector);
								collectionContainer.addClass('cycling');
								if (!imgCycInstance.images.hasClass('current')){
									imgCycInstance.images.eq(0).addClass('current');
								} else {
									imgCycInstance.collectionPos = $(imgCycInstance.images.selector +'.current').parent().index();
								}
								imgCycInstance.images.bind('click.imgSwap', function(e) {
									imgCycInstance.collectionPos = $(this).parents('li').index();
									if ($(this).hasClass('current')) {return;}
									imgCycInstance.imageSwap(this);
									return false;
								});
							};
							imgCycInstance.controls = function (context) {
								context = context || objInstance.zoomWindow;
								collectionLength = imgCycInstance.images.length;
								currentThumb = $(imgCycInstance.images.selector +'.current');
								imgCycInstance.collectionPos = currentThumb.parent().index()
								next = $('<a href="#" class="control next">next</a>');
								prev = $('<a href="#"  class="control prev">prev</a>');
								prev.bind('click.prev', function() {
									imgCycInstance.collectionPos--;
									imgCycInstance.collectionPos < 0 ? imgCycInstance.collectionPos = collectionLength - 1: null;
									imgCycInstance.images.removeClass('current');
									newPos = imgCycInstance.images.eq(imgCycInstance.collectionPos).addClass('current');
									imgCycInstance.imageSwap(newPos[0]);
//good for testing										console.log(imgCycInstance.collectionPos);
									if (objInstance.resetBtnHolder != null) {
										objInstance.resetBtnHolder.remove();
									}
									return false;
								});
								next.bind('click.next', function() {
									imgCycInstance.collectionPos++;
									imgCycInstance.collectionPos > collectionLength - 1 ? imgCycInstance.collectionPos = 0: null;
									imgCycInstance.images.removeClass('current');
									newPos = imgCycInstance.images.eq(imgCycInstance.collectionPos).addClass('current');
									imgCycInstance.imageSwap(newPos[0])
//good for testing									console.log(imgCycInstance.collectionPos);
									if (objInstance.resetBtnHolder != null) {
										objInstance.resetBtnHolder.remove();
									}
									return false;
								});
								context.append(next).prepend(prev);
							}
						};
						objInstance.mouseWheelFunc = function(event, delta) {
								if (-1 < objInstance.counter && objInstance.counter < objInstance.maxSteps + 1) {
									objInstance.wasCounter = objInstance.counter;
									objInstance.counter += delta;
									objInstance.counter < 0 ? objInstance.counter = 0: null;
									objInstance.counter > objInstance.maxSteps ? objInstance.counter = objInstance.maxSteps: null;
								}
								if (objInstance.counter > 0 && !$('a.reset').length) {
									objInstance.resetBtnHolder = objInstance.resetBtn();
									objInstance.zoomWindow.append(objInstance.resetBtnHolder);
								}
								if (objInstance.counter == 0 && $('a.reset').length && objInstance.resetBtnHolder != null) {
									objInstance.resetBtnHolder.remove();
								}
								if (objInstance.wasCounter != objInstance.counter) {
									objInstance.image.originalImage.height = objInstance.createIncrements().deltaIncrements.hArr[objInstance.counter];
									objInstance.image.originalImage.width = objInstance.createIncrements().deltaIncrements.wArr[objInstance.counter];
									objInstance.reposImageAccordingToMouse(objInstance.zoomWindow, image, event.pageX, event.pageY);
								}
								return false;
						};
						objInstance.attachMouseWheel = function () {
							$(objInstance.zoomWindow).bind('mousewheel', objInstance.mouseWheelFunc);
						};
						objInstance.detachMouseWheel = function () {
							$(objInstance.zoomWindow).unbind('mousewheel', objInstance.mouseWheelFunc);
						};
						objInstance.reposImageAccordingToMouse = function (container, zoomImage, leftPosition, topPosition) {
							var mouseXPosition = leftPosition - container.offset().left,
								mouseYPosition = topPosition - container.offset().top,
								zoomWindowWidth = container.width(),
								zoomWindowHeight = container.height(),
								imageWidth = objInstance.image.originalImage.width,
								imageHeight = objInstance.image.originalImage.height,
								newXPosition = Math.ceil(0 - ((mouseXPosition / zoomWindowWidth * imageWidth) - mouseXPosition)),
								newYPosition = Math.ceil(0 - ((mouseYPosition / zoomWindowHeight * imageHeight) - mouseYPosition));
							if(newXPosition>0){
								newXPosition = 0;
							}
							if(newYPosition>0){
								newYPosition = 0;
							}
							zoomImage.css({left:newXPosition+'px', top:newYPosition+'px'});
						};
						objInstance.mouseMoveSetup = function() {
							objInstance.zoomWindow.bind('mousemove.reposImage', function(e) {objInstance.reposImageAccordingToMouse(objInstance.zoomWindow, image, e.pageX, e.pageY)});
						};
						objInstance.setup = function() {
							objInstance.zoomWindow.addClass('mousewheel');
							objInstance.image.originalImage.src = objInstance.image.zoomableImage.src;
							objInstance.image.originalImage.height = objInstance.image.originalHeight;
							objInstance.image.originalImage.width = objInstance.image.originalWidth;
							objInstance.mouseMoveSetup();
						};
						objInstance.update = function(callback) {
							tempImgObj = new Image();
							tempImgObj.src = image.attr('src').replace(RegExp(standardExt,'i'), zoomExt);
							objInstance.image.zoomableImage.src = image.attr('src').replace(RegExp(standardExt,'i'), zoomExt);
							tempImgObj.onerror = function() {
								objInstance.image.zoomableImage.src = image.attr('src');
							};
						};
						objInstance.reset = function() {
							objInstance.image.originalImage.src = objInstance.image.zoomableImage.src;
							objInstance.image.originalImage.height = objInstance.image.originalHeight;
							objInstance.image.originalImage.width = objInstance.image.originalWidth;
							image.css({left:'0px', top:'0px'});
							objInstance.wasCounter = objInstance.counter = 0;
							if (objInstance.resetBtnHolder != null) {
								objInstance.resetBtnHolder.remove();
							};
						};
						objInstance.resetBtn = function() {
							var resetBtn = $('<a href="#" title="reset" class="control reset">reset</a>').bind('click.reset', function() {
								objInstance.reset();
								$(this).remove();
								return false;
							});
							return resetBtn;
						};
						objInstance.resetBtnClear = function() {
							if (objInstance.resetBtnHolder != null && (typeof objInstance.resetBtnHolder == "object")) {
								objInstance.resetBtnHolder.remove();
								objInstance.resetBtnHolder = null;
							}
						};
						objInstance.resetBtnHolder = null;
				}
				
				ContainedZoom = new ZoomController(MainImage, targetImage);
				MainImage.css('height', ContainedZoom.image.originalHeight + 'px');

				if (settings.Zoomable) {
				ContainedZoom.setup();
				}

				if (settings.ThumbnailsContainer.length) {
					ContainedZoomImages = new ContainedZoom.imageCycling();
					ContainedZoomImages.setup(settings.ThumbnailsContainer, targetImage);
					ContainedZoomImages.controls();
				}
				
				if (settings.Zoomable) {
					ContainedZoom.attachMouseWheel();
				
					$(this).bind('click.popUp' , popUp = function() { 
						var firstZoom = $(this);
						closeZoomFunc = function() {
							hideZoomDiv(zoomDiv, function() {
								zoomDiv.remove();
							});
							firstZoom.bind('click.popUp', popUp);
							ModalZoom.detachMouseWheel();
							ModalZoom.resetBtnClear();
							/*Important you have to re-assign the instance of the object back to the original Contained zoom to regain full control over it - not certain why but the instance seems to be a shared reference; the objects not truly separate instances*/
							objInstance = ContainedZoom;
							
							//ModalZoom = null;	//delete ModalZoom;
							
							ContainedZoom.attachMouseWheel();
							ContainedZoom.mouseMoveSetup();
							ContainedZoom.reset();
							showElementsToHide();
							if(pageCover.length) {
								pageCover.remove();
							}
							return false;
						}
						firstZoom.unbind('click.popUp');
						MainImage.unbind('mousemove.reposImage');
						ContainedZoom.detachMouseWheel();
						var pageCover = $('<div id="cover"/>').bind('click.closeZoom', closeZoomFunc);
						pageCover.insertAfter(MainImage);
						hideElementsToHide();
						ContainedZoom.reset();

						var zoomDiv = createZoomDiv(this);
						if (settings.ThumbnailsContainer.length) {
							var zoomThumbs = settings.ThumbnailsContainer.clone();
							zoomThumbs.appendTo(zoomDiv);
						}
						var popUpImg = zoomDiv.find('img.bigimg');
						
						showZoomDiv(zoomDiv);
						var ModalZoom = new ZoomController(zoomDiv, popUpImg);
						ModalZoom.image.originalHeight = Math.round((zoomDiv.width()/targetImage[0].width) * targetImage[0].height);
						ModalZoom.image.originalWidth = zoomDiv.width();
						ModalZoom.setup();
						if (settings.ThumbnailsContainer.length) {
							var thumbCollectionSelector = zoomThumbs[0].tagName.toLowerCase() +'.'+ $.trim(zoomThumbs[0].className.replace(new RegExp(" ", 'g'), "."));
							ModalZoomImages = new ModalZoom.imageCycling();
							/*This is to extend the  swap image functionality to pass the effect back to the original zoom;*/
							ModalZoomImages.imageSwap = function(hitImage, changeImage) {
								changeImage = changeImage || imgCycInstance.changeImage;
								imgCycInstance.images.removeClass('current');
								$(hitImage).addClass('current');
								changeImage.attr({ 'src': hitImage.src.replace(RegExp(thumbExt,'i'), standardExt),
									'alt': this.alt
								});
								targetImage.attr({ 'src': hitImage.src.replace(RegExp(thumbExt,'i'), standardExt),
									'alt': this.alt
								});

								currentPos = $(hitImage).parents('li').index();
								settings.ThumbnailsContainer.find('img').removeClass('current');
								settings.ThumbnailsContainer.children('li').eq(currentPos).children('img').addClass('current');
								objInstance.update();
								objInstance.reset();
							};
							ModalZoomImages.setup($(thumbCollectionSelector, '.zoomdiv'), popUpImg);						//ModalZoomImages.setup($('.images div.mousewheel ul.alternatives'), popUpImg);
							ModalZoomImages.controls();
						}
						ModalZoom.attachMouseWheel();
						zoomDiv.bind( 'click.moveWheel', function(event) {
								delta = 1;
								if (-1 < ModalZoom.counter && ModalZoom.counter < ModalZoom.maxSteps + 1) {
									ModalZoom.wasCounter = ModalZoom.counter;
									ModalZoom.counter += delta;
									ModalZoom.counter < 0 ? ModalZoom.counter = 0: null;
									ModalZoom.counter > ModalZoom.maxSteps ? ModalZoom.counter = ModalZoom.maxSteps: null;
								}
								if (ModalZoom.counter > 0 && !$('a.reset').length) {
									ModalZoom.resetBtnHolder = ModalZoom.resetBtn();
									ModalZoom.zoomWindow.append(ModalZoom.resetBtnHolder);
								}
								if (ModalZoom.counter == 0 && $('a.reset').length && ModalZoom.resetBtnHolder != null) {
									ModalZoom.resetBtnHolder.remove();
								}
								if (ModalZoom.wasCounter != ModalZoom.counter) {
									ModalZoom.image.originalImage.height = ModalZoom.createIncrements().deltaIncrements.hArr[ModalZoom.counter];
									ModalZoom.image.originalImage.width = ModalZoom.createIncrements().deltaIncrements.wArr[ModalZoom.counter];
									ModalZoom.reposImageAccordingToMouse(ModalZoom.zoomWindow, popUpImg, event.pageX, event.pageY);
								}
								return false;
							
						});
						//ModalZoom.reset();
						var closeZoomDiv = $('<a href="#" title="close" class="control close">close</a>').bind('click.closeZoom', closeZoomFunc);
						zoomDiv.append(closeZoomDiv);
					});
				}
			}
			
			if (!settings.Mousewheel) {
			$(MainImage).hoverIntent(function(){
		
				if (settings.HotSpot && !HotSpotHovered){
					return;
				}

				var imageLeft = $(this).offset().left,
					imageTop = $(this).offset().top,
					imageWidth = $(this).children('img').get(0).offsetWidth,
					imageHeight = $(this).children('img').get(0).offsetHeight;
					//var zoomDiv = $(this).parent().find('.zoomdiv');


				noalt= $(this).children("img").attr("alt");

				$(this).children("img").attr("alt",'');
				var zoomDiv = createZoomDiv(this);
				
				showZoomDiv(zoomDiv);

				//this determines whether the zoom pop up appears or just a cursor
				switch(settings.ZoomPup) {
				case "shadow":
					$(".jqZoomPup").addClass('shadow'); 
					break;
				case "cursor":
					$(".jqZoomPup").css('cursor','crosshair');
					break;
				}		
				
				
				if(!settings.lens){
					$(this).css('cursor','crosshair');
				}
				
				var zoomWidth = zoomDiv.width();
				var zoomHeight = zoomDiv.height();

				$(document.body).mousemove(function(e){

					var mouse = {
							x: e.pageX,
							y: e.pageY
						};

					var bigwidth = $(".bigimg").get(0).offsetWidth;
					var bigheight = $(".bigimg").get(0).offsetHeight;
					var scaley ='x';
					var scalex= 'y';

					if(isNaN(scalex)|isNaN(scaley)){

						var scalex = (bigwidth/imageWidth);

						var scaley = (bigheight/imageHeight);

						$("div.jqZoomPup").width(zoomWidth / scalex );

						$("div.jqZoomPup").height(zoomHeight / scaley);

						if(settings.lens){
							$("div.jqZoomPup").css('visibility','visible');
						}

					}

					xpos = mouse.x - $("div.jqZoomPup").width()/2 - imageLeft;

					ypos = mouse.y - $("div.jqZoomPup").height()/2 - imageTop ;

					if(settings.lens){

						xpos = (mouse.x - $("div.jqZoomPup").width()/2 < imageLeft ) ? 0 : (mouse.x + $("div.jqZoomPup").width()/2 > imageWidth + imageLeft ) ?  (imageWidth -$("div.jqZoomPup").width() -2)  : xpos;
						ypos = (mouse.y - $("div.jqZoomPup").height()/2 < imageTop ) ? 0 : (mouse.y + $("div.jqZoomPup").height()/2  > imageHeight + imageTop ) ?  (imageHeight - $("div.jqZoomPup").height() -2 ) : ypos;

					}

					if(settings.lens){

						$("div.jqZoomPup").css({ top: ypos,left: xpos });

					}

					scrolly = ypos;

					$("div.zoomdiv").get(0).scrollTop = scrolly * scaley;

					scrollx = xpos;

					$("div.zoomdiv").get(0).scrollLeft = (scrollx) * scalex ;

				});

				hideElementsToHide();
				
			},function(){

				$(this).children("img").attr("alt",noalt);
				$(document.body).unbind("mousemove");
				if(settings.lens){
					$("div.jqZoomPup").remove();
				}
				
				// this determines the way the zoom image disappears
				var zoomDiv = $("div.zoomdiv");
				hideZoomDiv(zoomDiv, function() {
					zoomDiv.remove();
				});

				
				showElementsToHide();

				
				if (settings.HotSpot){
					HotSpotHovered = false;
					HotSpotElem.fadeIn();
					ImageCover.show();
				}
			});
			}
			
            count = 0;

            if(settings.preload){

                $('body').append("<div style='display:none;' class='jqPreload"+count+"'></div>");

                $(this).each(function(){

                var imagetopreload= $(this).children("img").attr("src").replace(RegExp(standardExt, 'i'),'_xl.jpg');

                var content = jQuery('div.jqPreload'+count+'').html();

                jQuery('div.jqPreload'+count+'').html(content+'<img src=\"'+imagetopreload+'\">');

                });

            }

        }

        function MouseEvent(e) {
            this.x = e.pageX;
            this.y = e.pageY;
        }
	
		
		
})(jQuery);
