(function($){
  var settings;
  var hasLinks = false, hasMask = false;
  var currIndex = 0, nextIndex = 1, numImages = 0;
  var $currImage = null, $nextImage = null, $mask = null;

  function shuffle(arr) {
    for (
      var j, x, i = arr.length; i;
      j = parseInt(Math.random() * i),
      x = arr[--i], arr[i] = arr[j], arr[j] = x
    );
    return arr;
  }

  function displayNextImage() {
    if (currIndex == numImages) currIndex = 0;
    if (nextIndex == numImages) nextIndex = 0;

    // IE6-7 needed the "contains" selector ([src*=) instead of what was originally coded ([src=)
    $currImage = $('#' + settings.containerID + ' img[src*="' + settings.images[currIndex] + '"]').css('z-index', 2);
    $nextImage = $('#' + settings.containerID + ' img[src*="' + settings.images[nextIndex] + '"]').css('z-index', 1);

    $currImage.fadeOut(settings.animSpeed, function() {
      $(this).css('z-index', 0).show();

      // If there are links for the images and a mask...
      if (hasLinks && hasMask) {
        // ...get rid of any existing link for the mask.
        if ($mask.parent().get(0).tagName.toLowerCase() === 'a') $mask.unwrap();

        // If the upcoming image has a link, wrap the mask with the link.
        if (settings.links[nextIndex]) $mask.wrap('<a href="' + unescape(settings.links[nextIndex]) + '" target="_blank" \/>');
      }
      currIndex++;
      nextIndex++;
    });

    setTimeout(displayNextImage, settings.pauseTime);
  }
  
  $.fn.imageRotator = function(options) {
  
    var defaults = {
          images: [],
          links: [],
          containerID: 'imgRotator',
          maskID: '',
          pauseTime: 5000,
          animSpeed: 1000,
          sortImages: 1
        };
        
    settings = $.extend({}, defaults, options);

    if ( ! settings.sortImages) settings.images = shuffle(settings.images);

    numImages = settings.images.length;
    hasLinks = (settings.links.length > 0);
    if (settings.maskID !== '' && $('#' + settings.maskID).length) {
      hasMask = true;
      $mask = $('#' + settings.maskID);
    }

    this.each(function() {
      // $this is the element passed in to this plugin
      // e.g. $('#imgRotator').imageRotator(); - $this = element IDed with 'imgRotator'
      var $this = $(this);
      
      // Cache the first <img> tag (spacer.gif)
      var firstImg = $this.find('img:first');
      
      if (numImages) {
        if (numImages > 1) {
          // Create the HTML for the remaining images and insert them before the first
          for (var i=0; i<numImages; i++) {
            firstImg.clone().attr('src', settings.images[i]).insertBefore(firstImg);
          }
          // Put the first image on top
          $this.find('img:first').css('z-index', 1);

          // Get rid of the spacer.gif
          $this.find('img:last').remove();
        } else {
          // Assign an image to the 1st <img>
          firstImg.attr('src', settings.images[0]);
        }

        // If there are links for the images...
        if (hasLinks) {
          // ...and NO mask, we can wrap all of the images with links before we even start the animation.
          if (! hasMask) {
            var $img;
            for (var i=0; i<numImages; i++) {
              if (settings.links[i]) {
                $img = $('#' + settings.containerID + ' img[src="' + settings.images[i] + '"]');
                $img.wrap('<a href="' + unescape(settings.links[i]) + '" target="_blank" \/>');
              }
            }
          } else {
            // ...and a mask. If the first image has a link...
            if (settings.links[0]) {
              // ...wrap the mask with the link
              $mask.wrap('<a href="' + unescape(settings.links[0]) + '" target="_blank" \/>');
            }
          }
        }

        if (numImages > 1) setTimeout(displayNextImage, settings.pauseTime);

      } else {
        // If no images, hide the 1st <img>
        firstImg.hide();
      }
    });

    // returns the jQuery object to allow for chainability.
    return this;
  }
})(jQuery);

