(function($){

        var dropShadowZindex = 1;  //z-index counter

        $.fn.dropShadow = function(options)
        {
                // Default options
                var opt = $.extend({
                        left: 4,
                        top: 4,
                        blur: 2,
                        opacity: .5,
                        color: "black",
                        swap: false
                        }, options);
                var jShadows = $([]);  //empty jQuery collection
                
                // Loop through original elements
                this.not(".dropShadow").each(function()
                {
                        var jthis = $(this);
                        var shadows = [];
                        var blur = (opt.blur <= 0) ? 0 : opt.blur;
                        var opacity = (blur == 0) ? opt.opacity : opt.opacity / (blur * 8);
                        var zOriginal = (opt.swap) ? dropShadowZindex : dropShadowZindex + 1;
                        var zShadow = (opt.swap) ? dropShadowZindex + 1 : dropShadowZindex;
                        
                        // Create ID for shadow
                        var shadowId;
                        if (this.id) {
                                shadowId = this.id + "_dropShadow";
                        }
                        else {
                                shadowId = "ds" + (1 + Math.floor(9999 * Math.random()));
                        }

                        // Modify original element
                        $.data(this, "shadowId", shadowId); //store id in expando
                        $.data(this, "shadowOptions", options); //store options in expando
                        jthis
                                .attr("shadowId", shadowId)
                                .css("zIndex", zOriginal);
                        if (jthis.css("position") != "absolute") {
                                jthis.css({
                                        position: "relative",
                                        zoom: 1 //for IE layout
                                });
                        }

                        // Create first shadow layer
                        bgColor = jthis.css("backgroundColor");
                        if (bgColor == "rgba(0, 0, 0, 0)") bgColor = "transparent";  //Safari
                        if (bgColor != "transparent" || jthis.css("backgroundImage") != "none" 
                                        || this.nodeName == "SELECT" 
                                        || this.nodeName == "INPUT"
                                        || this.nodeName == "TEXTAREA") {                
                                shadows[0] = $("<div></div>")
                                        .css("background", opt.color);                                                                
                        }
                        else {
                                shadows[0] = jthis
                                        .clone()
                                        .removeAttr("id")
                                        .removeAttr("name")
                                        .removeAttr("shadowId")
                                        .css("color", opt.color);
                        }
                        shadows[0]
                                .addClass("dropShadow")
                                .css({
                                        height: jthis.outerHeight(),
                                        left: blur,
                                        opacity: opacity,
                                        position: "absolute",
                                        top: blur,
                                        width: jthis.outerWidth(),
                                        zIndex: zShadow
                                });
                                
                        // Create other shadow layers
                        var layers = (8 * blur) + 1;
                        for (i = 1; i < layers; i++) {
                                shadows[i] = shadows[0].clone();
                        }

                        // Position layers
                        var i = 1;                        
                        var j = blur;
                        while (j > 0) {
                                shadows[i].css({left: j * 2, top: 0});           //top
                                shadows[i + 1].css({left: j * 4, top: j * 2});   //right
                                shadows[i + 2].css({left: j * 2, top: j * 4});   //bottom
                                shadows[i + 3].css({left: 0, top: j * 2});       //left
                                shadows[i + 4].css({left: j * 3, top: j});       //top-right
                                shadows[i + 5].css({left: j * 3, top: j * 3});   //bottom-right
                                shadows[i + 6].css({left: j, top: j * 3});       //bottom-left
                                shadows[i + 7].css({left: j, top: j});           //top-left
                                i += 8;
                                j--;
                        }

                        // Create container
                        var divShadow = $("<div></div>")
                                .attr("id", shadowId) 
                                .addClass("dropShadow")
                                .css({
                                        left: jthis.position().left + opt.left - blur,
                                        marginTop: jthis.css("marginTop"),
                                        marginRight: jthis.css("marginRight"),
                                        marginBottom: jthis.css("marginBottom"),
                                        marginLeft: jthis.css("marginLeft"),
                                        position: "absolute",
                                        top: jthis.position().top + opt.top - blur,
                                        zIndex: zShadow
                                });

                        // Add layers to container        
                        for (i = 0; i < layers; i++) {
                                divShadow.append(shadows[i]);
                        }
                        
                        // Add container to DOM
                        jthis.after(divShadow);

                        // Add shadow to return set
                        jShadows = jShadows.add(divShadow);

                        // Re-align shadow on window resize
                        $(window).resize(function()
                        {
                                try {
                                        divShadow.css({
                                                left: jthis.position().left + opt.left - blur,
                                                top: jthis.position().top + opt.top - blur
                                        });
                                }
                                catch(e){}
                        });
                        
                        // Increment z-index counter
                        dropShadowZindex += 2;

                });  //end each
                
                return this.pushStack(jShadows);
        };


        $.fn.redrawShadow = function()
        {
                // Remove existing shadows
                this.removeShadow();
                
                // Draw new shadows
                return this.each(function()
                {
                        var shadowOptions = $.data(this, "shadowOptions");
                        $(this).dropShadow(shadowOptions);
                });
        };


        $.fn.removeShadow = function()
        {
                return this.each(function()
                {
                        var shadowId = $(this).shadowId();
                        $("div#" + shadowId).remove();
                });
        };


        $.fn.shadowId = function()
        {
                return $.data(this[0], "shadowId");
        };


        $(function()  
        {
                // Suppress printing of shadows
                var noPrint = "<style type='text/css' media='print'>";
                noPrint += ".dropShadow{visibility:hidden;}</style>";
                $("head").append(noPrint);
        });

})(jQuery);
