$(function(){

	$.zoomable = function(options){

		if(/MSIE 6/i.test(navigator.userAgent)) return false;

		var settings = {
			container			: 'body',
			magnifier_id		: 'magnifier',
			placeholder_id		: 'placeholder',
			cover_id			: 'cover',
			loading_id			: 'loading',
			placeholder_border	: 0,
			ratio_modifier		: 1
		};

		(! options) || $.extend(settings, options);

		var $magnifier		= $('<div id="' + settings.magnifier_id + '"></div>'),
			$placeholder	= $('<div id="' + settings.placeholder_id + '"></div>'),
			$cover			= $('<div id="' + settings.cover_id + '" style="* background: #FFF; * filter: alpha(opacity=0);"></div>'),
			$loading		= $('<div id="' + settings.loading_id + '">Loading Magnifier...</div>'),
			$container		= $(settings.container),
			$zoom			= false,
			$body			= $('body').eq(0),
			values			= {},
			is_loaded		= false,
			url				= false,
			loading_timer	= false,
			cache			= Array(),

			calculate_placeholder_position = function(e){

				values.placeholder.left	= Math.ceil(e.pageX - (values.placeholder.width		/ 2));
				values.placeholder.top	= Math.ceil(e.pageY - (values.placeholder.height	/ 2));

				if(values.placeholder.left < values.original.left)
				{
					values.placeholder.left = values.original.left;
				}
				else if((values.placeholder.left + values.placeholder.width) > (values.original.left + values.original.width))
				{
					values.placeholder.left = Math.ceil(values.original.left + values.original.width - values.placeholder.width);
				}

				if(values.placeholder.top < values.original.top)
				{
					values.placeholder.top = values.original.top;
				}
				else if((values.placeholder.top + values.placeholder.height) > (values.original.top + values.original.height))
				{
					values.placeholder.top = Math.ceil(values.original.top + values.original.height - values.placeholder.height);
				}

			},
			
			calculate_image_position = function(e){

				values.zoom.left	= Math.ceil((e.pageX - values.original.center.left)	* values.ratio.x);
				values.zoom.top		= Math.ceil((e.pageY - values.original.center.top)	* values.ratio.y);

				(values.zoom.left	< values.threshold.left)		|| (values.zoom.left = values.threshold.left);
				(values.zoom.top	< values.threshold.top)			|| (values.zoom.top = values.threshold.top);
				(values.zoom.left	> values.threshold.left * -1)	|| (values.zoom.left = values.threshold.left * -1);
				(values.zoom.top	> values.threshold.top * -1)	|| (values.zoom.top = values.threshold.top * -1);

			};

		$magnifier.hide().appendTo($container);

		$body
			.delegate('[data-zoom]', 'mousemove', function(e){
				var $this = $(this);

				url = $this.attr('data-zoom');

				values.original = {
					top			: $this.offset().top,
					left		: $this.offset().left,
					width		: $this.outerWidth(),
					height		: $this.outerHeight()
				};

				$cover.css({
					'top'		: values.original.top,
					'left'		: values.original.left,
					'width'		: values.original.width,
					'height'	: values.original.height
				});

				$body.append($cover);
			})
			.delegate('#cover', 'mouseover', function(e){
				if(typeof cache[url] == 'undefined')
				{
					$loading.css({
						'top'		: Math.ceil(values.original.top + (values.original.height / 2)),
						'left'		: Math.ceil(values.original.left + (values.original.width / 2))
					});

					$body.append($loading);

					$loading.css({
						'margin-top'	: ($loading.height() / 2) * -1,
						'margin-left'	: ($loading.width() / 2) * -1
					});
				}
				$zoom = $(document.createElement('img'));
				$zoom.load(function(){
					cache[url] = true;
					$loading.remove();
					$magnifier.append($zoom).show(0, function(){

						values.zoom = {
							width	: $zoom.outerWidth(),
							height	: $zoom.outerHeight()
						};

						values.magnifier = {
							width	: $magnifier.width(),
							height	: $magnifier.height()
						};

						values.original.center = {
							top		: values.original.top	+ (values.original.height	/ 2),
							left	: values.original.left	+ (values.original.width	/ 2)
						};

						values.threshold = {
							top		: ((values.zoom.height	- values.magnifier.height)	/ 2),
							left	: ((values.zoom.width	- values.magnifier.width)	/ 2)
						};

						values.ratio = {
							x		: (values.zoom.width	/ values.original.width) * settings.ratio_modifier,
							y		: (values.zoom.height	/ values.original.height) * settings.ratio_modifier
						};

						values.placeholder = {
							width	: (values.magnifier.width	/ values.ratio.x),
							height	: (values.magnifier.height	/ values.ratio.y)
						};

						(values.magnifier.width		<= values.zoom.width)	|| $magnifier.css('width',	values.zoom.width);
						(values.magnifier.height	<= values.zoom.height)	|| $magnifier.css('height',	values.zoom.height);

						$zoom.css({
							left:	values.threshold.left	* -1,
							top:	values.threshold.top	* -1
						});

						calculate_placeholder_position(e);

						$placeholder.css({
							'left'		: values.placeholder.left,
							'top'		: values.placeholder.top,
							'width'		: values.placeholder.width - (settings.placeholder_border * 2),
							'height'	: values.placeholder.height - (settings.placeholder_border * 2)
						});

						$body.append($placeholder);

						is_loaded = true;
					});
				});
				$zoom.attr('src', url);
			})
			.delegate('#cover', 'mousemove', function(e){

				if(! is_loaded){
					return false;
				}

				calculate_placeholder_position(e);
				calculate_image_position(e);

				$placeholder.css({
					'left'	: values.placeholder.left,
					'top'	: values.placeholder.top
				});

				$zoom.css({
					'margin-left'	: (values.zoom.left * -1),
					'margin-top'	: (values.zoom.top * -1)
				});

			})
			.delegate('#cover', 'mouseout', function(){
				$magnifier.hide();
				$cover.remove();
				$placeholder.remove();
				$zoom.remove();
				$loading.remove();
				is_loaded = false;
			});

	};

});
