(function($)
{
 var defaultParameters =
 {
  "rows": 5,           // Rows number
  "cols": 5,           // Columns number
  "width": 100,        // One image width
  "height": 100,       // One image height
  "changeTime": 1500,  // One image is changed every "changeTime" ms
                       // It could be an associative array with parameter "min" and "max which
                       // respectively represent the bounds of random interval
 
  "fadeTime": 700,     // Image change take "fadeTime" ms
  "images": [],        // Array of image url (its length shall be greater than "rows" * "cols")
  "baseZIndex": 0,     // Minimum z-index for images
  "startDelay": 0      // Delay before start animation
 };
 
 $.fn.checkerboardSlide = function( params )
 {

  // First initialization
  if( typeof $(this).data( "checkerboardSlide.params" ) == "undefined" )
  {
   params = $.extend( {}, defaultParameters, params );
   
   if( $(this).css( "position" ) == "static" )
    $(this).css( "position", "relative" );
    
   $(this).css( {
    "display": "block",
    "width": params.width * params.cols,
    "height": params.height * params.rows
   } );
  }
  else
   params = $.extend( {}, $(this).data( "checkerboardSlide.params" ), params );
   
  $(this).data( "checkerboardSlide.params", params );
  $(this).empty();
  
  var stockImages = params.images;
  var currentImages = [];
  
  for( var i = 0 ; i < params.rows ; i++ )
  {
   for( var j = 0 ; j < params.cols ; j++ )
   {
    var index = Math.floor( Math.random() * stockImages.length );
    
    $(this).append( $("<img/>").attr( "src", stockImages[ index ] ).addClass( "image-" + i + "-" + j ).css(
    {
     "display": "block",
     "position": "absolute",
     "left": j * params.width,
     "top": i * params.height,
     "width": params.width,
     "height": params.height,
     "zIndex": params.baseZIndex + 1
    } ) );
    
    currentImages.push( stockImages[ index ] );
    stockImages.splice( index, 1 )
   }
  }
  
  $(this).data( "checkerboardSlide.stockImages", stockImages );
  $(this).data( "checkerboardSlide.currentImages", currentImages );
  
  if( typeof $(this).data( "checkerboardSlide.timeout" ) != "undefined" )
   clearTimeout( $(this).data( "checkerboardSlide.timeout" ) );
   
  var checkerboard = $(this);
  
  if( typeof params.changeTime == "object" )
   $(this).data( "checkerboardSlide.timeout", setTimeout( function(){ checkerboardSlideChangeImage( checkerboard ); }, params.startDelay + params.changeTime.min + Math.floor( Math.random() * ( params.changeTime.max - params.changeTime.min ) ) ) );
  else
   $(this).data( "checkerboardSlide.timeout", setTimeout( function(){ checkerboardSlideChangeImage( checkerboard ); }, params.startDelay + params.changeTime ) );
 };
 
 function checkerboardSlideChangeImage( checkerboard )
 {
  var params = checkerboard.data( "checkerboardSlide.params" );
  var stockImages = checkerboard.data( "checkerboardSlide.stockImages" );
  var currentImages = checkerboard.data( "checkerboardSlide.currentImages" );
  
  var currentIndex = Math.floor( Math.random() * currentImages.length );
  var stockIndex = Math.floor( Math.random() * stockImages.length );
  
  var i = Math.floor( currentIndex / params.cols );
  var j = Math.floor( currentIndex % params.cols );
  
  var oldImg = checkerboard.children( "img.image-" + i + "-" + j );
  var newImg = $("<img/>").attr( "src", stockImages[ stockIndex ] ).addClass( "image-" + i + "-" + j ).css(
  {
   "display": "block",
   "position": "absolute",
   "left": j * params.width,
   "top": i * params.height,
   "width": params.width,
   "height": params.height,
   "zIndex": params.baseZIndex
  } );
  
  checkerboard.append( newImg );
  
  stockImages[ stockIndex ] = currentImages[ currentIndex ];
  currentImages[ currentIndex ] = newImg.attr( "src" );
 
  checkerboard.data( "checkerboardSlide.stockImages", stockImages );
  checkerboard.data( "checkerboardSlide.currentImages", currentImages );
  
  oldImg.fadeOut( params.fadeTime, function()
  {
   newImg.css( "zIndex", params.baseZIndex + 1 );
   $(this).remove();
   
   if( typeof params.changeTime == "object" )
    checkerboard.data( "checkerboardSlide.timeout", setTimeout( function(){ checkerboardSlideChangeImage( checkerboard ); }, params.changeTime.min + Math.floor( Math.random() * ( params.changeTime.max - params.changeTime.min ) ) ) );
   else
    checkerboard.data( "checkerboardSlide.timeout", setTimeout( function(){ checkerboardSlideChangeImage( checkerboard ); }, params.changeTime ) );
  } );
 }

})(jQuery);
