/**
 * jQuery Slideshow
 *
 * Manages images (cross-fading) and a single flash video (optional).
 *
 * Author: Johannes Wüller
 * Created On: 07.04.2010
 *
 * Usage:
 *    jQuery(".some-slideshow-container").slideshow(options);
 *
 * Options:
 *    fadeType            which jQuery animation type should be used to do the
 *                        fading - currently possible values: swing, linear.
 *                        defaults to swing
 *    fadeDuration        time used for fading between images in milliseconds
 *    imageControlLabel   text to be displayed as the images-category-descriptor
 *    videoControlLabel   text to be displayed as the video-category-descriptor
 *    prevControlImage    path to image that should be used as previous-button
 *    nextControlImage    path to image that should be used as next-button
 *    positionSeparator   text to separate current position and maximum position
 *                        number. defaults to /
 *    continuous          wether the wrap around the range (i.e. jump from first
 *                        to last item or the other way around). values:
 *                        true/false. defaults to false
 */
(function() {
   
   // quick reference
   var window = this;
   var undefined;
   
   jQuery.fn.slideshow = function(options) {
      jQuery(this).each(function() {
         // merge with default options
         options = jQuery.extend({
            fadeType:          "swing",
            fadeDuration:      1000,
            imageControlLabel: "",
            videoControlLabel: "",
            prevControlImage:  "",
            nextControlImage:  "",
            positionSeparator: "/",
            continuous:        false
         }, options || {});
         
         // reference to some basic nodes to cut down redundancy
         var nodes = {
            root:           jQuery(this),
            imageContainer: jQuery(this).children(".image-container"),
            images:         jQuery(this).children(".images-content").children(),
            video:          jQuery(this).children(".video-content"),
            controls:       jQuery(this).children(".controls")
         };
         
         // variables for tracking offsets
         var imagesPosition = 1;
         
         // determine contents
         var hasImage = nodes.images.children().length > 0;
         var hasVideo = nodes.video.children().length > 0;
         
         /*
          * functions
          */
         var getImageUrl = function(element) {
            return jQuery(element).find(".src").html().replace(/&amp;/g, '&');
         };
         var preloadImages = function() {
            nodes.images.each(function() {
               jQuery(document.createElement("img"))
                  .attr("src", getImageUrl(this)).hide()
                  .load(jQuery.noop); // kind of senseless x]
            });
         };
         var updatePositionLabel = function() {
            nodes.positionLabel.html(imagesPosition+options.positionSeparator+nodes.images.length);
         };
         var prevImage = function() {
            if (imagesPosition > 1) {
               imagesPosition -= 1;
            } else {
               imagesPosition = nodes.images.length;
            }
         };
         var nextImage = function() {
            if (imagesPosition < nodes.images.length) {
               imagesPosition += 1;
            } else {
               imagesPosition = 1;
            }
         };
         var applyCurrentImage = function() {
            updatePositionLabel();
            
            // save image that is about to be replaced for later use
            var oldImg = nodes.imageContainer.find("img");
            
            // create new image
            var data = nodes.images.eq(imagesPosition - 1);
            var newImg = jQuery(document.createElement("img"))
               .attr("src", getImageUrl(data))
               .attr("title", data.find(".title").html());
            
            // fade in new image
            newImg.css({
               zIndex:  2,
               opacity: 0.0
            }).animate({
               opacity: 1.0
            }, options.fadeDuration).appendTo(nodes.imageContainer);
            
            // fade out old image if it exists
            if (oldImg.length > 0) {
               oldImg.stop().css({
                  zIndex: 1
               }).animate({
                  opacity: 0.0
               }, options.fadeDuration, function() {
                  jQuery(this).remove();
               });
            }
         };
         
         /*
          * prepare elements
          */
         // video
         if (hasVideo) {
            var videoControl = jQuery(document.createElement("div"))
               .addClass("video button").html(options.videoControlLabel)
               .appendTo(nodes.controls);
         }
         // separator
         if (hasVideo && hasImage) {
            jQuery(document.createElement("div")).addClass("separator")
               .appendTo(nodes.controls);
         }
         // images
         if (hasImage) {
            preloadImages();
            // generate controls
            nodes.positionLabel = jQuery(document.createElement("span"))
               .addClass("position")
               .html(imagesPosition+options.positionSeparator+nodes.images.length);
            var label = jQuery(document.createElement("div"))
               .addClass("button").html(options.imageControlLabel);
            var imgButtonPrototype = jQuery(document.createElement("img"))
               .addClass("button");
            var prevButton = imgButtonPrototype.clone().addClass("prev")
               .attr("src", options.prevControlImage);
            var nextButton = imgButtonPrototype.clone().addClass("next")
               .attr("src", options.nextControlImage);
            jQuery(document.createElement("div")).addClass("images")
               .append(label).append(nodes.positionLabel)
               .append(prevButton).append(nextButton).appendTo(nodes.controls);
         }
         
         /*
          * bindings
          */
         nodes.controls.find(".images .prev").click(function() {
            prevImage();
            applyCurrentImage();
         });
         nodes.controls.find(".images .next").click(function() {
            nextImage();
            applyCurrentImage();
         });
         
         /*
          * show first image
          */
         applyCurrentImage();
      });
   };
   
}());
