(function($){

  $.fn.slideShow = function(options) {

    var slideShowSelektor = "#slideShow";
        var loadingAnimationSelektor = slideShowSelektor + " #loading";
    var currentImageSelektor = slideShowSelektor + " #imageSlot01";
    var hiddenImageSelektor = slideShowSelektor + " #imageSlot02";
    var textPanelSelektor = slideShowSelektor + " #textPanel";
        
    var prevButtonSelektor = slideShowSelektor + " #prevButton";
    var nextButtonSelektor = slideShowSelektor + " #nextButton";
        var linkButtonSelektor = slideShowSelektor + " #linkButton";

    var SLIDE_PROPERTY_IMAGE_URL = "imageURL";
    var SLIDE_PROPERTY_HREF = "href";
    var SLIDE_PROPERTY_HEADING_TEXT = "headingText";
    var SLIDE_PROPERTY_BODY_TEXT = "bodyText";
        var SLIDE_PROPERTY_BUTTON_TEXT = "buttonText";
        var SLIDE_PROPERTY_LINK_URL = "buttonLink";
        var SLIDE_PROPERTY_LINK_IS_VIDEO = "buttonLinkIsVideo";
        var SLIDE_PROPERTY_LINK_VIDEO_WIDTH = "buttonLinkVideoWidth";
        var SLIDE_PROPERTY_LINK_VIDEO_HEIGHT = "buttonLinkVideoHeight";
        var SLIDE_PROPERTY_ID = "image";
        var SLIDE_PROPERTY_IS_LOADED = "isLoaded";

        var ANIM_TEXTPANEL_UP = "animationTextPanelUp";
        var ANIM_TEXTPANEL_DOWN = "animationTextPanelDown";
        var ANIM_IMAGE_LEFT = "animationImageLeft";
        var ANIM_IMAGE_RIGHT = "animationImageLeft";
        var ANIM_TEXTPANEL_DURATION = 500;
        var ANIM_IMAGE_DURATION = 500;
        var IMAGE_WIDTH = 920;

    var delay;
    var slides = new Array();
        var buttonLinkTarget;
    var currentSlideIndex = 0;
        var timer;

        var isShadowBoxOpened = false;

    // read the xml
    $.ajax({
      type: "GET",
      url: options["xmlURL"],
      dataType: "text",
      success: onLoadXML,
      error: onError
    });

        function onError() {
      alert("Problem: couldn't load file '" + options["xmlURL"] + "'");
    }

    function onLoadXML(str) {
      var xmlDoc = $.parseXML(str); // requires jQuery 1.5
      var xml = $(xmlDoc);

      // parse XML
      delay = $(xml).find("slideShow").attr("delay");
      buttonLinkTarget = $(xml).find("slideShow").attr("buttonLinkTarget");
      trace("delay=" + delay);
      var counter = 0;
      $(xml).find("slide").each(function() {
        var slide$ = $(this);
        var slideObject = new Object();
        slideObject[SLIDE_PROPERTY_IMAGE_URL] = slide$.find(SLIDE_PROPERTY_IMAGE_URL).text();
        slideObject[SLIDE_PROPERTY_HREF] = slide$.find(SLIDE_PROPERTY_HREF).text();
        slideObject[SLIDE_PROPERTY_HEADING_TEXT] = slide$.find(SLIDE_PROPERTY_HEADING_TEXT).text();
        slideObject[SLIDE_PROPERTY_BODY_TEXT] = slide$.find(SLIDE_PROPERTY_BODY_TEXT).text();
                slideObject[SLIDE_PROPERTY_BUTTON_TEXT] = slide$.find(SLIDE_PROPERTY_BUTTON_TEXT).text();
                slideObject[SLIDE_PROPERTY_LINK_URL] = slide$.find(SLIDE_PROPERTY_LINK_URL).text();
                slideObject[SLIDE_PROPERTY_LINK_IS_VIDEO] = slide$.find(SLIDE_PROPERTY_LINK_URL).attr("isVideo") == "true";
                slideObject[SLIDE_PROPERTY_LINK_VIDEO_WIDTH] = parseInt(slide$.find(SLIDE_PROPERTY_LINK_URL).attr("width"));
                slideObject[SLIDE_PROPERTY_LINK_VIDEO_HEIGHT] = parseInt(slide$.find(SLIDE_PROPERTY_LINK_URL).attr("height"));
                slideObject[SLIDE_PROPERTY_ID] = "image" + (counter++);
                slideObject[SLIDE_PROPERTY_IS_LOADED] = false;
        slides.push(slideObject);
      });

            // load first slide (=image) - others will start loading once first image is ready
            loadSlide(slides[0]);
        }

        function loadSlide(slide) {
            $("<img>")
                    .attr("src", slide[SLIDE_PROPERTY_IMAGE_URL])
                    .attr("id", slide[SLIDE_PROPERTY_ID])
                    .css("display", "none") // not visible
                    .appendTo(slideShowSelektor)
                    .imagesLoaded(createImageLoadCallback(slide));
        }

        function createImageLoadCallback(slide) {
            return function() {
                trace("image " + slide[SLIDE_PROPERTY_ID] + " is loaded!");

                // problem: the load image event may be fired more than once
                if (slide[SLIDE_PROPERTY_IS_LOADED]) {
                    return;
                }

                // mark as loaded
                slide[SLIDE_PROPERTY_IS_LOADED] = true;

                // continue only when first slide
                if (slide != slides[0]) {
                    return;
                }

                trace("init!!!");

                // load the other images
                for (var i = 1; i < slides.length; i++) { // skip the first one, it's already loaded
                    loadSlide(slides[i]);
                }

                // remove the "loading" GIF
                $(slideShowSelektor).remove(loadingAnimationSelektor);

                // show the first image
                $(currentImageSelektor).attr("src", slides[currentSlideIndex][SLIDE_PROPERTY_IMAGE_URL]);

                // populate the text panel
                var headingText = slides[currentSlideIndex][SLIDE_PROPERTY_HEADING_TEXT];
                var bodyText = slides[currentSlideIndex][SLIDE_PROPERTY_BODY_TEXT];
                var buttonText = slides[currentSlideIndex][SLIDE_PROPERTY_BUTTON_TEXT];

                $(textPanelSelektor).find("h3").html(headingText);
                $(textPanelSelektor).find("p").html(bodyText);
                $(textPanelSelektor).find("a").html(buttonText);

                // show the text panel
                $(textPanelSelektor).animate({"top" : "0"}, ANIM_TEXTPANEL_DURATION, startSlideShow);
            }
        }

    $(prevButtonSelektor).click(function(){ // scroll images to the right
      trace("prev!");
            prevSlide();
    });

    $(nextButtonSelektor).click(function(){ // scroll images to the left
            trace("next!");
      nextSlide();
    });

        $(linkButtonSelektor).click(function() {
            var slide = slides[currentSlideIndex];
            var url = slide[SLIDE_PROPERTY_LINK_URL];
            var isVideo = slide[SLIDE_PROPERTY_LINK_IS_VIDEO];

            if (!isVideo) {
                window.open(url, buttonLinkTarget);

            } else {

                // stop the slideshow while the shadowbox is opened
                stopSlideShow();
                isShadowBoxOpened = true;

                var width = slide[SLIDE_PROPERTY_LINK_VIDEO_WIDTH];
                var height = slide[SLIDE_PROPERTY_LINK_VIDEO_HEIGHT];

                // example url:
                // http://player.vimeo.com/video/17595864
                //var content = "<iframe src='" + url + "' width='" + width + "' height='" + height + "' frameborder='0' scrolling='no'></iframe>";
                Shadowbox.open({
                    content: url,
                    player: "iframe",
                    width: width,
                    height: height,
                    options: {
                        onClose: onShadowBoxClose
                    }
                });
            }
        });

        function onShadowBoxClose() {
            isShadowBoxOpened = false;
            startSlideShow();
        }

    $(slideShowSelektor).mouseover(function() {
      trace("mouseover");
            stopSlideShow();
    });

    $(slideShowSelektor).mouseout(function() {
      trace("mouseout");

            // when the shadowbox comes up, the mouseout event will be triggered
            // and start the slideshow again, prevent this by checking isShadowBoxOpened
            if (isShadowBoxOpened) {
                return;
            }
            startSlideShow();
    });

    function startSlideShow() {
            trace("startSlideShow!!!");
            if (timer != null) { // slideshow is already running
                return;
            }
      timer = window.setInterval(nextSlide, delay);
    }

        function stopSlideShow() {
            trace("stopSlideShow!!!");
             if (timer == null) { // slideshow already stopped
                 return;
             }
             window.clearInterval(timer);
             timer = null;
        }

        function nextSlide() {

            // skip if animation is still running
            if ($(slideShowSelektor).find("div, img").filter(":animated").length > 0) {
        return;
      }

            var nextSlideIndex = (currentSlideIndex + 1) % slides.length;

            // skip if image isn't loaded yet
            if (!slides[nextSlideIndex][SLIDE_PROPERTY_IS_LOADED]) {
                return;
            }

            // place "next" image
      $(hiddenImageSelektor).attr("src", slides[nextSlideIndex][SLIDE_PROPERTY_IMAGE_URL]);
      $(hiddenImageSelektor).css("left", IMAGE_WIDTH + "px");

      // animation: slide textPanel up
      //$(textPanelSelektor).animate({"top" : "-120px"}, ANIM_TEXTPANEL_DURATION, onTextHidden);
            animTextPanel(ANIM_TEXTPANEL_UP, onTextHidden);
      function onTextHidden() {

        // animation: slide images to the left
        $(currentImageSelektor).animate({"left" : "-" + IMAGE_WIDTH + "px"}, ANIM_IMAGE_DURATION);
        $(hiddenImageSelektor).animate({"left": "0"}, ANIM_IMAGE_DURATION, onImageReady);

        // update variables
        currentSlideIndex = nextSlideIndex;
        var tmp = currentImageSelektor;
        currentImageSelektor = hiddenImageSelektor;
        hiddenImageSelektor = tmp;

        // set new text
        setTextPanelValues(slides[currentSlideIndex]);
      }

      // animation: slide textPanel down
      function onImageReady() {
        //$(textPanelSelektor).animate({"top" : "0"}, ANIM_TEXTPANEL_DURATION);
                animTextPanel(ANIM_TEXTPANEL_DOWN);
      }
        }

        function prevSlide() {

            // skip if animation is still running
            if ($(slideShowSelektor).find("div, img").filter(":animated").length > 0) {
        return;
      }

      var prevSlideIndex = (slides.length + currentSlideIndex - 1) % slides.length;

            // skip if image isn't loaded yet
            if (!slides[prevSlideIndex][SLIDE_PROPERTY_IS_LOADED]) {
                return;
            }

      $(hiddenImageSelektor).attr("src", slides[prevSlideIndex][SLIDE_PROPERTY_IMAGE_URL]);
      $(hiddenImageSelektor).css("left", "-" + IMAGE_WIDTH + "px");

      // animation: slide textPanel up
      //$(textPanelSelektor).animate({"top" : "-120px"}, ANIM_TEXTPANEL_DURATION, onTextHidden);
            animTextPanel(ANIM_TEXTPANEL_UP, onTextHidden);
      function onTextHidden() {

        // animation: slide images to the right
        $(currentImageSelektor).animate({"left" : IMAGE_WIDTH + "px"}, ANIM_IMAGE_DURATION);
        $(hiddenImageSelektor).animate({"left": "0"}, ANIM_IMAGE_DURATION, onImageReady);

        // update variables
        currentSlideIndex = prevSlideIndex;
        var tmp = currentImageSelektor;
        currentImageSelektor = hiddenImageSelektor;
        hiddenImageSelektor = tmp;

        // set new text
                setTextPanelValues(slides[currentSlideIndex]);
      }

      // animation: slide textPanel down
      function onImageReady() {
        //$(textPanelSelektor).animate({"top" : "0"}, 500);
                animTextPanel(ANIM_TEXTPANEL_DOWN);
      }
        }

        function setTextPanelValues(slide) {
            var headingText = slide[SLIDE_PROPERTY_HEADING_TEXT];
            var bodyText = slide[SLIDE_PROPERTY_BODY_TEXT];
            var buttonText = slide[SLIDE_PROPERTY_BUTTON_TEXT];
            $(textPanelSelektor).find("h3").html(headingText);
            $(textPanelSelektor).find("p").html(bodyText);
            $(textPanelSelektor).find("a").html(buttonText);
        }

        function animTextPanel(action, callback) {
            if (action == ANIM_TEXTPANEL_DOWN) {
                $(textPanelSelektor).animate({"top" : "0"}, ANIM_TEXTPANEL_DURATION, callback);
            }
            else if (action == ANIM_TEXTPANEL_UP) {
                $(textPanelSelektor).animate({"top" : "-120px"}, ANIM_TEXTPANEL_DURATION, callback);
            }
        }

        function animImage(action, callback) {
            if (action == ANIM_IMAGE_LEFT) {
                $(currentImageSelektor).animate({"left" : "-" + IMAGE_WIDTH + "px"}, ANIM_IMAGE_DURATION);
        $(hiddenImageSelektor).animate({"left": "0"}, ANIM_IMAGE_DURATION, callback);
            }
            else if (action == ANIM_IMAGE_RIGHT) {
                $(currentImageSelektor).animate({"left" : IMAGE_WIDTH + "px"}, ANIM_IMAGE_DURATION);
        $(hiddenImageSelektor).animate({"left": "0"}, ANIM_IMAGE_DURATION, callback);
            }
        }
        
    function trace(str) {
      //$("#debug").append(str + "<br>");
    }

  };
})(jQuery);

