(function($) 
{
  
  $.__getCache = {};
  $.getCached = function(url, data, callback, type )
  {
    if(!data)
    {
      data = {}; 
    }
    if(!type)
    {
      type = null;
    }
    if(!callback)
    {
      return;
    }
    
    var key = url + '.' +type;
    
    if($.__getCache[key])
    {
      callback($.__getCache[key]); 
      return;
    }
    
    $.get(url,data,function(data)
    {
      $.__getCache[key] = data;
      callback($.__getCache[key]);  
    },type);
  }

   $.fn.preview = function(settings) 
   {

     var currentPreview = null;
     var currentTarget = null;
     var currentX = 0;
     var currentY = 0;
     
     var config = 
     {
         'url': '',
         'xOffset' : 15,
         'yOffset' : 15
     };
     
     function getPositionCss()
     {
       var arr = 
       {
         'position' : 'fixed',
         'top'      : currentY + config.yOffset - $(window).scrollTop() + 'px',
         'left'     : currentX + config.xOffset - $(window).scrollLeft() + 'px',
         'z-index'  : 666     
       };
       return arr;
     }
     
     if (settings) $.extend(config, settings);
 
     this.each(function() 
     {
       if(config.url == '')
       {
         return;
       }

       // element-specific code here
       $($(this)).hover(
       function(e)
       {
         $('.__preview-obj').remove();
         //mouse in code
         currentX = e.pageX;
         currentY = e.pageY;
         var target = this;
         currentTarget = this;
         
         $.getCached(config.url,{}, function(data)
         {
           if(currentTarget == target)
           {
             var obj = $(data);
             obj.hide();
             obj.addClass('__preview-obj');
             obj.appendTo('body');
             var imageCounter = obj.find('img').length;
             var completed = true;
             
             //the completed flag checking is needed when data is loaded from client cache, img load event is not fired up
             obj.find('img').each(function()
             {
               if(this.complete === false)
               {
                 completed = false;
               }
             });
             
             if(completed)
             {
               if(imageCounter > 0)
               {
                 imageCounter--; 
               }
               
               if(currentTarget == target && imageCounter == 0)
               {
                 obj.css(getPositionCss()).fadeIn('fast');
                 currentPreview = obj;
               }
             }
             else
             {
               obj.find('img').load(function()
               {
                 if(currentTarget == target && --imageCounter == 0)
                 {
                   obj.css(getPositionCss()).fadeIn('fast');
                   currentPreview = obj;
                 }
               });
             }
           }
         });
       },
       function()
       {
         //mouse out code
         $('.__preview-obj').remove();
         currentTarget = null;
       }).mousemove(
       function(e)
       {
         currentX = e.pageX;
         currentY = e.pageY;
         currentTarget = this;
         //mouse move code
         if(currentPreview)
         {
           currentPreview.removeClass('__preview-obj');
           $('.__preview-obj').remove();
           currentPreview.addClass('__preview-obj');
           
           currentPreview.css(getPositionCss());//.fadeIn('fast');
         }
       }); 
     
     });
 
     return this;
   };
 
 })(jQuery);

