﻿/**
* jQuery Magnifier Plugin
* 
* @version 0.2
* @author Dieter Orens dieter@dio5.com
* 
* @option Number lensWidth -  width of the lens 
* @option Number lensHeight - height of the lens
* @option Boolean link - makes clicking go to the large image (default:true)
* @option Number delay - adds a delay to the appearing of the lens (default:0)
* 
*/
(function($) {
    $.extend($.fn,
	{
	    magnify: function(options) {
	        return this.each(function() {
	            var magnifier =
				{
				    defaults:
					{
					    lensWidth: 160,
					    lensHeight: 160,
					    link: true,
					    delay: 0
					},

				    a: null,
				    $img: null,
				    $largeImage: null,
				    $lens: null,
				    $sensor: null,
				    $loader: null,
				    timeOut: null,
				    largeWidth: 0,
				    largeHeight: 0,

				    init: function(options) {
				        magnifier.options = $.extend({}, magnifier.defaults, options);
				        magnifier.a = this;
				        magnifier.$img = $('img', this);
				        magnifier.setLargeImage();
				        magnifier.setLens();
				        magnifier.setSensor();
				        magnifier.setLoader();
				        magnifier.loadImage();
				        magnifier.addHandles();
				    },

				    setLargeImage: function() {
				        magnifier.$largeImage = $(new Image());
				        magnifier.$largeImage.attr('src', magnifier.a.href).css('display', 'none');
				    },

				    setLens: function() {
				        magnifier.$lens = $("<div id='dio-lens'></div>");
				        magnifier.$lens.css({
				            width: magnifier.options.lensWidth,
				            height: magnifier.options.lensHeight,
				            visibility: 'hidden',
				            overflow: 'hidden',
				            position: 'absolute',
				            left: 0,
				            top: 0
				        }).appendTo('body');
				    },

				    setSensor: function() {
				        magnifier.$sensor = $("<div id='dio-sensor' style='position:absolute;'></div>");
				        $('body').append(magnifier.$sensor);

				        if (magnifier.options.link) {
				            magnifier.$sensor.click(function() { window.location = magnifier.a.href });
				        }
				    },

				    setLoader: function() {
				        magnifier.$loader = $("<div id='dio-loader'>loading</div>").css({ width: magnifier.options.lensWidth, height: magnifier.options.lensHeight });
				        magnifier.$lens.append(magnifier.$loader);
				    },

				    loadImage: function() {

				        magnifier.$largeImage.load(function(e) {
				            magnifier.imgLoadCheck(magnifier.$largeImage[0], magnifier.loadCallback, magnifier.errorCallback, e);
				        });
				    },

				    imgLoadCheck: function(img, loadCallback, errorCallback) {
				        if (img != null) {
				            function imgWatch() {
				                if (img.complete) {
				                    clearInterval(loadWatch);
				                    loadCallback();
				                }
				            }
				            var loadWatch = setInterval(imgWatch, 100);
				        }
				        else {
				            errorCallback();
				        }
				    },

				    loadCallback: function() {
				        magnifier.$lens.append(magnifier.$largeImage);

				        function moveWatch() {
				            if (magnifier.$largeImage.width()) {
				                magnifier.largeWidth = magnifier.$largeImage.width();
				                magnifier.largeHeight = magnifier.$largeImage.height();
				            }
				            if (magnifier.largeWidth) {
				                magnifier.$loader.remove();
				                clearInterval(moveID);
				            }
				        }
				        var moveID = setInterval(moveWatch, 100);
				    },

				    errorCallback: function() {
				        alert("large image could not be loaded");
				    },

				    addHandles: function() {
				        magnifier.$sensor.css(
						{
						    width: magnifier.$img.width() + "px",
						    height: magnifier.$img.height() + "px",
						    top: magnifier.$img.offset().top + "px",
						    left: magnifier.$img.offset().left + "px",
						    backgroundColor: "#fff",
						    opacity: "0"
						})
						.mousemove(function(e) { magnifier.handleMouseMove(e); })
						.mouseout(function(e) { magnifier.handleMouseOut(e); });
				    },

				    handleMouseMove: function(e) {
				        magnifier.$lens.css({
				            left: parseInt(e.pageX - (magnifier.options.lensWidth * .5)) + "px",
				            top: parseInt(e.pageY - (magnifier.options.lensHeight * .5)) + "px"
				        });


				        if (magnifier.options.delay) {
				            if (!magnifier.timeOut) {
				                magnifier.timeOut = setTimeout(function() {
				                    magnifier.$lens.css('visibility', 'visible');
				                }, magnifier.options.delay);
				            }
				        }
				        else {
				            magnifier.$lens.css('visibility', 'visible');
				        }

				        if (magnifier.largeWidth) { magnifier.positionLargeImage(e); }

				        magnifier.$lens.css('display', 'block');
				    },

				    positionLargeImage: function(e) {
				        var scale = {};

				        scale.x = magnifier.largeWidth / magnifier.$img.width();
				        scale.y = magnifier.largeHeight / magnifier.$img.height();

				        var left = -scale.x * Math.abs((e.pageX - magnifier.$img.offset().left)) + magnifier.options.lensWidth / 2 + "px";
				        var top = -scale.y * Math.abs((e.pageY - magnifier.$img.offset().top)) + magnifier.options.lensHeight / 2 + "px";

				        magnifier.$largeImage.css(
						{
						    position: 'absolute',
						    left: left,
						    top: top,
						    display: 'block'
						});
				    },

				    handleMouseOut: function(e) {
				        if (magnifier.timeOut) {
				            clearTimeout(magnifier.timeOut);
				            magnifier.timeOut = null;
				        }
				        magnifier.$lens.css({
				            visibility: 'hidden',
				            display: 'none'
				        });
				    }
				};

	            magnifier.init.call(this, options);
	        });
	    }
	});
})(jQuery);
