/*
	VERSION: Drop Shadow jQuery Plugin 1.5  12-10-2007

	REQUIRES: jquery.js and jquery.dimensions.js

	SYNTAX: $(selector).dropShadow(options);  // Creates new drop shadows
					$(selector).redrawShadow();       // Redraws shadows on elements
					$(selector).removeShadow();       // Removes shadows from elements
					$(selector).shadowId();           // Returns an existing shadow's ID

	OPTIONS:

		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, in	pixels, to
	offset the shadow. The blur parameter specifies the spread, or dispersion, of
	the shadow. This should be a very low integer, in a range from one to about
	four or five--higher values increase the processing load. The opacity parameter
	should be a decimal value between zero and one or two. Color is specified in 
	the usual manner, with a color name or hex value. The swap parameter	reverses
	the stacking order of the original and the shadow.

	EXPLANATION:
	
	This jQuery plug-in adds soft drop shadows behind page elements. It is only
	intended for adding a few drop shadows to mostly stationary objects, like a
	page heading, a photo, or a content container.

	The shadows it creates are not bound to the original elements, so they won't
	move or change size automatically if the original elements change. A window
	resize event listener is assigned, which should re-align the shadows in many
	cases, but if the elements otherwise move or resize you will have to handle
	those events manually. Shadows can be redrawn with the redrawShadow() method
	or removed with the removeShadow() method. The redrawShadow() method uses the
	same options used to create the original shadow. If you want to change the
	options, you should remove the shadow first and then create a new shadow.
	
	The dropShadow method returns a jQuery collection of the new shadow(s). If
	further manipulation is required, you can store it in a variable like this:

		var myShadow = $("#myElement").dropShadow();

	You can also read the ID of the shadow from the original element at a later
	time. To get a shadow's ID, either read the shadowId attribute of the
	original element or call the shadowId() method. For example:

		var myShadowId = $("#myElement").attr("shadowId");  or
		var myShadowId = $("#myElement").shadowId();

	If the original element does not already have an ID assigned, a random number
	will be used for the shadow's ID. However, if the original does have an ID,
	the shadow's ID will be the letters "ds_" and the original ID. For example, if
	your element's ID is "myElement", the shadow's ID will be "ds_myElement".

	If you have a long piece of text and the user resizes the	window so that the
	text wraps or unwraps, the shape of the text changes and the words are no
	longer in the same positions. In that case, you can either preset the height
	and width, so that it becomes a fixed box, or you can shadow each word
	separately, like this:

		<h1><span>Your</span> <span>Page</span> <span>Title</span></h1>

		$("h1 span").dropShadow();

	The dropShadow method attempts to determine whether the selected elements have
	transparent backgrounds. If you want to shadow the content inside 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.

	The shadow elements are positioned absolute one layer below the original 
	element, which is positioned relative (unless it's already absolute). 

	All shadows will have the "dropShadow" class, for selecting with CSS or jQuery.

	ISSUES:
	
		1)	Limited styling of shadowed elements by ID. Because IDs must be unique,
				and the shadows have their own ID, styles applied by ID won't transfer
				to the shadows. Instead, style elements by class or use inline styles.
		2)	Sometimes the shadows don't re-align properly on window resize. 
				
	AUTHOR: Larry Stevens (McLars@eyebulb.com) This work is in the public domain.
*/

var dropShadowZindex = 1;  //global stack counter

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

		// Get background, margin, and position styles
		var bgc, bgi, mt, mr, mb, ml, pos;
		var cs = this.currentStyle;
		if (cs) {  //IE
			bgc = cs.backgroundColor;
			bgi = cs.backgroundImage;
			pos = cs.position;
			mrt = cs.marginTop;
			mrr = cs.marginRight;
			mrb = cs.marginBottom;
			mrl = cs.marginLeft;
		}
		else {  //Mozilla & Safari
			cs = document.defaultView.getComputedStyle(this, null);
			bgc = cs.getPropertyValue("background-color");
			bgi = cs.getPropertyValue("background-image");
			pos = cs.getPropertyValue("position");
			mrt = cs.getPropertyValue("margin-top");
			mrr = cs.getPropertyValue("margin-right");
			mrb = cs.getPropertyValue("margin-bottom");
			mrl = cs.getPropertyValue("margin-left");
			if (bgc == "rgba(0, 0, 0, 0)") bgc = "transparent";  //Safari
		}
		// Modify original element
		jQuery.data(this, "shadowId", shadowId); //store id in expando
		jQuery.data(this, "shadowOptions", options); //store options in expando
		jthis
			.attr("shadowId", shadowId)
			.css("zIndex", zOriginal);
		if (pos != "absolute") {
			jthis.css({
				position: "relative",
				zoom: 1 //for IE layout
			});
		}

		// Create first shadow layer
		if (bgc != "transparent" || bgi != "none" 
				|| this.nodeName == "SELECT" 
				|| this.nodeName == "INPUT"
				|| this.nodeName == "TEXTAREA") {		
			shadows[0] = jQuery("<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: opt.opacity / (blur * 8),
				position: "absolute",
				top: blur,
				width: jthis.outerWidth(),
				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 = jQuery("<div></div>")
			.attr("id", shadowId) 
			.addClass("dropShadow")
			.css({
				left: jthis.position().left + opt.left - blur,
				marginTop: mrt,
				marginRight: mrr,
				marginBottom: mrb,
				marginLeft: mrl,
				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
		jQuery(window).resize(function()
		{
			try {
				divShadow.css({
					left: jthis.position().left + opt.left - blur,
					top: jthis.position().top + opt.top - blur
				});
			}
			catch(e){}
		});
		
		// Increment stack counter
		dropShadowZindex += 2;

	});  //end each
	
	return jShadows;
}


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


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


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


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