﻿// Files needed: 
// jquery.ip.lightbox.css
// Example file
// lightbox.htm

(function($){
  // Create lightbox from wrappedset
  $.fn.lightbox = function(config) {
    // Create only one lightbox class
    $.__lightbox = $.__lightbox ? $.__lightbox : new $.Lightbox();
    // Create lightbox entry in class
    $.__lightbox.add($(this), config ? config : { name: "first" });
    return $(this);
  };

  // Create lightbox from wrappedset
  $.lightboxShowDimScreen = function() {
    // Create only one lightbox class
    $.__lightbox = $.__lightbox ? $.__lightbox : new $.Lightbox();
    $.__lightbox.showDimScreen();
  };
  
  // Create lightbox from wrappedset based on ajax-call
  $.fn.ajaxContentForLightbox = function(contentId, url, config, callback) {
    var items = $(this);
  
    var lightboxContainer = $("#lightbox-ajax-content");
    if (lightboxContainer.size() == 0) {
      $("body").append('<div id="lightbox-ajax-content" class="verborgen"></div>');
      lightboxContainer = $("#lightbox-ajax-content");
    }
    
    items.each(function() {
      var item = $(this);
      item.attr("href", "javascript:void(0);").addClass("lightbox-ajax-content").click(function() {
        $.lightboxShowDimScreen(config);
        var current = $(this);
        var currentId = current.attr("id").split("_")[1];
        url = $.cleanUrl(url.replace('{0}', currentId));
        
        var content = lightboxContainer.find("#lightbox_ajax_content_"+contentId);
        // Create content container for this lightbox
        if (content.size() == 0) {
          lightboxContainer.append('<div id="lightbox_ajax_content_'+contentId+'"></div>');
          content = lightboxContainer.find("#lightbox_ajax_content_"+contentId);
          content.load(url, function() {
            items.attr("loaded", "true");
          
            lightboxContainer.find(".slideshow").lightbox($.extend({ 
              name: "fotoalbum"+contentId 
            }, config));

            lightboxContainer.find("#item_lightbox_ajax_content_"+ currentId).click();
          });
        }
        else {
          lightboxContainer.find("#item_lightbox_ajax_content_"+ currentId).click();
        }
      });
    });
  
    return $(this);
  };
  
  // Creates events before content which fire the events fire.
  $.Lightbox = function(wrappedset, config) {
    // Call the constructor of the class
    this.__constructor(wrappedset, config);
  };
  
	// Define our class
	$.extend($.Lightbox.prototype, {	
	  // Our class definition
	  // Collection of all lightboxes
    lightboxes: null,
    // Internal var which states whether the lightbox is busy
    __busy: false,
    // Arguments and placeholders for lightbox elements
    elements: {
      lightbox: null,
      items: null,
      config: null,
      current: null,
      dim: null,
      wrapper: null,
      container: null,
      content: null,
      loader: null,
      progress: null,
      index: -1
    },
    // The constructor of the class
	  __constructor: function(wrappedset, config) {
      this.lightboxes = new Object();
      // Add first lightbox
      this.add(wrappedset, config);
      return this;
	  },
	  // If number is not 0 then an error has occurred
	  error: {
	    setError: function(number, message) {
	      this.number = number;
	      this.message = message;
	      return this;
	    },
	    OK: function() {
	      return this.setError(0, "Success");
	    },
	    number: 0,
	    message: "succes"
	  },
	  // Add new lightbox
    add: function(items, config) {
      // Only add set when size is bigger then 0
      if (!items || items.size() == 0) {
        return this.error.setError("2", "No elements in this set");
      }
      // TODO: add lightbox items to existing lightbox, for paging perhaps.
      // Name must be unique
      if (this.lightboxes[config.name]) {
        return this.error.setError("1", "Name already exists");
      }
      
      // Create lightbox implementation.
      var lightbox = new Object();
      // Create config based on defaults and parameter config
      lightbox.config = $.extend($.LightboxDefaults, config);
      // Set items of this lightbox
      lightbox.items = items;
      // Set lightbox object under config name
      this.lightboxes[config.name] = lightbox;
      
      // Set class to curObj, for use later
      var curObj = this;
      // Create click events for all lightbox items
      items.each(function(i, n) {
        // Set index number for this lightbox
        $(n).attr("lightbox-index", i);
        // Set marker for lightbox
        $(n).attr("lightbox", config.name);
        // Add name of content and size functions if client specifies it through trigger setcontent.
        $(n).trigger("setcontent", [ this, lightbox ]);
        if (!$(n).attr("lightbox-content")) {
        // Add name of content and size functions
          $(n).attr("lightbox-content", lightbox.config.content);
        }
        // Add class for styling the lightbox items
        $(n).addClass("lightboxed");
        // First unbind click event(current click event is lost)
        $(n).unbind("click").bind("click.lightbox", function() {
          // Start lightbox with clicked element
          curObj.start.apply(curObj, [ $(this).filter(":first") ]);
          // Return false in case of a tag
          return false;
        });
      });
      
      if (lightbox.config.startDirect) {
        curObj.start.apply(curObj, [ $(items.get(0)).filter(":first") ]);
      }
      
      // Return error object, which says ok ;-)
      return this.error.OK();
    },
    // Function that shows the dim screen
    showDimScreen: function() {
      // Only do something if the lightbox isn't busy
      if (!this.__busy) {
        var tempConfig = $.LightboxDefaults;
        // Set class to curObj, for use later
        var curObj = this;
        
        this.__busy = true;
        // Create the lightbox
        if ($("#ip-lightbox-dimscreen").hide().size() != 1) {
          $("#ip-lightbox-dimscreen").remove();
          $(document.body).append($('<div id="ip-lightbox-dimscreen"></div>').hide());
        }
        $("#ip-lightbox-dimscreen").css("opacity", 0).show().animate({ "opacity": tempConfig.dimOpacity }, "fast");
      }
      this.__busy = false;
    },
    // Function that starts the lightbox
    start: function(item) {
      // Set class to curObj, for use later
      var curObj = this;
      // Only do something if the lightbox isn't busy
      if (!this.__busy) {
        this.__busy = true;
        // Retrieve the right lightbox object
        var lightbox = this.lightboxes[item.attr("lightbox")];
        // Set all parameters of this.elements
        this.elements.items = lightbox.items;
        this.elements.config = lightbox.config;
        // Create the lightbox
        this.createLightboxContainer();
        
        // If set, create end clicks
        if (this.elements.config.end != null && this.elements.config.end != "") {
          // Create end click actions, overrule through setting "end", which contains selector
          $(this.elements.config.end).addClass("lightbox-end").click(function() {
            // Call end function and set context to curObj
            curObj.end.apply(curObj);
          });
        }
        
        // Unbind events first
        this.elements.config.events.unbind(this.elements.content);
        // Bind navigation if needed
        if (this.elements.config.mode != "single" && $.LightboxEvents[this.elements.config.navigation]) {
          $.LightboxEvents[this.elements.config.navigation].bind(this.elements.config.events);
        }
        else if ($.LightboxEvents[this.elements.config.navigation]) {
          $.LightboxEvents[this.elements.config.navigation].unbind(this.elements.config.events);
        }
          
        // Bind events
        this.elements.config.events.bind(this.elements.content);
        // Trigger event beforestart
        this.elements.content.trigger("beforestart", [ this, this.elements ]);
        // Show the lightbox (finally)
        if (this.elements.dim.css("opacity") == 1) {
          this.elements.dim.css("opacity", 0);
        }
        this.elements.dim.show().animate({ "opacity": this.elements.config.dimOpacity }, "fast", function() {
          // First show lightbox with default width and height
          curObj.showDefault.apply(curObj);
          // Then show the clicked item
          curObj.showItem.apply(curObj, [ item.attr("lightbox-index") ]);
        });
      }
    },
    // Create the lightbox html and other elements
    createLightboxContainer: function() {
      // Set temporary variables
      var curObj= this;
      var elements = this.elements;
      // Search for previous uncleaned lightbox
      if ($("ip-lightbox-loader").size() == 0) {
        $(document.body).append($('<div id="ip-lightbox-loader"></div>').hide());
      }
      if ($("#ip-lightbox-dimscreen").size() == 0) {
        $(document.body).append($('<div id="ip-lightbox-dimscreen"></div>').hide());
      }
      if ($("#ip-lightbox").size() == 0) {
        // Create base html
        $(document.body).append($('<div id="ip-lightbox"><div class="lightbox-wrapper"><div class="lightbox-container"><div class="lightbox-content"></div><div id="slideout-under"></div></div></div></div>').hide());
      }
      // Set lightbox and add browser name class
      elements.lightbox = $("#ip-lightbox").addClass($.browser.name());
      // Remove al end lightbox classes
      $(".lightbox-end").removeClass("lightbox-end");
      // Set dimscreen element
      elements.dim = $("#ip-lightbox-dimscreen");
      // Set wrapper element
      elements.wrapper = elements.lightbox.find(".lightbox-wrapper").draggable();
      // Stop propagation events of the lightbox content.
      elements.wrapper.click(function(event) {
        event.stopPropagation();
      });
      // Set container element
      elements.container = elements.lightbox.find(".lightbox-container");
      // Define dummy loaded function to set context
      var loaded = function() { curObj.loaded.apply(curObj); };
      // Set container element
      elements.content = elements.lightbox.find(".lightbox-content").bind("contentloaded", loaded);
      // Set loader element (for loading the content for the lightbox)
      elements.loader = $("#ip-lightbox-loader").bind("contentloaded", loaded);
      // Set progress element (TODO: implement progress element)
      elements.progress = elements.lightbox.find(".progress").hide();
      // Set current element to null
      elements.current = null;
      // Set index element to -1
      elements.index = -1;
    },
    // Function to fire when content is loaded
    loaded: function() {
      // Trigger event beforeshow
      this.elements.content.trigger("beforeshow", [ this, this.elements ]);
      // Set size through size function
      var size = $.LightboxContent[this.elements.current.attr("lightbox-content")].size.apply(this.elements.current, [ this.elements ]);
      // Empty content and set content from loader element
      this.elements.content.html("").append(this.elements.loader.find("> *"));
      // Animate content to the proper size (and show the content)
      this.elements.wrapper.css("top", "0");
      this.__animate(size.width, size.height);
    },
    // Show default content (of course empty) 
    showDefault: function() {
      // Set content to empty string
      this.elements.content.html("&#160;");
      // Show the progress element
      this.showProgress();
      // Animate content to the default size
      this.__animate(); 
    },
    // Show current content (first load it in the loader object)
    showItem: function(index) {
      // Set the context of the current item
      this.__setContext(index);
      // Set content to empty string
      this.elements.content.html("&#160;");
      // Set loader to empty string
      this.elements.loader.html("&#160;");
      // Show the progress element
      this.showProgress();
      // Trigger event beforeload
      this.elements.content.trigger("beforeload", [ this, this.elements ]);
      // Show the content if content function is available.
      if ($.LightboxContent[this.elements.current.attr("lightbox-content")]) {
        // Fire content function and set right context
        $.LightboxContent[this.elements.current.attr("lightbox-content")].content.apply(this.elements.current, [ this.elements ]);
      }
    },
    // Animate content pane to right width and height
    __animate: function(width, height) {
      // Set class to curObj, for use later
      var curObj= this;
      // Hide content
      this.elements.content.css("visibility", "hidden");
      // If width isn't set, don't show content and size to default width and height
      var visible = !!width;
      
      // Set css width and height
      var css = {
        width: !width ? this.elements.config.defaultWidth : width < this.elements.config.minWidth ? this.elements.config.minWidth : width, 
        height: !height ? this.elements.config.defaultHeight : height < this.elements.config.minHeight ? this.elements.config.minHeight : height
      };
      
      // Show the lightbox
      this.elements.lightbox.show();
      
      // Set left for IE to keep content centered
      if ($.browser.msie) {
        this.elements.wrapper.css("left", ($("body").width() / 2) - (this.elements.wrapper.width() / 2));
        this.elements.wrapper.stop().animate({ left: Math.round($(document.body).width() / 2) - Math.round(css.width / 2) }, "normal");
        // IE 6 needs even more fixing
        if ($.browser.version.substring(0, 1) == "6") {
          scroll(0,0);
          $("body").css("overflow", "hidden");
        }
      }
      // Animate container to width and height
      this.elements.container.stop().animate(css, "normal", function() {
        // Show content and fade it in
        curObj.elements.content.css({ opacity: 0, visibility : !visible ? "hidden" : "" }).animate({ opacity: 1 }, "normal", function() {
          // Fix for IE: set opacity empty, so rendering of text is proper
          curObj.elements.content.css("opacity", "");
        });
        // only show content when needed
        if (visible) {
          // Hide progress object
          curObj.hideProgress.apply(curObj);
          // Trigger event afterload
          curObj.elements.content.trigger("afterload", [ curObj, curObj.elements ]);
          // Set busy to false
          curObj.__busy = false;
          // Trigger event complete
          curObj.elements.content.trigger("complete", [ curObj, curObj.elements ]);
        }
      });
    },
    // Set context of the current object
    __setContext: function(index, current) {
      // If current is not set, set it
      if (!current) {
        current = $(this.elements.items.get(index));
      }
      // Only set context if current is set
      if (current) {
        this.elements.index = parseInt(index,10);
        this.elements.current = current;
        // Return error, which states everything is ok
        return this.OK;
      }
      // Return error, because item doesn't exist for some unknown reason
      return this.setError(-2, "Item with index "+index+" doesn't exist.");
    },
    // Show loading progress element
    showProgress: function() {
      // Set progress element for later use
      var progress = this.elements.progress;
      // Only do something if progress is set
      if (progress.size() > 0) {
        // bind resize event and fire it for resizing
        this.elements.container.unbind("resize.progress").bind("resize.progress", function() {
           // If container is resized recalculate center
           progress.css($.getCenterPoint(progress, $(this)));
        }).resize();
      }
      // Show the progress element
      progress.show();
    },
    // Hide loading progress element
    hideProgress: function() {
      this.elements.progress.hide();
    },
    // End the lightbox
    end: function() {
      // Trigger event before end
      this.elements.content.trigger("beforeend", [ this, this.elements ]);
      // Empty content
      this.elements.content.html("&#160;");
      // Empty loader
      this.elements.loader.html("&#160;");
      // Hide dim element slowly
      this.elements.dim.animate({opacity: 0}, "slow", function() {
        // Remove dim element
        $(this).remove();
      });
      // Hide lightbox element slowly
      this.elements.lightbox.animate({opacity: 0}, "slow", function() {
        // Remove lightbox element
        $(this).remove();
      });
      // Trigger event afterend
      this.elements.content.trigger("afterend", [ this, this.elements ]);
    }
  });

  // Globally defined defaults.
  $.LightboxDefaults = {
    mode: "multi", // single multi
    // Set default width and height
    defaultWidth: 250,
    defaultHeight: 250,
    minWidth: 100,
    minHeight: 10,
    loading: "../images/lightbox/loading.gif", // Set loading image
    content: "image", // Choose one of the content function or create your own content and size function.
    dimOpacity: 0.4, // Set opacity of the dimmedscreen
    currentIndex: -1, // Set index if lightbox should be loaded when lightbox is initiated
    events: new $.LateBoundEvents(), // Must be instance of LateBoundEvents class
    navigation: "navigation", // Define navigation event here, creates navigation of lightbox, which is in variable events.
    end: "#ip-lightbox-dimscreen,#ip-lightbox .lightbox-content", // Define selector for ending the lightbox.
    startDirect: false // Do not start the lightbox directly;
  }; 

  // Globally defined content and size functions.
  $.LightboxContent = {
    // Lightbox element is image.
    image: {
      // Content function
      content: function(args) {
        // Get image from current element or descendant element
        var image = this.filter("img").size() > 0 ? $(this.filter("img").get(0)) : this.find("img:first");
        // imagename must start with thumb_
        var imageSrc = image.attr("src").replace("thumb_", "");
        var imageAlt = image.attr("alt");
        // Create content in loader element
        args.loader.append('<img src="'+imageSrc+'" alt="'+imageAlt+'" title="'+imageAlt+'" />');
        // Preload the image
				var preloader = new Image();
				// Create onload function to show the image only when loaded
				preloader.onload = function() {
				  // Empty onload event 
					preloader.onload = null;
				  // Empty preloader 
					preloader = null;
					// Trigger event that content is loaded
					args.content.trigger("contentloaded", [ args ]);
				};	
				// Set source for preloader, so onload will be triggered
				preloader.src = imageSrc;
      },
      // Size function
      size: function(args) {
        // Size is size of the loader object
        return {
          width:  args.loader.width(), 
          height: args.loader.height()
        };
      }
    },
    // Lightbox element is image.
    imagelist: {
      // Content function
      content: function(args) {
        // Get image from current element or descendant element
        var imageSrc = $(this).find(".source").text();
        var imageAlt = $(this).find(".source").attr("alt");
        var img = $('<img src="'+imageSrc+'" alt="'+imageAlt+'" title="'+imageAlt+'" />');
        args.loader.append(img);
        if ($(this).find(".description:has(*)").size() == 1) {
          $(this).attr("descId", $(this).find(".description").attr("id"));
        }
        // Preload the image
				var preloader = new Image();
				// Create onload function to show the image only when loaded
				preloader.onload = function() {
          var windowHeight = $(window).height() - 170;
          var windowWidth = $(window).width() - 70;

          var newHeight = preloader.height;
          var newWidth = preloader.width;
          if (windowHeight < preloader.height) {
            newHeight = windowHeight;
            newWidth = Math.round((preloader.width * newHeight) / preloader.height);
          }
          
          if (windowWidth < newWidth) {
            newWidth = windowWidth;
            newHeight = Math.round((preloader.height * newWidth) / preloader.width);
          }
          
          img.attr("width", newWidth);
          img.attr("height", newHeight);
          
				  // Empty onload event 
					preloader.onload = null;
				  // Empty preloader 
					preloader = null;
					// Trigger event that content is loaded
					args.content.trigger("contentloaded", [ args ]);
				};	
				// Set source for preloader, so onload will be triggered
				preloader.src = imageSrc;
      },
      // Size function
      size: function(args) {
        // Size is size of the loader object
        return {
          width:  args.loader.width(), 
          height: args.loader.height()
        };
      }
    },
    // Set content based on something that is on the page (maybe hidden and triggered by link or something else)
    loadedonpage: {
      content: function(args) {      
        // Content is already loaded somewhere on the page.
        var href = $(this).attr("href");
        if(!href && $(this).find("[href]:first").size() == 1) {
          href = $(this).find("[href]:first").attr("href");
        }
        href = href.substring(href.indexOf("#"));
        args.loader.append($(href).clone(true));
				
				args.content.trigger("contentloaded", [ args ]);
				// Return false to ensure nothing else is fired
        return false;
      },
      // Size function is same as image size function
      size: function(args) {
        return $.LightboxContent.image.size(args);
      }
    },
    // Set content based on something that is on the page (maybe hidden and triggered by link or something else)
    ajax: {
      content: function(args) {      
        // Content is already loaded somewhere on the page.
        var href = $(this).attr("href");
        if(!href && $(this).find("[href]:first").size() == 1) {
          href = $(this).find("[href]:first").attr("href");
        }
        args.loader.load(href, function() {
  				args.content.trigger("contentloaded", [ args ]);
        });
				
				// Return false to ensure nothing else is fired
        return false;
      },
      // Size function is same as image size function
      size: function(args) {
        return $.LightboxContent.image.size(args);
      }
    }
  };

  // Globally defined events
  $.LightboxEvents = {
    hideform: {
      // Prebind events
      bind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.add("beforeload.hideform", this.hideFormElements, true);
        lateBoundEventsObj.add("afterend.hideform", this.showFormElements, true);
      },
      // Unbind events
      unbind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.remove("beforeload", "hideform");
        lateBoundEventsObj.remove("afterend", "hideform");
      },
      // Hide all formelements on the page
      hideFormElements: function(event, sender, args) {
        $("select, iframe").css("visibility", "hidden");
      },
      // Show all formelements on the page
      showFormElements: function(event, sender, args) {
        $("select, iframe").css("visibility", "");
      }
    },
    // Slide down slide-out div beneath content
    slidedown: {
      // Prebind events
      bind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.add("beforeload.slidedown", this.hide, true);
        lateBoundEventsObj.add("complete.slidedown", this.slide, true);
      },
      // Unbind events
      unbind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.remove("beforeload", "slidedown");
        lateBoundEventsObj.remove("complete", "slidedown");
      },
      // Hide slider before loading content
      hide: function(event, sender, args) {
        var slider = args.container.find("#slideout-under");
        slider.css("visibility", "hidden");
      },
      // Slide slider to height
      slide: function(event, sender, args) {
        var slider = args.container.find("#slideout-under");
        // Slide only when it has content
        if (slider.find("> *").size() > 0) {
          // Set slider width
          slider.width(args.content.width());
          // Animate the height of the container so slider is completely in site
          args.container.animate({ height: "+="+slider.height() }, "normal", function() {
            // Show the content of the slider
            slider.css("visibility", "");
          });
        };
      }
    },
    // Default navigation in slider
    navigation: {
      bind: function(lateBoundEventsObj) {
        // prebind events here
        // bind slidedown events
        $.LightboxEvents.slidedown.bind(lateBoundEventsObj);
        lateBoundEventsObj.add("beforestart.navigation", this.init, true);
        lateBoundEventsObj.add("afterload.navigation", this.show, true);
      },
      unbind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.remove("beforestart", "navigation");
        lateBoundEventsObj.remove("afterload", "navigation");
      },
      // Define params
      __prev: null,
      __next: null,
      __position: null,
      __number: null,
      // Set default settings
      defaults: {
        nextHtml: "next",
        previousHtml: "previous",
        positionHtml: "Image #CURRENT# from #TOTAL#",
        container: "#slideout-under",
        position: "prepend"
      },
      init: function(event, sender, args) {
        // Create navigation here, bottom of the content.
        var config = $.extend($.LightboxEvents.navigation.defaults, args.config.NavigationOptions || {});
        var slideout = args.container.find(config.container);
        // Only make a new navigation node, if only one exists.
        slideout.find("#lightbox-navigation").remove();
        __prev = $('<div id="lightbox-navigation-previous"><a href="#">'+config.previousHtml+'</a></div>').click(function() {
          $.LightboxEvents.navigation.hide();
          sender.showItem.apply(sender, [ args.index - 1 ]);
          return false;
        });
        __next = $('<div id="lightbox-navigation-next"><a href="#">'+config.nextHtml+'</a></div>').click(function() {
          $.LightboxEvents.navigation.hide();
          sender.showItem.apply(sender, [ args.index + 1 ]);
          return false;
        });
        __position = $('<div id="lightbox-navigation-number">'+ config.positionHtml.replace("#CURRENT#", '<span class="current"></span>').replace("#TOTAL#", args.items.size()) +'</div>');
        __number = __position.find(".current");
        var nav = $('<div id="lightbox-navigation"></div>').append(__position).append(__next).append(__prev);
        // Set navigation element.
        if (config.position == "prepend") {
          // First element in the container
          slideout.prepend(nav);
        }
        else if ($.isFunction(config.position)) {
          // User function to set the navigation
          config.position.apply(sender, [ nav, config, args ]);
        }
        else if (args.container.find(config.position).size() > 0) {
          // It's a defined place in the container, so prepend it there
          args.container.find(config.position).prepend(nav);
        }
        else {
          // Else last element in the container
          slideout.append(nav);
        }
      },
      // Show or hide next and previous links.
      show: function(event, sender, args) {
        if (args.index == 0) {
          // If index is zero, then previous link invisible
          __prev.css("visibility", "hidden");
        }
        else {
          // If index is other then zero, then previous link visible
          __prev.css("visibility", "visible");
        }
        if (args.index >= (args.items.size() - 1)) {
          // If index is last in the row, then next link invisible
          __next.css("visibility", "hidden");
        }
        else {
          // If index is other then last, then next link visible
          __next.css("visibility", "visible");
        }
        // Set number of the current item
        __number.html(args.index + 1 + " ");
      },
      hide: function() {
        // Hide navigation
        __prev.add(__next).css("visibility", "hidden");
      }
    },
    // Create slideshow navigation.
    slideshow: {
      bind: function(lateBoundEventsObj) {
        // prebind events here
        $.LightboxEvents.slidedown.bind(lateBoundEventsObj);
        lateBoundEventsObj.add("beforestart.slideshow", this.init, true);
        lateBoundEventsObj.add("beforeload.slideshow", this.suspend, true);
        lateBoundEventsObj.add("afterload.slideshow", this.play, true);
      },
      unbind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.remove("beforestart", "slideshow");
        lateBoundEventsObj.remove("beforeload", "slideshow");
        lateBoundEventsObj.remove("afterload", "slideshow");
      },
      // Define fields (must be object, type like string, because these can't be used in events)
      __config: null,
      // Set default settings
      defaults: {
        forwardHtml: "next",
        backwardHtml: "previous",
        playHtml: "play",
        suspendHtml: "suspend",
        positionHtml: "Image #CURRENT# from #TOTAL#",
        container: "#slideout-under",
        position: "prepend",
        interval: 4000,
        direction: "forward", // or backward
        __prev: null,
        __next: null,
        __play: null,
        __playbutton: null,
        __position: null,
        __number: null,
        __timer: -1
      },
      // Define events here
      init: function(event, sender, args) {
        // Add slide show html to slide-down,
        // forward: move to next and keep moving forward
        // backward: move to previous and keep moving backward
        // Suspend/play: suspend or start slideshow
        // Create navigation here, bottom of the content.
        __config = $.extend($.LightboxEvents.slideshow.defaults, args.config.SlideshowOptions || {});
        
        if (!__config.interval || __config.interval == "" || isNaN(__config.interval)) {
          __config.interval = 4000;
        }
        
        var slideout = args.container.find(__config.container);
        // First remove old slideshow
        slideout.find("#lightbox-navigation-slideshow").remove();
        // Create backward button
        __config.__prev = $('<div id="lightbox-navigation-slideshow-backward"><a href="#">'+__config.backwardHtml+'</a></div>').click(function() {
          var index = args.index - 1;
          if (index < 0) {
            index = args.items.size() - 1;
          }
          __config.direction = "backward";
          sender.showItem.apply(sender, [ index ]);
        });
        __config.__next = $('<div id="lightbox-navigation-slideshow-forward"><a href="#">'+__config.forwardHtml+'</a></div>').click(function() {
          var index = args.index + 1;
          if (index >= args.items.size()) {
            index = 0;
          }
          __config.direction = "forward";
          sender.showItem.apply(sender, [ index ]);
        });
        __config.__play = $('<div id="lightbox-navigation-slideshow-play"><a href="#">'+ __config.suspendHtml +'</a></div>');
        __config.__playbutton = __config.__play.find("a").toggle(function() {
          // Show play button and call suspend
          __config.__playbutton.html(__config.playHtml);
          $.LightboxEvents.slideshow.suspend(event, sender, args);
        }, function() {
          // Show suspend button and call start
          __config.__playbutton.html(__config.suspendHtml);
          $.LightboxEvents.slideshow.play(event, sender, args);
        });
        __config.__position = $('<div id="lightbox-navigation-slideshow-number">'+ __config.positionHtml.replace("#CURRENT#", '<span class="current"></span>').replace("#TOTAL#", args.items.size()) +'</div>');
        __config.__number = __config.__position.find(".current");
        var nav = $('<div id="lightbox-navigation-slideshow"></div>').append(__config.__play).append(__config.__position).append(__config.__next).append(__config.__prev);
        // Set navigation element.
        if (__config.position == "prepend") {
          // First element in the container
          slideout.prepend(nav);
        }
        else if ($.isFunction(__config.position)) {
          // User function to set the navigation
          __config.position.apply(sender, [ nav, __config, args ]);
        }
        else if (args.container.find(__config.position).size() > 0) {
          // It's a defined place in the container, so prepend it there
          args.container.find(__config.position).prepend(nav);
        }
        else {
          // Else last element in the container
          slideout.append(nav);
        }
      },
      suspend: function(event, sender, args) {
        // suspend (read "end") timer, because loading has started
        clearTimeout(__config.__timer);
      },
      play: function(event, sender, args) {
        // Set number of the current item
        __config.__number.html(args.index + 1 + " ");
        // start timer, then load next
        __config.__timer = setTimeout(function() {
          // Load next or previous based on direction
          if (__config.direction == "forward") {
            __config.__next.click();
          }
          else {
            __config.__prev.click();
          }
        }, __config.interval);
      }
    },    
    description: {
      bind: function(lateBoundEventsObj) {
        // prebind events here
        $.LightboxEvents.slidedown.bind(lateBoundEventsObj);
        lateBoundEventsObj.add("beforestart.description", this.init, true);
        lateBoundEventsObj.add("afterload.description", this.show, true);
      },
      unbind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.remove("beforestart", "description");
        lateBoundEventsObj.remove("afterload", "description");
      },
      __container: null,
      __content: null,
      __config: null,
      // Set default settings
      defaults: {
        position: "append"
      },
      init: function(event, sender, args) { 
        __config = $.extend($.LightboxEvents.description.defaults, args.config.DescriptionOptions || {});

        // Create description here, bottom of the content.
        var slider = args.container.find("#slideout-under");
        if (slider.find("#lightbox-description").size() == 0) {
          this.__container = $('<div id="lightbox-description"><div class="lightbox-description-inner"></div></div>');
          this.__content = this.__container.find(".lightbox-description-inner");
          // Set description element.
          if (__config.position == "append") {
            // Last element in the container, which is the default
            slider.append(this.__container);
          }
          else if ($.isFunction(__config.position)) {
            // User function to set the navigation
            __config.position.apply(sender, [ this.__container, __config, args ]);
          }
          else if (args.container.find(__config.position).size() > 0) {
            // It's a defined place in the container, so prepend it there
            args.container.find(__config.position).prepend(this.__container);
          }
          else {
            // Else first element in the container
            slider.prepend(this.__container);
          }
        }
      },
      show: function(event, sender, args) {
        if (args.current.attr("descId")) {
          this.__content.html($("#"+args.current.attr("descId")).html());
        }
        else if (args.current.attr("alt")) {
          this.__content.html($("<p>" + args.current.attr("alt") + "</p>"));
        }
        else if (args.current.attr("title")) {
          this.__content.html($("<p>" + args.current.attr("title") + "</p>"));
        }
        else if (args.current.find("[alt]:first").size() > 0) {
          this.__content.html($("<p>" + args.current.find("[alt]:first").attr("alt") + "</p>"));
        }
        else if (args.current.find("[title]:first").size() > 0) {
          this.__content.html($("<p>" + args.current.find("[title]:first").attr("title") + "</p>"));
        }
      }
    },
    header: {
      bind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.add("beforeshow.header", this.load, true);
      },
      unbind: function(lateBoundEventsObj) {
        // prebind events here
        lateBoundEventsObj.remove("beforeshow", "header");
      },
      load: function(event, sender, args) { 
        // Create navigation here, bottom of the content.
        var header = $('<div id="lightbox-header"><div class="lightbox-header-inner"><a class="close" href="#">X</a></div></div>');
        if ($.browser.msie && $.browser.version.substring(0, 1) == "6") {
          header.css("width", args.loader.width());
        }
        args.loader.prepend(header);
        header.find("a.close").click(function() {
          sender.end.apply(sender);
          return false;
        });
      }
    }
  };
})(jQuery);

