/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
//								Loupe jQuery Plugin 2011
//
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//-----------------------------------API VARS--------------------------------

(function($) {
  id = 0;
jQuery.fn.loupe_plugin = function(set) {

	id++;
	if (this.length > 1){
            this.each(function() { 
            	$(this).loupe_plugin(set)
            	 
            });
            return this;
        }
	
	set = $.extend({
		
				'trigger' : 'mouseenter',											// which evet triggers the loupe - mouseenter or click
				'shape' : 'circle',														// shape of loupe: 'circle', 'square', 'rounded'
				'rounded_corners' : 10,												// size of rounded corners in pixels - note!!! only applied for rounded shape
				'loupe_toggle_time' : 'medium',								// time used for fade in/out loupe animation
				'loupe_toggle_easing' : 'linear',							// easing used for loupe toggling
				'default_size'		: 200,											// size of loupe described in pixels -> size of squared div used as loupe area
				'min_size' : 150,															// minimum size of loupe
				'max_size' : 250,															// max size of loupe		
				'glossy' : true,															// applies glossy effect
				'drop_shadow' : true,													// loupe drops shadow
				'allow_resize' : true,												// allow loupe resize
				'size_snap' : 10,															// size snap described in pixels
				'resize_animation_time' : 'medium',						// time needed for loupe resize animation	
				'resize_animation_easing' : 'easeOutBack',		// easing used for resize animation
				'allow_zoom' : true,													// allow zoom
				'zoom_key' : 90,															// key used as zoom modifier - z = 90 charcode
				'default_zoom' : 100,													// default zoom described in percents of source image -> 100 stands for native image size
				'min_zoom' : 50,															// min zoom described in percents of source image -> 100 stands for native image size
				'max_zoom' : 200,															// max zoom described in percents of source image -> 100 stands for native image size
				'zoom_snap' : 5,															// snap used for zoom in/out operations in percents
				'zoom_animation_time' : 'medium',						  // time needed for loupe resize animation	
				'zoom_animation_easing' : 'easeOutBack',		  // easing used for resize animation
				'apply_overlay' : true,												// apply overlay for image
				'overlay_opacity' : 0.5,											// overlay opacity
				'overlay_effect_time' : 'slow',							  // time used for fade in/out overlay effect
				'overlay_effect_easing' : 'easeOutBack',			// easing used for overlay animation
				'overlay_class_name' : ''											// additional class name aplied to overlay div
				},
			set || {});


//-----------------------------------GLOBAL VARS--------------------------------
var $this = jQuery(this);
var this_id = 'loupe_plugin-' + id;
var this_overlay_id = 'loupe_overlay-' + id;												
var diameter = set.default_size;
var outer_size;
var loupe_image = null;
var thumb_width = 0;
var thumb_height = 0;
var image_width = 0;
var image_height = 0;
var current_width = 0;
var current_height = 0;
var zoom_pressed = false;
var is_active = false;
var current_zoom = set.default_zoom;
var back_pos_x = 0;
var back_pos_y = 0;
var target_image;
var old_msie = false;
//=================================FUNCTIONS==========================================================================
return this.each(function() {				
		                      
		function init_loupe() {
				if( $this.is('a') )
				  {
						loupe_image = $this.attr('href');
						target_image = $this.find('img');
					}	
				else if( $this.is('img') )
					{
					  loupe_image = $this.attr('src');
					  target_image = $this;
					}
					
				if( jQuery.browser.msie && ( parseInt(jQuery.browser.version, 10) < 9 ) )
				  {
				  	old_msie = true;
				  	current_zoom = 100;
				  }		
					
				thumb_width = target_image.width();
				thumb_height = target_image.height();	  		
												
				$('body').append("<div class='loupe_plugin' id='" + this_id + "'></div>");
																								
				var img = new Image();
				img.onload = function() {
					image_width = this.width; 
					image_height = this.height;
					
					current_width = Math.round( image_width * current_zoom / 100.0 );
					current_height = Math.round( image_height * current_zoom / 100.0 );
					
					var size = diameter / 2;
					  
					  $('#' + this_id).css({ 'width': diameter + "px", 
																	 'height': diameter + "px", 
																	 'background-image': 'url(' + loupe_image + ')',
																	 'background-size': current_width + 'px ' + current_height + 'px' });
																					    
						if( set.shape == 'circle' )
						  {	
						  	$('#' + this_id).css({ '-webkit-border-radius' : size + 'px',
																			 '-moz-border-radius' : size + 'px',
																			 'border-radius' : size + 'px' });
						  }
						else if( set.shape == 'rounded' )
							{
								$('#' + this_id).css({ '-webkit-border-radius' : set.rounded_corners,
																			 '-moz-border-radius' : set.rounded_corners,
																			 'border-radius' : set.rounded_corners + 'px' });
							}	  															    
																						
						outer_size = $('#' + this_id).outerWidth();
						
						if( set.glossy )
						  {
				    		$('#' + this_id).append("<div class='glossy'></div>");
				    	}
				    	
				    if( set.apply_overlay )
				      {
				      	$('body').append("<div class='overlay " + set.overlay_class_name + "' id='" + this_overlay_id + "'></div>");
				      	$('#' + this_overlay_id ).css({ 'top': target_image.offset().top + "px", 
																						    'left': target_image.offset().left + "px",
				      															    'width': target_image.outerWidth() + "px", 
																						    'height': target_image.outerHeight() + "px"
																									 });
																									 															 
				      }  		
				    	
				    if( set.drop_shadow )
				        $('#' + this_id).addClass('shadow');						  
				}
				img.src = loupe_image;																		  		
		}
		
		function apply_glossy() {
			  
			  var width = diameter - 2 * $('#' + this_id + ' .glossy').css('marginTop'); 
			  var height = diameter / 2;
			  
			  var cornertl = 0;
			  var cornertr = 0;
			  
			  if( set.shape == 'circle' )
					{	
						cornertl = height;
			  		cornertr = height;  	
					}
				else if( set.shape == 'rounded' )
					{
						var borderwidth = parseInt( $('#' + this_id).css('border-top-width') );
						
						cornertl = set.rounded_corners - borderwidth;
			  		//cornertr = parseInt( $('#' + this_id).css('border-top-right-radius') ) - borderwidth;
			  		cornertr = cornertl;
					}	
			  
			  $('#' + this_id + ' .glossy').stop();
			  $('#' + this_id + ' .glossy').animate({ 'width': width + 'px',
																				'height': height + 'px',
																				'-webkit-border-top-left-radius': cornertl + 'px',
																				'-webkit-border-top-right-radius': cornertr + 'px',
																				'-moz-border-radius-topleft': cornertl + 'px',
																				'-moz-border-radius-topright': cornertr + 'px',
																				'border-top-left-radius': cornertl + 'px',
																				'border-top-right-radius': cornertr + 'px' },
																				{queue: false, 
																				 easing: set.resize_animation_easing,
																				 duration: set.resize_animation_time }); 		
		}
		
		function handle_mousewheel(delta, event) {
			  if( zoom_pressed && set.allow_zoom ) {
			  	
			  	if( current_zoom + set.zoom_snap * delta > set.max_zoom ||
			  	    current_zoom + set.zoom_snap * delta < set.min_zoom )
			  	    return;
			  	    
			  	current_zoom += set.zoom_snap * delta;
			  	$('#log').text('zoom: ' + current_zoom);    
			  	
			  	current_width += Math.round( image_width * set.zoom_snap / 100 ) * delta;
			  	current_height += Math.round( image_height * set.zoom_snap / 100 ) * delta;
			  	
			  	var x_rel = event.pageX - this.offsetLeft;
	  			var y_rel = event.pageY - this.offsetTop;
	  			
	  			back_pos_x = Math.round( ( current_width / thumb_width ) * x_rel ) * -1 + diameter / 2;
	  			back_pos_y = Math.round( ( current_height / thumb_height ) * y_rel ) * -1 + diameter / 2;
	  			
	  			$('#' + this_id).animate({ 'background-position' : back_pos_x + 'px ' + back_pos_y + 'px',
	  																 'background-size': current_width + 'px ' + current_height + 'px'	},
	  																						{queue: false, 
																								 easing: set.zoom_animation_easing,
																								 duration: set.zoom_animation_time,
																								 complete:  function() {
																									  outer_size = $('#' + this_id).outerWidth();
																									  var new_mouse_x = x + outer_size / 2;
																									  var new_mouse_y = y + outer_size / 2;
																									  
																									  var e = new jQuery.Event("mousemove", { pageX: new_mouse_x, pageY: new_mouse_y});
																										$this.trigger( e );
																								 }
																								 });
			  }
			  else if( set.allow_resize && !zoom_pressed ){	
				  var diff = delta * set.size_snap;
				  
				  if( diameter + diff > set.max_size || diameter + diff < set.min_size )
			  	    return;
				  
				  diameter += diff;
				  var size = 0;
				  var x = Math.round ( $('#' + this_id).offset().left - diff  );
				  var y = Math.round ( $('#' + this_id).offset().top - diff  );
				  
				  back_pos_x += diff;
				  back_pos_y += diff;
				  
				  $('#' + this_id).stop();
				  
				  if( set.shape == 'circle' )
						{	
						  	size = diameter / 2;
						  	$('#' + this_id).animate({ 'width': diameter + "px", 
																		 'height': diameter + "px",
																		 '-webkit-border-top-left-radius': size + 'px',
																		 '-webkit-border-top-right-radius': size + 'px',
																		 '-webkit-border-bottom-left-radius': size + 'px',
																		 '-webkit-border-bottom-right-radius': size + 'px',
																		 '-moz-border-radius-topleft': size + 'px',
																		 '-moz-border-radius-topright': size + 'px',
																		 '-moz-border-radius-bottomleft': size + 'px',
																		 '-moz-border-radius-bottomright': size + 'px',
																		 'border-top-left-radius': size + 'px',
																		 'border-top-right-radius': size + 'px',
																		 'border-bottom-left-radius': size + 'px',
																		 'border-bottom-right-radius': size + 'px',
																		 'background-position' : back_pos_x + 'px ' + back_pos_y + 'px',
																								'left': x + 'px', 
																								'top': y + 'px' }, 
																								{queue: false, 
																								 easing: set.resize_animation_easing,
																								 duration: set.resize_animation_time,
																								 complete:  function() {
																									  outer_size = $('#' + this_id).outerWidth();
																									  var new_mouse_x = x + outer_size / 2;
																									  var new_mouse_y = y + outer_size / 2;
																									  
																									  var e = new jQuery.Event("mousemove", { pageX: new_mouse_x, pageY: new_mouse_y});
																										$this.trigger( e );
																								 }
																								 });
						}
				  else if( set.shape == 'rounded' )
					  {
								$('#' + this_id).animate({ 'width': diameter + "px", 
																					 'height': diameter + "px",
																					 '-webkit-border-radius' : set.rounded_corners,
																					 '-moz-border-radius' : set.rounded_corners,
																					 'border-radius' : set.rounded_corners,
																					 'background-position' : back_pos_x + 'px ' + back_pos_y + 'px',
																					 'left': x + 'px', 
																					 'top': y + 'px' }, 
																								{queue: false, 
																								 easing: set.resize_animation_easing,
																								 duration: set.resize_animation_time,
																								 complete:  function() {
																									  outer_size = $('#' + this_id).outerWidth();
																									  var new_mouse_x = x + outer_size / 2;
																									  var new_mouse_y = y + outer_size / 2;
																									  
																									  var e = new jQuery.Event("mousemove", { pageX: new_mouse_x, pageY: new_mouse_y});
																										$this.trigger( e );
																								 }
																								 });											 
						}
					else if( set.shape == 'square' )
						{
							  $('#' + this_id).animate({ 'width': diameter + "px", 
																					 'height': diameter + "px",
																					 'background-position' : back_pos_x + 'px ' + back_pos_y + 'px',
																					 'left': x + 'px', 
																					 'top': y + 'px' }, 
																								{queue: false, 
																								 easing: set.resize_animation_easing,
																								 duration: set.resize_animation_time,
																								 complete:  function() {
																									  outer_size = $('#' + this_id).outerWidth();
																									  var new_mouse_x = x + outer_size / 2;
																									  var new_mouse_y = y + outer_size / 2;
																									  
																									  var e = new jQuery.Event("mousemove", { pageX: new_mouse_x, pageY: new_mouse_y});
																										$this.trigger( e );
																								 }
																								 });
						}		
																						
					if( set.glossy )
					 apply_glossy();
				} 																	
		}		
//=================================END OF FUNCTIONS==========================================================================	

		if (jQuery.browser.webkit && document.readyState != "complete"){
		    setTimeout( arguments.callee, 100 );
		    return;
    } 

//=================================MAIN======================================================================================		
		init_loupe();								
//================================END OF MAIN=====================================================================		
		

//================================EVENT HANDLERS==================================================================
		
		if( ( set.allow_resize || set.allow_zoom ) && !old_msie && $.event.special.mousewheel )
		  {
				$('#' + this_id).bind('mousewheel', function(event, delta) {
		            handle_mousewheel(delta, event);
		            return false;
		        });
		  }      
		
		target_image.bind(set.trigger,
		    function (event, source) {
		    	  
		    	  if( !is_active )
		    	    {
				    	  $('#' + this_id).fadeIn(set.loupe_toggle_time, set.loupe_toggle_easing);
				    	  is_active = true;
				    	  
				    	  if( set.apply_overlay )
						      {
						      	$('#' + this_overlay_id ).fadeTo(set.overlay_effect_time, set.overlay_opacity, set.overlay_effect_easing);															 
						      }
						      
						    apply_glossy();  
				    	}
				    else
				    	{
				    		$('#' + this_id).fadeOut(set.loupe_toggle_time, set.loupe_toggle_easing);
				    	  is_active = false;
				    	  if( set.apply_overlay )
						      {
						      	$('#' + this_overlay_id ).fadeOut(set.overlay_effect_time, set.overlay_effect_easing);															 
						      }
				    	}		  
		    	  
 
				    if( event.type == 'click' )
				      {
				      	if (event.preventDefault)
				        		event.preventDefault();
						    else
						        event.returnValue= false;
						    return false;
				      }	  	    								 
		    }
		);
		
		$('#' + this_id).bind('click',
			function (event) {
  				target_image.trigger('click');	
 			}						        								 
		);
		
		$(document).bind('mousemove',
			function (event) {
  			if( !is_active )
            return true;
  			
  			var left_spacer = parseInt( target_image.css('border-left-width') ) + parseInt( target_image.css('padding-left') );
  			var top_spacer = parseInt( target_image.css('border-top-width') ) + parseInt( target_image.css('padding-top') );
  			var right_spacer = parseInt( target_image.css('border-right-width') ) + parseInt( target_image.css('padding-right') );
  			var bottom_spacer = parseInt( target_image.css('border-bottom-width') ) + parseInt( target_image.css('padding-bottom') );
  			
  			var x_rel = event.pageX - target_image.offset().left - left_spacer;
  			var y_rel = event.pageY - target_image.offset().top - top_spacer;
  			
  			var x = Math.round(  event.pageX - outer_size / 2  );
  			var y = Math.round(  event.pageY - outer_size / 2  );
  			
  			back_pos_x = Math.round( ( current_width / thumb_width ) * x_rel ) * -1 + diameter / 2;
  			back_pos_y = Math.round( ( current_height / thumb_height ) * y_rel ) * -1 + diameter / 2;
  			
  			$('#' + this_id).css({ 'background-position' : back_pos_x + 'px ' + back_pos_y + 'px'});  			
  			
  			$('#' + this_id).css({ 'left': x + 'px', 'top': y + 'px' });
  			  			
  			if( x_rel < -left_spacer || y_rel < -top_spacer || x_rel > thumb_width + right_spacer || y_rel > thumb_height + bottom_spacer )
  			  {
  			   $('#' + this_id).fadeOut(set.loupe_toggle_time);
  			   is_active = false;
  			   
  			   if( set.apply_overlay )
				      {
				      	$('#' + this_overlay_id ).fadeOut(set.overlay_effect_time);															 
				      }	
  			  } 		
 			}						        								 
		);
	 
	  $(document).keyup(function (event) {
			if( event.which == set.zoom_key && is_active)
			  { 
			   zoom_pressed=false;
			   if (event.preventDefault)
        		event.preventDefault();
		     else
		        event.returnValue= false;
		     return false;
		      
			  }   
	  }).keydown(function (event) {
			if( event.which == set.zoom_key && is_active)
			  { 
			   zoom_pressed=true;
				 if (event.preventDefault)
        		event.preventDefault();
		     else
		        event.returnValue= false;
		     return false;
				}     
		});  		
//================================END OF EVENT HANDLERS==================================================================		
});

};
})(jQuery);		
