(function($) {
	$.fn.roundbox = function(options) {
		
		//debug(this);
		
		//build main options before element iteration
		var opts = $.extend({}, $.fn.roundbox.defaults, options);
		
		//iterate and reformat each matched element
		return this.each(function() {
			
			$this = $(this);
			
			//build element specific options
			var o = $this.metadata() ? $.extend({}, opts, $this.metadata()) : opts;
			//o now holds all our options
			
			//inject the needed semantic markup to get rounded corners
			var bgTop = 'url('+ o.themepath + o.theme + '/top.png)';
			var bgBottom = 'url('+ o.themepath + o.theme + '/bottom.png)';
			
			$this.addClass('rbouter').css({
				backgroundImage: bgBottom
			});
			
			if ($this.children('h1,h2,h3,h4').length > 0) {

				$this.children('h1,h2,h3,h4').addClass('rbtitle').css({
					backgroundImage: bgTop
				}).wrapInner('<span style="background-image:'+bgTop+';padding:'+o.headerPadding+'"></span>');
				
				$this.children('.rbtitle').css('color',o.headerColor);
				
			} else { // no box title, just contruct the box top
				$this.prepend('<div class="rbtitle" style="background-image:'+bgTop+';"><span style="background-image:'+bgTop+';"></span></div>');
			}
			
			$this.children('.boxcontent').addClass('rbcontent').css({
				backgroundImage: bgBottom
			}).wrapInner('<div class="rbinner"></div>');
			
			$this.find('.rbinner').css('padding',o.contentPadding);
			
			if (o.theme == "light-blue") //todo:make this smarter
				$this.find('.rbinner').css('backgroundColor', o.contentBgColor);
			
			//apply accordian
			if (o.accordian) {
				
				var leftMargin = ($.browser.msie && $.browser.version < 7) ? parseInt($this.find('.rbtitle > span').css('paddingLeft'))/2 : parseInt($this.find('.rbtitle > span').css('paddingLeft'));
				var topMargin = ($this.find('.rbtitle').height()/2) - 8;
				
				$this.children('.rbtitle').css({
					cursor:'pointer',
					color:'#0F6DB6'
				});
				
				$this.children('.rbtitle').prepend('<div class="accordian '+o.accordianInitState+'" style="margin-left:'+leftMargin+'px;margin-top:'+topMargin+'px"></div>');
				
				
				if (o.accordianInitState == "closed") {
					$this.find('.rbinner').css({
						paddingTop:'0',
						paddingBottom:'0',
						height:'0',
						overflow: 'hidden'
					});
				}
				
				//bind click action
				$this.children('.rbtitle, .accordian').click(function(){
					$.fn.roundbox.animateAccordian($(this),o.contentPadding);
				});
				
			}
			
			//apply gradient
			if (o.gradient) {
				applyGradient($this.find('.rbinner'), o.gradientStart, o.gradientEnd);
			}
			
			//apply drop shadows
			//NOTE: ie6 is having problems with drop shadow positioning, also some issues with drop shadows and accordians, skip these cases for now
			if(!($.browser.msie && $.browser.version < 7) && !o.accordian) { 
			
				if (o.shadow) {
					shadowWidth = $this.width() + 4;
					shadowHeight = $this.height() - 10;
					shadowOffset = ($this.find('.rbtitle').height() - 6)*-1;
					
					//the gradient throws off the shadow in IE6, todo: fix this
					shadowBtmBottomPos = -5;
					if ($.browser.msie && $.browser.version < 7)
						shadowBtmBottomPos = 69;
						
					//alert((parseInt($this.find('.rbinner').css('paddingLeft'))+1) * -1);
						
					shadowBtmLeftPos = 0;
					if ($.browser.msie && $.browser.version < 7) //IE6 adjustment
						shadowBtmLeftPos = (parseInt($this.find('.rbinner').css('paddingLeft'))+1) * -1;					
	
					$this.children('.rbcontent').append('<div class="rbshadow-btm" style="left:'+shadowBtmLeftPos+'px;bottom:'+shadowBtmBottomPos+'px;width:'+shadowWidth+'px"><div></div></div><div class="rbshadow-side" style="height:'+shadowHeight+'px;top:'+shadowOffset+'px"></div>');	
				}
				
			}
			
		});
		
	};
	
	//
	// private functions
	//
	
	//appplies a gradient to a box object
	function applyGradient($gradientObject, startColor, endColor) {

		if (!$gradientObject || !startColor || !endColor)
				return;
				
		$gradientObject.css('backgroundColor','#'+endColor);

		if($.browser.msie) { //use filters to draw gradient for IE
			$gradientObject.css('width', $gradientObject.width());
			$gradientObject.css('filter', "progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=\"#" + startColor + "\",EndColorStr=\"#" + endColor + "\")");
		} else {
			if (canvasCompatible()) { //use canvas to draw gradient for browsers supporting canvas
				y = 0;
				h = Math.round($gradientObject.height());
				if(!h) h = 1;
				w = $gradientObject.parent().width() + 4;
				$gradientObject.wrapInner("<div style='position:relative;z-index:10;'></div>");
				$gradientObject.append("<canvas style='position:absolute;z-index:0;top:" + y + "px;left:1px;' height="+h+" width="+w+" />");
				var context = $('canvas:last').get(0).getContext('2d');
				context.fillStyle = context.createLinearGradient(0, 0, 0, h);
				context.fillStyle.addColorStop(0, "#"+startColor);
				context.fillStyle.addColorStop(1, "#"+endColor);
				context.fillRect(0, 0, w, h);
			} else { //brute force technique - insert an array of colored divs
				colorArray = createColorPath(startColor,endColor);
				y = 0;
				h = Math.round($gradientObject.height()/colorArray.length);
				if(!h) h = 1;
				w = $gradientObject.parent().width() + 4;
				$gradientObject.wrapInner("<div style='position:relative;z-index:10;'></div>");
				var gradientHtml = "";
				for(p = 0;p < colorArray.length;p++) {
					gradientHtml += "<div style='position:absolute;z-index:0;top:" + y + "px;left:1px;height:" + h + "px;width:" + w + "px;background-color:rgb(" + colorArray[p][0] + "," + colorArray[p][1] + "," + colorArray[p][2] + ")'></div>";
					y += h;
					if(y >=$gradientObject.height() - h) break;
				}
				$gradientObject.append(gradientHtml);
			}

		}

	}
		
	function createColorPath(color1,color2) {
		colorPath = new Array();
		colorPercent = 1.0;
		do {
			colorPath[colorPath.length]=setColorHue(longHexToDec(color1),colorPercent,longHexToDec(color2));
			colorPercent-=.01;
		} while(colorPercent > 0);
		return colorPath;
	}
			
	function setColorHue(originColor,opacityPercent,maskRGB) {
		returnColor=new Array();
		for(w=0;w < originColor.length;w++) returnColor[w] = Math.round(originColor[w]*opacityPercent) + Math.round(maskRGB[w]*(1.0-opacityPercent));
		return returnColor;
	}
	
	function longHexToDec(longHex) {
		return new Array(toDec(longHex.substring(0,2)),toDec(longHex.substring(2,4)),toDec(longHex.substring(4,6)));	
	}
	
	function toDec(hex) {	
		return parseInt(hex,16);
	}
	
	function canvasCompatible() {
		var canvasCompatible = false;
		try {
	        canvasCompatible = !!(document.createElement('canvas').getContext('2d'));
	    } catch(e) {
	        canvasCompatible = !!(document.createElement('canvas').getContext);
	    } 
	    return canvasCompatible;
	}

	function debug(msg) {
		if (window.console && window.console.log)
		window.console.log(msg);
	};
	
	//
	// public functions  -  can be called from outside the plugin
	//
	
	$.fn.roundbox.animateAccordian = function($target, contentPadding) {
		
		if ($target.parent('.rbouter').find('.accordian').hasClass('open')) { //content is open, collapse the box
			$target.parent('.rbouter').find('.accordian').removeClass('open').addClass('closed');
			$target.parent('.rbouter').find('.rbinner').animate({
				height:'0'
	   		}, function(){
	   			$target.parent('.rbouter').find('.rbinner').css({
	   				padding:'0',
					paddingTop:'0',
					paddingBottom:'0'
				});
	   		});
		} else { //content is closed, expand the box	
			$target.parent('.rbouter').find('.accordian').removeClass('closed').addClass('open');
			$target.parent('.rbouter').find('.rbinner').css('height','auto'); //height needs to be set back to auto to retrieve the target height
			var targetHeight = $target.parent('.rbouter').find('.rbinner').height();
			$target.parent('.rbouter').find('.rbinner').css('height','0'); //set it back to 0
			$target.parent('.rbouter').find('.rbinner').css('padding',contentPadding);
			$target.parent('.rbouter').find('.rbinner').animate({
				height: targetHeight + "px"
	   		});
	   		
	   		//todo: support drop shadow animation in accordians

		}
	}
	
	//
	// plugin defaults
	//
	$.fn.roundbox.defaults = {
		accordian: false,
		accordianInitState: 'closed',
		headerPadding: '5px 10px',
		contentPadding: '5px 10px',
		shadow: false,
		gradient: false,
		gradientStart: 'ffffff',
		gradientEnd: 'eef7fa',
		theme: 'default',
		headerColor: '#333',
		contentBgColor: '#fff',
		themepath:'/images/roundbox/'
	};
	
})(jQuery);