/**
 Based on Cloud Zoom V1.0.2 by R Cecco <http://www.professorcloud.com>, 2010.
 Released under MIT License

 Mousestop event idea from R Scarrot <http://www.richardscarrot.co.uk>, 2010.
 
 Updated by M Hinchliffe for Design UK <http://www.designuk.com>, 2010
 Features removed:- soft focus, outer focus tint, galleries, inline options
 Features added:- toggle to activate, toggle button
 **/
(function($) {

	function format(str)
	{
		for (var i = 1; i < arguments.length; i++)
		{
			str = str.replace('%' + (i - 1), arguments[i]);
		}
		return str;
	}

	function CloudZoom(jWin, opts)
	{
		var sImg = $('img', jWin),
			img1,
			img2,
			zoomDiv = null,
			$mouseTrap = null,
			lens = null,
			toggle = null,
			$ie6Fix = null,
			zoomImage,
			controlTimer = 0,
			cw,
			ch,
			destU = 0,
			destV = 0,
			currU = 0,
			currV = 0,
			filesLoaded = 0,
			timeout,
			active,
			mx,
			my,
			ctx = this,
			zw;

		// Display an image loading message.
		// We add a small delay before the message is displayed to avoid the message flicking on then off again images load really fast
		setTimeout(function()
		{
			if ($mouseTrap === null)
			{
				var w = jWin.width();
				jWin.parent().append(format('<div style="width:%0px;position:absolute;top:75%;left:%1px;text-align:center" class="cloud-zoom-loading" >Loading&hellip;</div>', w / 3, (w / 2) - (w / 6))).find(':last').css('opacity', 0.5);
			}
		}, 200);

		// Remove IE6 iframe fix
		var ie6FixRemove = function()
		{
			if ($ie6Fix !== null)
			{
				$ie6Fix.remove();
				$ie6Fix = null;
			}
		};

		// Removes zoom cursor
		this.removeBits = function()
		{
			if (lens)
			{
				lens.remove();
				lens = null;
			}
			ie6FixRemove();
			$('.cloud-zoom-loading', jWin.parent()).remove();
		};

		// Remove entire cloud zoom
		this.destroy = function()
		{
			jWin.data('zoom', null);
			if ($mouseTrap)
			{
				$mouseTrap.unbind().remove();
				$mouseTrap = null;
			}
			if (zoomDiv)
			{
				zoomDiv.remove();
				zoomDiv = null;
			}
			this.removeBits();
		};

		// This is called when the zoom window has faded out so it can be removed.
		this.fadedOut = function()
		{
			if (zoomDiv)
			{
				zoomDiv.remove();
				zoomDiv = null;
			}
			this.removeBits();
		};

		// Move lens and large image
		this.controlLoop = function()
		{
			if (lens)
			{
				var x = (mx - sImg.offset().left - (cw * 0.5)) >> 0,
				    y = (my - sImg.offset().top - (ch * 0.5)) >> 0;

				if (x < 0)
					x = 0;
				else if (x > (sImg.outerWidth() - cw))
					x = (sImg.outerWidth() - cw);

				if (y < 0)
					y = 0;
				else if (y > (sImg.outerHeight() - ch))
					y = (sImg.outerHeight() - ch);

				lens.css({ left: x, top: y });
				lens.css('background-position', (-x) + 'px ' + (-y) + 'px');

				destU = (((x) / sImg.outerWidth()) * zoomImage.width) >> 0;
				destV = (((y) / sImg.outerHeight()) * zoomImage.height) >> 0;
				currU += (destU - currU) / opts.smoothMove;
				currV += (destV - currV) / opts.smoothMove;

				zoomDiv.css('background-position', (-(currU >> 0) + 'px ') + (-(currV >> 0) + 'px'));
			}
			controlTimer = setTimeout(function()
			{
				ctx.controlLoop();
			}, 30);
		};

		this.init2 = function(img, id)
		{
			filesLoaded++;
			if (id === 1)
				zoomImage = img;

			if (filesLoaded === 2)
				this.init();
		};

		// Toggle active boolean
		this.toggleActive = function()
		{
			if (active)
			{
				$mouseTrap.attr('title', 'Click to start zoom');
				
				if (toggle)
					toggle.text('Start Zoom').parent().removeClass('active');

				if (lens)
					$mouseTrap.trigger('mouseleave');
			}
			else
			{
				$mouseTrap.attr('title', 'Click to stop zoom');
				
				if (toggle)
					toggle.text('Stop Zoom').parent().addClass('active');
			}
			active = active ? false : true;
		};

		// Init function start
		this.init = function()
		{
			// Remove loading message (if present);
			$('.cloud-zoom-loading', jWin.parent()).remove();

			// Add a box (mouseTrap) over the small image to trap mouse events across browsers.
			$mouseTrap = jWin.parent().append(format("<div class='mousetrap' style='background-image:url(\".\");z-index:999;position:absolute;width:%0px;height:%1px;left:%2px;top:%3px;\' title='Click to start zoom'></div>", sImg.outerWidth(), sImg.outerHeight(), 0, 0)).find(':last');

			active = opts.activeOnStart;

			// Click to activate zoom
			if (opts.clickToActivate)
			{
				// Add an external toggle button
				if (opts.addToggle)
				{
					if ($('.zoom-toggle a', jWin.parent()).length > 0)
						toggle = $('.zoom-toggle a', jWin.parent());
					else
						toggle = jWin.parent().append('<div class="zoom-toggle"><a href="#">Start Zoom</a></div>').find('.zoom-toggle a').first();
					
					if (active)
						toggle.parent().removeClass('active').addClass('active');
					else
						toggle.parent().removeClass('active');

					toggle.bind('click', function(e)
					{
						e.preventDefault();
						ctx.toggleActive();
					});
				}

				$mouseTrap.bind('click', this, function(e)
				{
					ctx.toggleActive();
					if (!lens)
						$mouseTrap.trigger('mousestop');
				});
			}

			// Bind events to mouse trap
			$mouseTrap.bind('mousemove', this, function(e)
			{
				mx = e.pageX;
				my = e.pageY;
				if (timeout)
					clearTimeout(timeout);
			})
			.bind('mouseleave', this, function(e)
			{
				if (zoomDiv && active)
				{
					$(e.target).removeData('mousestop');
					clearTimeout(controlTimer);

					if (timeout)
						clearTimeout(timeout);

					if (lens)
						lens.fadeOut(299);

					zoomDiv.fadeOut(300, function()
					{
						ctx.fadedOut();
					});
					$mouseTrap.css('cursor', 'pointer');
				}
			})
			.bind('mouseenter', this, function(e)
			{
				mx = e.pageX;
				my = e.pageY;
				zw = e.data;
			})
			.bind('mousemove', this, function(e)
			{
				mx = e.pageX;
				my = e.pageY;

				// Only start zoom if status is active and mouse stops
				if (!zoomDiv && active)
				{
					clearTimeout(timeout);
					timeout = setTimeout(function()
					{
						$(e.target).trigger('mousestop');
					}, opts.mousestopDelay);
				}
			})
			.bind('mousestop', this, function(e)
			{
				// Clear mouse stop
				if (timeout)
					clearTimeout(timeout);

				// clean up any left overs
				if (zoomDiv) {
					zoomDiv.stop(true, false);
					zoomDiv.remove();
				}

				if (lens) {
					lens.remove();
					lens = null;
				}

				var xPos = opts.adjustX,
					yPos = opts.adjustY,
					siw = sImg.outerWidth(),
					sih = sImg.outerHeight(),
					w = opts.zoomWidth,
					h = opts.zoomHeight;

				if (opts.zoomWidth == 'auto')
					w = siw;

				if (opts.zoomHeight == 'auto')
					h = sih;

				var appendTo = jWin.parent();

				switch (opts.position)
				{
					case 'top':
						yPos -= h;
						break;
					case 'right':
						xPos += siw;
						break;
					case 'bottom':
						yPos += sih;
						break;
					case 'left':
						xPos -= w;
						break;
					case 'inside':
						w = siw;
						h = sih;
						break;
					default:
						appendTo = $('#' + opts.position);
						if (!appendTo.length)
						{
							appendTo = jWin;
							xPos += siw;
							yPos += sih;
						}
						else
						{
							w = appendTo.innerWidth();
							h = appendTo.innerHeight();
						}
				}
				zoomDiv = appendTo.append(format('<div id="cloud-zoom-big" class="cloud-zoom-big" style="display:none;position:absolute;left:%0px;top:%1px;width:%2px;height:%3px;background-image:url(\'%4\');z-index:99;"></div>', xPos, yPos, w, h, zoomImage.src)).find(':last');

				// Add the title from title tag.
				if (sImg.attr('title') && opts.showTitle)
					zoomDiv.append(format('<div class="cloud-zoom-title">%0</div>', sImg.attr('title'))).find(':last').css('opacity', opts.titleOpacity);

				// Fix ie6 select elements wrong z-index bug. Placing an iFrame over the select element solves the issue...
				if ($.browser.msie && $.browser.version < 7)
				{
					$ie6Fix = $('<iframe frameborder="0" src="#"></iframe>').css({
						position: "absolute",
						left: xPos,
						top: yPos,
						zIndex: 99,
						width: w,
						height: h
					}).insertBefore(zoomDiv);
				}

				zoomDiv.fadeIn(500);

				// Work out size of cursor
				cw = (sImg.outerWidth() / zoomImage.width) * zoomDiv.width();
				ch = (sImg.outerHeight() / zoomImage.height) * zoomDiv.height();

				// Attach mouse, initially invisible to prevent first frame glitch
				lens = jWin.append(format("<div class='cloud-zoom-lens' style='display:none;z-index:98;position:absolute;width:%0px;height:%1px;'></div>", cw, ch)).find(':last');

				$mouseTrap.css('cursor', lens.css('cursor'));

				var noTrans = false;
				if (!noTrans)
					lens.css('opacity', opts.lensOpacity);

				if (opts.position !== 'inside')
					lens.fadeIn(500);

				zw.controlLoop();
			});
		};

		// Attach load listener to images
		img1 = new Image();
		$(img1).load(function()
		{
			ctx.init2(this, 0);
		});
		img1.src = sImg.attr('src');

		img2 = new Image();
		$(img2).load(function()
		{
			ctx.init2(this, 1);
		});
		img2.src = jWin.attr('href');

		return;
	}

	$.fn.CloudZoom = function(options)
	{
		// IE6 background image flicker fix
		try {
			document.execCommand("BackgroundImageCache", false, true);
		}
		catch (e) {}

		this.each(function()
		{
			$(this).css({
				'position': 'relative',
				'display': 'block'
			});
			$('img', $(this)).css({ 'display': 'block' });

			// Wrap an outer div around the link so we can attach things without them becoming part of the link.
			if (!$(this).parent().hasClass('cloud-wrap'))
				$(this).wrap('<div class="cloud-wrap" style="top:0;z-index:100;position:relative;"></div>');

			var opts = $.extend({}, $.fn.CloudZoom.defaults, options);
			$(this).data('zoom', new CloudZoom($(this), opts));
		});
		return this;
	};

	$.fn.CloudZoom.defaults = {
		zoomWidth: 436,
		zoomHeight: 'auto',
		position: 'right',
		lensOpacity: 0.5,
		smoothMove: 10,
		showTitle: false,
		titleOpacity: 0,
		adjustX: 12,
		adjustY: -1,
		mousestopDelay: 50,
		activeOnStart: false,
		addToggle: true,
		clickToActivate: true
	};
})(jQuery);

$(function()
{
	$('a.cloud-zoom').CloudZoom();
});
