/*
	AUTHOR: Larry Stevens (McLars@eyebulb.com)

	VERSION: Drop Shadow 1.2  12-1-2007

	SYNTAX: $(selector).dropShadow(options);  // Creates new drop shadows
					$(selector).shadowId();  // Returns an existing drop shadow's ID

	REQUIRES: jquery.js and jquery.dimensions.js

	This jQuery UI plug-in adds soft drop shadows to page elements. It has only
	two public methods, dropShadow, which accepts an optional parameter object,
	and shadowId, which returns the ID of selected shadows.
	The options are as follows:

		left    : integer (default = 4)
		top     : integer (default = 4)
		blur    : integer (default = 1)
		opacity : decimal (default = 0.5)
		color   : string (default = "black")
		swap    : boolean (default = false)

	The left and top parameters specify the distance and direction (x,y) in	pixels,
	to offset the shadow. The blur parameter specifies the amount of spread or
	dispersion of the shadow. This should be a very low integer, from 0, for a
	sharp shadow, to something less than 4 or 5--processing and distortion becomes
	excessive at higher numbers. The opacity parameter should be a decimal value
	between 0 and 1. Color is specified in the usual manner, with a color name or
	hexadecimal. The swap parameter	will reverse the stacking order of the original
	and the shadow. This would only be used for special effects.

	If no parameters are provided, the default offset is 4 pixels in the bottom-
	right direction, with a slight amount of blur, and half-opacity black. This
	should work well for smaller fonts and elements, with the minimum performance
	impact. If you only have a few larger elements to shadow, you may want to try
	using larger offsets and blurs, or multiple shadows.

	The dropShadow method attempts to determine whether the selected elements have
	transparent backgrounds. If you want to shadow the inside of an element, like
	text or a transparent image, it must not have a background-color or background-
	image style. If the element has a solid background it will create a rectangular
	shadow around the outside box.

	Newly created shadow elements are given a random ID and two classes (see
	following section). The original elements are given a new attribute named
	"shadowId," which is set to the ID of the associated shadow. The shadow
	elements are positioned absolutely one layer below the original element,
	which is positioned relatively.

	All shadows have the "dropShadow" class, which may be used to globally change
	styles or other manipulations, like deletion. To access a single shadow, read
	the "shadowId" attribute of the original element or call the shadowId method.
	For example:

		var myTextShadow = $("#myText").attr("shadow");  or
		var myTextShadow = $("#myText").shadowId();

	The interior shadows also have the class "dropShadowInner" and the outside
	shadows also have the class "dropShadowOuter." The interior shadows use the
	color style but the outside shadows use the background style. For example:

		.dropShadowInner {color: red !important;}   for transparent elements, or
		.dropShadowOuter {background: red !important;}   for solid elements

	The dropShadow method supports chaining, so you can add multiple shadows in a
	single statement. This is useful for darkening or expanding the shadow.
	However, only the last shadow's ID will be available in the original element.
	If you need to manipulate the shadows later, you should store each ID before
	applying additional shadows.

	EXAMPLES:
		$("h1").dropShadow();                   //default, 4 pixels, bottom-right
		$("h1").dropShadow({left: -4, top: 4})  //bottom-left
		$("h1").dropShadow({left: 4, top: -4})  //top-right
		$("h1").dropShadow({left: -4, top: -4}) //top-left
		$("h1").dropShadow({left: 6, top: 6});  //larger offset
		$("h4").dropShadow({left: 1, top: 1});  //smaller offset

	ISSUES:
		1) Limited styling of shadowed elements by ID, prefer class or inline styles.
		2) Some elements don't re-adjust properly when window resizes or font size
			 changes. May require setting the height and width of the element.
		3) A few elements, like checkboxes and radio buttons, do not shadow well.
			 Form elements shadow as transparent elements in Opera.
		4) Shadow positions are off when printing. Recommend using the following:
					<style type="text/css" media="print">
						.shadowIn, .shadowOut { visibility: hidden; }
					</style>
*/

var dropShadowZindex = 1;  // Global stack counter

(function($){
	jQuery.fn.dropShadow = function(options)
	{
		// Default options
		var opt = $.extend({
			left: 4,
			top: 4,
			blur: 1,
			opacity: .5,
			color: "black",
			swap: false
			},options);

		// Loop through collection of elements
		return this.not(".dropShadow").each(function()
		{
			var jthis = jQuery(this);
			var shadows = [];
			var blur = opt.blur;
			var shadowId = "ds" + (1 + Math.floor(9999 * Math.random()));
			var zOriginal = (opt.swap) ? dropShadowZindex : dropShadowZindex + 1;
			var zShadow = (opt.swap) ? dropShadowZindex + 1 : dropShadowZindex;

			// Check for transparency
			var bgc, bgi, pos;
			if (this.currentStyle) {
				bgc = this.currentStyle.backgroundColor;
				bgi = this.currentStyle.backgroundImage;
				pos = this.currentStyle.position;
			}
			else {
				bgc = document.defaultView.getComputedStyle(this, null)
							.getPropertyValue("background-color");
				bgi = document.defaultView.getComputedStyle(this, null)
							.getPropertyValue("background-image");
				pos = document.defaultView.getComputedStyle(this, null)
							.getPropertyValue("position");
				if (bgc == "rgba(0, 0, 0, 0)") bgc = "transparent";  // Safari
			}

			// Modify original element
			$.data(this, "shadowId", shadowId); //store id in expando
			jthis
				.attr("shadowId", shadowId)
				.css("zIndex", zOriginal);
			if (pos != "absolute") {
				jthis.css({
					position: "relative",
					zoom: 1  // IE layout
				});
			}

			// Create first shadow layer
			if (bgc == "transparent" && bgi == "none") {  // Copy original
				shadows[0] = jthis
					.clone()
					.removeAttr("id")
					.removeAttr("name")
					.removeAttr("shadowId")
					.addClass("dropShadowInner")
					.css({
						color: opt.color,
						height: jthis.outerHeight(),
						width: jthis.outerWidth()
					});
			}
			else {  // Create empty div
				shadows[0] = $("<div></div>")
					.addClass("dropShadowOuter")
					.css({
						background: opt.color
					});
				switch(this.nodeName) {
					case "SELECT":
						shadows[0].css({
							height: jthis.height() - 1,
							width: jthis.width() - 1
						});
						break;
					case "TEXTAREA":
						shadows[0].css({
							height: jthis.innerHeight() + 1,
							width: jthis.innerWidth() + 1
						});
						break;
					case "TABLE":
						shadows[0].css({
							height: jthis.outerHeight() + 1,
							width: jthis.outerWidth() + 1
						});
						break;
					default:
						shadows[0].css({
							height: jthis.outerHeight(),
							width: jthis.outerWidth()
						});
				}
			} // End if transparent
			shadows[0].style = this.style;
			shadows[0]
				.addClass("dropShadow")
				.css({
					left: blur,
					opacity: opt.opacity / (blur * 8),
					position: "absolute",
					top: blur,
					zIndex: zShadow
				});

			// Create other shadow layers
			var min = (blur == 0) ? 1 : blur;
			var layers = (8 * min) + 1;
			for (i = 1; i < layers; i++) {
				shadows[i] = shadows[0].clone();
			}

			// Position layers
			var i = 1;
			var j = blur;
			do {
					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--;
			} while (j > 0);

			// Create container
			var divShadow = $("<div></div>")
				.attr("id", shadowId)
				.addClass("dropShadow")
				.css({
					left: jthis.position().left + opt.left - blur,
					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);

			// Re-align shadow on window resize
			/*$(window).resize(function()
			{
				$("#" + shadowId).css({
					left: jthis.position().left + opt.left - blur,
					top: jthis.position().top + opt.top - blur
				});
			});*/

			// Increment stack counter
			dropShadowZindex += 2;

		});  // End each
	}
})(jQuery);


jQuery.fn.shadowId = function()
{
	return $.data(this[0], "shadowId");
}
