(function($) {  // create the encapsulation

  function default_content() {
    return "<h3> Default Content </h3> <p> You must give the lightbox plugin a function called 'content_function' in the options which generates the content. </p>";
  }

  function default_wait_content() {
    // make mask opaque
    $('#lightbox_dimming_element').css('background-color','#000');
    $('#lightbox_dimming_element').fadeTo(0, 0.5);
    return '<span> <img src="/images/ajax-loader.gif" alt="loading..." /> </span>';
  }

  function install_lightbox( lightboxed_element, lb_options ) {
    // get the dimensions
    lightboxed_element = $(lightboxed_element);

    // append the necessary elements to the inside of that
    var outer_wrapper   = $('<div id="lightbox_outer_wrapper"   style="display: none; position: absolute" ></div>');
    var dimmer          = $('<div id="lightbox_dimming_element" style="display: none; position: absolute" ></div>');
    var content_wrapper = $('<div id="lightbox_content_wrapper" style="display: none;"></div>');
    var content         = $('<div id="lightbox_content_element" style="display: inline-block" ></div>');
    
    // add the mode to the outer wrapper
    outer_wrapper.addClass(lb_options.mode);

    // assign a higharchy
    outer_wrapper.append(dimmer);
    outer_wrapper.append(content_wrapper);
    content_wrapper.append(content);
    lightboxed_element.prepend(outer_wrapper);

    // return the lightbox object
    var lb = $.extend( {
      parent          : lightboxed_element,
      outer_wrapper   : outer_wrapper,
      dimmer          : dimmer,
      content_wrapper : content_wrapper,
      content         : content,
      timer_id        : false }, lb_options );

      // add a method to jQuery
      $.extend({
        lightbox_update : function(content, callback) {
          if ( callback === undefined ) callback = function() {};
          update_content(lb, content, callback); },

          lightbox_wait   : function() { wait(lb); },

          lightbox_change_mode : function (mode, timeout) {
            if ( timeout === undefined ) timeout = false;
            change_mode(lb, mode, timeout); },

            lightbox_on_close : function(closing_function) { lb.on_close = closing_function; }
          });

          return lb;
        }

        function change_mode(lb, mode, timeout) {
          if ( mode != 'notify' && lb.mode == 'notify' && lb.timeout !== false) clearTimeout( lb.timer_id );
          lb.mode = mode;
          lb.timeout = timeout;
          if ( mode == 'notify' ) set_timeout( lb );
        }


        // lb is a lightbox object ( see install_lightbox );
        function set_dimensions(lb) {

          // minimize string operations: 
          var height = lb.parent.height().toString() + "px";
          var width = lb.parent.width().toString() + "px";

          lb.outer_wrapper.css("height", height );
          lb.outer_wrapper.css("width", width );
          lb.dimmer.css("height", height );
          lb.dimmer.css("width", width );
        }




        // the close animation
        function close_lightbox(lb, callback) {
          function n_callback() {
            if ( callback !== undefined ) callback();
            lb.on_close();
          }
          lb.content_wrapper.slideUp(lb.speed, function() { lb.dimmer.fadeOut(lb.speed, function() { remove_lightbox(lb); n_callback(); }); });
        }

        function remove_lightbox(lb) {
          var wrapper = $("<div>").append(lb.outer_wrapper);
          wrapper.html("");
        }


        function set_timeout( lb ) {
          lb.timer_id = setTimeout( function() { 
            if ( lb.timeout === false ) return;
            else close_lightbox(lb); },
            lb.timeout === false ? 0 : lb.timeout );
          }

          // load the content and run the animation
          function show(lb) {
            lb.outer_wrapper.css("display", "block");

            if ( lb.mode != 'wait' && lb.mode != 'force-interact') { 
              lb.content.append( '<br /><br /><a href="#" id="lightbox_close"> close </a>' );
            }

            lb.content.prepend($(lb.wait_content()).addClass("lightbox_busy_waiting")); // add some busy waiting content
            animate_in( lb, lb.content_function );



            // bind the close button
            $("#lightbox_close").click( function() { close_lightbox(lb); return false; } );
          }

          function wait(lb) {
            lb.content.children(":first").remove();
            lb.content.prepend($(lb.wait_content()).addClass("lightbox_busy_waiting")); // add some busy waiting content
          }

          function update_content(lb, content, callback){
            if ( lb.mode == "wait" ) {
              close_lightbox(lb, callback);
              return;
            }

            if ( lb.mode == 'notify' )
            set_timeout(lb); // setTimeout

            $(".lightbox_busy_waiting").remove();
            lb.content.prepend(content);
            callback();
          };

          function animate_in( lb, callback ) {
            lb.content_wrapper.css("position", "absolute");
            if ( lb.parent.attr("tagName") == "BODY" ) {
              var offset = jQuery(window).scrollTop();
            } else {
              var offset = 0;
            }
            lb.content_wrapper.css("top", offset + "px");
            lb.dimmer.fadeIn(lb.speed, function() { lb.content_wrapper.slideDown( lb.speed, callback ); });   // animate with callback
          }

          $.fn.lightbox = function( options ) {
            // mode: one of 'interact', 'force-interact', 'notify', or 'wait'

            var defaults = {
              mode               : 'interact',
              dim_on_selector    : this,
              top                : "center",
              content_function   : default_content,
              wait_content       : default_wait_content,
              timeout            : 2000,
              speed              : 250,
              on_close           : function() {} };

              options = $.extend( defaults, options );    
              return this.each( function () {
                var lb = install_lightbox(options.dim_on_selector, options);
                set_dimensions(lb);
                show(lb);
              });
            };
})(jQuery); // Execute the encapsulation now!

