;
(function($) {

    function findOuterBody() {
        return $(document).find('body');
    }
                      
    /**
     * If there is a shadowbox open, close it
     */
    $.closeShadowbox = function() {             
        findOuterBody().data('shadow-content-close').click();
    }

    /**
     * Creates a shadow box over the entire window and inserts content into it.
     *
     * @param html The content to display.  This can be any valid JQuery selector.
     *     If this is left blank, the last shown content will be shown again 
     *
     * @param options Options to display.
     *   - speed:   The speed of the show and hide animations. Default is 200.
     *   - show:    If this is false, the content pane will be initialized but the
     *              shadowbox won't actually be shown; call this method again without
     *              any html to show the shadowbox.  Defaults to true.
     *   - class:   An optional class to assign to the outer content pane div.
     *   - closeOnClick:  If this is true (default), any mouse click on the shadow
     *   				  will close the shadow box.  If this is false, only the 
     *   				  close button will close the shadow box.
     */
    $.shadowbox = function(html, options) {
        var defaultOptions = {
            'speed': 200,
            'show': true,
            'class': null,
            'closeOnClick': true
        }
        options = $.extend(defaultOptions, options);
        
        var body = findOuterBody();
        var doc = body.get(0).ownerDocument;
        
        // Create the shadow
        var shadow = body.data('shadow-pane');
        if (!shadow) {
            shadow = $(doc.createElement("div"))
                .addClass('shadow-pane')
                .appendTo(body)
                .hide();
            if (options.closeOnClick) {
            	shadow.click($.closeShadowbox);
            }
            body.data('shadow-pane', shadow);
        }
                
        // Create the content pane
        var content = body.data('shadow-content-pane');
        if (!content) {
            content = $(doc.createElement("div"))
                .addClass('shadow-content-pane')
                .appendTo(body)
                .hide();

            // Add an X in the corner
            var x = $(doc.createElement("div"))
                .html('<a href="#"><b>[X]</b></a>')
                .addClass('close-button')
                .click(function() {
                    shadow.fadeOut(options.speed);
                    content.fadeOut(options.speed, function() {
                    	if (options['class']) {
                    		content.removeClass(options['class']);
                    	}
                    });
                    return false;
                })
                .appendTo(content);
                       
            body.data('shadow-content-pane', content);
            body.data('shadow-content-close', x);
        }
        
        var container = body.data('shadow-container');
        if (!container) {
            container = $(doc.createElement("div"))
                .addClass('shadow-container')
                .prependTo(content);
            body.data('shadow-container', container);
        }
        
        // If the user specified a content class to use, add it
        if (options['class']) {
            content.addClass(options['class']);
        }
        
        // Add the content
        if (html) {
            container.html(html);
        }
        
        function showShadowBox() {
            // Show the shadow
            if (content.is(":hidden") && shadow.is(":hidden") && options.show) {
                var win_height = $(window).height();
                var win_width = $(window).width();
                var doc_height = $(document).height();
                var doc_width = $(document).width();
                
                shadow
                    .height(doc_height)
                    .width(doc_width)
                    .css('opacity', 0);
                
                // Calculate the center point of the window
                var top = (win_height - content.outerHeight(true)) / 2;
                var left = (win_width - content.outerWidth(true)) / 2;

                // Calculate the start of the visible portion of the window                
                var scrollTop = 0;
                var scrollLeft = 0;
                
                // Adjust for the case where we're in a nested frame
                var offset = content.offset();
                scrollTop = Math.max(scrollTop, offset.top);
                scrollLeft = Math.max(scrollLeft, offset.left);
                
                // Make sure that the top appears in view
                top = Math.max(top + scrollTop, scrollTop + 5);
                left = Math.max(left + scrollLeft, scrollLeft);
                
                content.css({
                    top: Math.floor(top),
                    left: Math.floor(left)
                });
                            
                shadow
                    .show()
                    .fadeTo(options.speed, 0.5);
                content.fadeIn(options.speed);
            }
        }
        
        // Give the content time to render, so we can get an accurate width
        setTimeout(showShadowBox, 10);
        
        // Don't break the chain
        return this;
    }
    
    /**
     * Shows a copy of the selected elements in a shadowbox.
     * Just like calling $.shadowbox() on the given nodes.
     * If the 'clone' option is set (default), the node will be cloned
     * before being displayed.
     */
    $.fn.shadowbox = function(options) {
        var defaultOptions = {
            'clone': true
        }
        options = $.extend(defaultOptions, options);
        
        var nodes = this;
        if (options.clone) {
            nodes = this.clone();
        }
        
        $.shadowbox(nodes, options);
        return this;
    }
    
})(jQuery);
