
/*
Multiple background CSS Parser for IE6/7/8, Firefox <=3.5
Author: Ben Green (bgreen@chicowebdesign.com)
Date: 101117
License: Free

Usage: background: url(left.gif) no-repeat 0 0, url(right.gif) no-repeat 100% 0, url(middle.gif) repeat-x 0 0;
Also includes support for :active, :hover, and :focus psuedo classes


*/
jQuery(function($){
	//conditional for which browsers you want to support (ie6/7/8,firefox<=3.5)
	if(($.browser.msie && parseFloat($.browser.version)>=6 && parseFloat($.browser.version)< 9)||
	   ($.browser.mozilla && parseInt($.browser.version.substr(0,1))<=1 && parseInt($.browser.version.substr(2,1))<=9 && parseInt($.browser.version.substr(4,1))<=1)){
	   //store the loaded css rules
		var myCss={};
		var putLayerOutside=new Array("input");
	   
		/*
		Supplementary JQuery Extension:

		*
		* @author Terry Wooton+Ben Green
		* @desc Adds a background layer to an element
		* @version 2
		* @example
		* $("#elaement").addLayer("url('/test.gif') bottom left no-repeat");
		* @license free
		* @param background css
		* @param outer boolean
		*
		@modified Ben Green to support padding correctly and took off weird extra divs...
					and the ability to put extra wrappers on the outside of elements
		*/
		$.fn.addLayer = function(bg,outer,params) {
			$(this).each(function() {

				var s = $(this).extend({},params || {});      
				if(outer){
					//put layers on outside
					var $this=$(this);
					$this.wrap('<div class="add_background_outer" />');
					$last=$this.parent();
					
					$last.css({"margin":$this.css("margin"),
								"display":$this.css("display"),
								"position":$this.css("position"),
								"top":$this.css("top"),
								"left":$this.css("left"),
								"right":$this.css("right"),
								"bottom":$this.css("bottom"),
								"float":$this.css("float"),
								"clear":$this.css("clear"),
								"z-index":$this.css("z-index"),
								"height":parseFloat($this.css("height").replace("px",""))+parseFloat($this.css("padding-top").replace("px",""))+parseFloat($this.css("padding-bottom").replace("px","")),
								"width":parseFloat($this.css("width").replace("px",""))+parseFloat($this.css("padding-left").replace("px",""))+parseFloat($this.css("padding-right").replace("px","")),
								"-moz-border-radius-bottomright":$this.css("-moz-border-radius-bottomright"),
								"-moz-border-radius-bottomleft":$this.css("-moz-border-radius-bottomleft"),
								"-moz-border-radius-topleft":$this.css("-moz-border-radius-topleft"),
								"-moz-border-radius-topright":$this.css("-moz-border-radius-topright"),
								"background":bg});
					$this.css({"margin":'',
								"display":'',
								"position":'',
								"top":'',
								"left":'',
								"right":'',
								"bottom":'',
								"float":'',
								"z-index":'',
								"clear":'',
								"height":'',
								"width":'',
								"-moz-border-radius-bottomright":'',
								"-moz-border-radius-bottomleft":'',
								"-moz-border-radius-topleft":'',
								"-moz-border-radius-topright":''});
				}else{
					//put layers on inside

					$last = ($(this).find('.add_background:last').length > 0 ? $(this).find('.add_background:last') : $(this));
					var innerHtml=$last.html();
					if($.browser.msie){
						$last.html('<div class="add_background">'+innerHtml+'</div>');
					}else{
						//firefox will add wrapper divs when setting the innerhtml for some reason
						$last.empty().append('<div class="add_background">'+innerHtml+'</div>');
					};
					$last = $(this).find('.add_background:last');
					if(($.browser.msie && parseFloat($.browser.version)<8)&&($(this).css('position')=="static")){
						//width/height screws up negative margin in ie6/7 on elements without position:relative?
						$last.css({'background':bg});
					}else{
						$last.css({'background':bg,'width':'100%','height':'100%'});
					};
					//take care of any padding that would mess up the layout by using negative margins
					var $parent=$last.parent();
					var p=new Array($parent.css("padding-top"),$parent.css("padding-right"),$parent.css("padding-bottom"),$parent.css("padding-left"),$parent.css("height"));
					if($.browser.msie && parseFloat($.browser.version)<6){
						$parent.css("padding","0");
						$last.css({'padding-top':p[0],'padding-right':p[1],'padding-bottom':p[2],'padding-left':p[3]});
					}else{
						
						$last.css({'padding-top':p[0],'padding-right':p[1],'padding-bottom':p[2],'padding-left':p[3], 'margin-top':'-'+p[0],'margin-right':'-'+p[1],'margin-bottom':'-'+p[2],'margin-left':'-'+p[3]});
						if($.browser.msie && parseInt($.browser.version)<=7){
							//ie 7 won't push everything all the way out all the time so give it a height
							$last.css({'height':p[4]});
						};
					};

					//commented out just like extra wrapper div in the constructor above
					//$last = $(this).find('.add_background div:last');

					if(s.insideCss){
						$last.css(s.insideCss);
					};
					if(s.insideClass)
						$last.addClass(s.insideClass);  	

				};
			});
		};
		//End Supplementary Extension
		  
		//remove a layer
		//@param element: selector for the actual layer element, not the element with the layers
		function removeLayer(element){
			var $layer=$(element);
			var $parent=$layer.parent();
	  		var p=new Array($layer.css("padding-top"),$layer.css("padding-right"),$layer.css("padding-bottom"),$layer.css("padding-left"));
	  		var innerHtml=$layer.html();
	  		$parent.html(innerHtml);
	  		if($.browser.msie && parseFloat($.browser.version)<6){
	  			$parent.css({'padding-top':p[0],'padding-right':p[1],'padding-bottom':p[2],'padding-left':p[3]});
	  		};
		};
		function removeOuterLayer(element){
			var $layer=$(element);
			var $child=$($layer.children()[0]);
			
			$child.css({"margin":$layer.css("margin"),
						"position":$layer.css("position"),
						"top":$layer.css("top"),
						"left":$layer.css("left"),
						"right":$layer.css("right"),
						"bottom":$layer.css("bottom"),
						"float":$layer.css("float"),
						"clear":$layer.css("clear"),
						"z-index":$layer.css("z-index")});
	  		$child.unwrap();
	  		
			
		};

		//find lower/uppercase combinations and replace with lowercase for compatability
		function replaceWithLower(inStr,replaceWith){
			var linStr=inStr.toLowerCase();
			var pos=linStr.indexOf(replaceWith);
			while(pos>-1){
				inStr=inStr.substr(0,pos)+replaceWith+inStr.substr(pos+replaceWith.length);
				pos=linStr.indexOf(replaceWith,pos+1);
			};
			return inStr;
		};
		

		//read in a selector and output and integer precedence score
		function selectorScore(selector,important){
			//decendents and siblings aren't any different to us
			selector=selector.replace(">"," ").replace("+"," ");
			var sSpl=selector.split(" ");
			var score=0;
			for(var i=0;i<sSpl.length;i++){
				var cPart=$.trim(sSpl[i]);
				var pos=0;
				while(pos>-1){
					function analyzePosition(p){
						var lowest=10000; /*theorical max selector length*/
						var which=-1;
						for(var i=0;i<p.length;i++){
							if((p[i]<lowest)&&(p[i]>-1)){
								lowest=p[i];
								which=i;
							};
						};
						if(lowest==10000) lowest=-1;
						return {'lowest':lowest,'which':which};
					};
					var p=[cPart.indexOf("#",pos),cPart.indexOf(".",pos),cPart.indexOf(":",pos)];
					var a=analyzePosition(p);
					if(pos==0 && a.lowest>0){
						//this item began with an element
						score+=1;
						pos++;
					}else if(pos==0 && a.lowest==-1){
						//this item is just an element!
						score+=1;
						break;
					}else if(a.lowest>-1){
						if(a.which==0){score+=100; /* id found */ };
						if(a.which==1){score+=10; /* class found */ };
						if(a.which==2){score+=10; /* psuedo-class found */ };
						pos=a.lowest+1;
					}else if(pos==0){ 
						score+=1;  /* element found */
					}else{
						break;
					};
				};
			};
			return score+(important ? 1000 : 0);
		};
		
		//in order to not get messed up on things like:
		//rgba(100,100,100,0.5)
		//change to:
		//rgba(100##comma##100##comma##100##comma##0.5)
		//will only do the change on commas inside of parentheses
		function replaceInnerComma(str){
			var pos=str.indexOf("(");
			while(pos>-1){
				var endPos=str.indexOf(")",pos+1);
				var newMiddle=str.substr(pos,endPos-pos).replace(/,/g,"##comma##");
				str=str.substr(0,pos)+newMiddle+str.substr(endPos);
				pos=str.indexOf("(",endPos+1);
			};
			return str;
		};
				
		//readCSS - main function to read css
		//@param: conts - chunk of css to read in
		//@param: prop - which function to look for
		//@param: path - path which to make the urls change to (false to disable)
		function readCss(conts,prop,path){
			var output={};
			//get rid of comments
			conts=conts.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g,'');
			var pos=conts.indexOf(prop);
			//loop through all backgrounds in the stylesheet
			while(pos>-1){
				var bgVal=replaceWithLower($.trim(conts.substr(conts.indexOf(":",pos+1)+1,conts.indexOf(";",pos+1)-conts.indexOf(":",pos+1)-1)),"url(");
			
				//only do anything if there are actually multiple bgs in the property
				
				bgVal=replaceInnerComma(bgVal);
				if(bgVal.indexOf(",")>-1){
					
					
					//make paths relative to the stylesheet work out
					if(path){
						var urlPos=bgVal.indexOf("url(");
						while(urlPos>-1){
							//don't do any working on absolute urls
							if(bgVal.substr(urlPos+4,7).toLowerCase()!="http://"){
								var extraSlash=(bgVal.substr(urlPos+4,1) == '/');
								var domain=document.URL.substr(0,document.URL.indexOf('/',9));
								bgVal=bgVal.substr(0,urlPos+4)+(extraSlash ? domain :path)+bgVal.substr(urlPos+4);
							};
							//seek to next
							urlPos=bgVal.indexOf("url(",urlPos+1);
						};
					};
				
					//determine if there was an important in this bg value
					var important=bgVal.length;
					bgVal=bgVal.replace("!important","");
					important=(important==bgVal.length ? false : true);
					var prevBrace=conts.lastIndexOf("}",pos)+1;
					//Allow for charset 
					if(conts.lastIndexOf(";",pos)+1>prevBrace) prevBrace=conts.lastIndexOf(";",conts.lastIndexOf("{",pos))+1;
					if(prevBrace==-1) prevBrace=0;
					var selector = $.trim(conts.substr(prevBrace,conts.lastIndexOf("{",pos)-prevBrace));
					//account for multiple selectors
					var selSplit=selector.split(",");
					for(var i=0;i<selSplit.length;i++){
						var curSel=$.trim(selSplit[i]);
						curSel=replaceWithLower(curSel,":active");
						curSel=replaceWithLower(curSel,":hover");
						curSel=replaceWithLower(curSel,":focus");
						
					
						output[curSel]={property:prop,value:bgVal,selScore:selectorScore(curSel,important)};
					};
				};
			
			
				pos=conts.indexOf(prop,conts.indexOf(";",pos+1));
			};
			//put the contents into the storage
			$.extend(myCss,output);
		};
	
		//apply a specific background property to a selector
		function applyBg(selector,attr){
			$(selector).each(function(){
				var $element=$(this);
				$element.css("background","none");
			
				//check this current element's selector score against this score
				var curSelector=$element.attr("jQueryMultipleBgCurSelector");
				var newSelector=$element.attr(attr);

				$element.attr("jQueryMultipleBgCurSelector",newSelector);
				vals=myCss[newSelector].value.split(",");
				//fix any commas that may be in each val
				for(var i=vals.length-1;i>=0;i--){
					vals[i]=$.trim(vals[i].replace(/##comma##/g,","));
				};

				if(inArray(putLayerOutside,this.tagName.toLowerCase())){
					//these layers are going on the outside so it may be an input on ie!
					var curLayer=$element.parent();
					while(curLayer.parent().hasClass("add_background_outer")){
						curLayer=curLayer.parent();
					};
					for(var i=vals.length-1;i>=0;i--){
						if(!curLayer.hasClass("add_background_outer")){
							//not enough backgrounds! add more!
							$element.addLayer(vals[i],true);
						}else{
							//we still have backgrounds, let's use 'em
							curLayer.css('background',vals[i]);
							//jump into the next layer
							curLayer=$(curLayer.children()[0]);
						};
					};
					//are there any extra backgrounds?
					//if so, axe them!
					while(curLayer.hasClass("add_background_outer")){
						var saveLayer=curLayer;
						//jump into the next layer
						curLayer=$(curLayer.children()[0]);
						removeOuterLayer(saveLayer);
					};
				}else{
				
					//replacing current backgrounds
					var count=$element.find(".add_background").length;
					var curLayer=$($element.children(".add_background")[0]);
					for(var i=vals.length-1;i>=0;i--){
						if(curLayer.length<1){
							//not enough backgrounds! add more!
							$element.addLayer(vals[i],false);
						}else{
							//we still have backgrounds, let's use 'em
							curLayer.css('background',vals[i]);
							//jump into the next layer
							curLayer=$(curLayer.children(".add_background")[0]);
						};
					};
					//are there any extra backgrounds?
					//if so, axe them!
					while(curLayer.length){
						var saveLayer=curLayer;
						//jump into the next layer
						curLayer=$(curLayer.children(".add_background")[0]);
						removeLayer(saveLayer);
					};
				};
			});
		};
	
	
		//mouseover event for elements with hover multiple bgs
		function elementMouseover(e){
			if($(this).attr("jQueryMultipleBgCurSelector")!=$(this).attr("jQueryMultipleBgActiveSelector")){
				applyBg(this,"jQueryMultipleBgHoverSelector");
			};
		};
		//mouseout event for elements with hover multiple bgs
		function elementMouseout(e){
			applyBg(this,"jQueryMultipleBgStaticSelector");
		};
	
		//mousedown event for elements with active multiple bgs
		function elementMousedown(e){
			applyBg(this,"jQueryMultipleBgActiveSelector");
		};
		//mouseup event for elements with active multiple bgs
		function elementMouseup(e){
			if($(this).attr("jQueryMultipleBgHoverSelector")){
				applyBg(this,"jQueryMultipleBgHoverSelector");
			}else{
				applyBg(this,"jQueryMultipleBgStaticSelector");
			};
		};
	
		//focus event for elements with focus multiple bgs
		function elementFocus(e){
			applyBg(this,"jQueryMultipleBgFocusSelector");
		};
		//blur event for elements with focus multiple bgs
		function elementBlur(e){
			applyBg(this,"jQueryMultipleBgStaticSelector");
		};
		
		// Returns true if the passed value is found in the
		// array. Returns false if it is not.
		function inArray(myArray,value,caseSensitive) {
			var i;
			for (i=0; i < myArray.length; i++) {
				// use === to check for Matches. ie., identical (===),
				if(caseSensitive){ //performs match even the string is case sensitive
					if (myArray[i].toLowerCase() == value.toLowerCase()) {
						return true;
					};
				}else{
					if (myArray[i] == value) {
						return true;
					};
				};
			};
			return false;
		};
	
		//apply an array of css selectors with multiple backgrounds
		function applyCss(root){
			
			if(root==undefined) root=document;
			for(var sel in myCss){
				
				var lsel=sel.toLowerCase(); 
				if((lsel.indexOf(":hover")>-1)||(lsel.indexOf(":active")>-1)||(lsel.indexOf(":focus")>-1)){
					var leftSide, rightSide;
					if(lsel.indexOf(":hover")>-1){
						leftSide=sel.substr(0,lsel.indexOf(":hover"));
						rightSide=sel.substr(lsel.indexOf(":hover")+6);
						
						//set the reference selector on each element
						$(leftSide+rightSide,root).each(function(){
							var curSelector=$(this).attr("jQueryMultipleBgHoverSelector");
							//make sure the current selector still works
							if((curSelector)&&(!inArray($(replaceWithLower(curSelector,":hover").replace(/:hover/g,'')),this))) curSelector=undefined;
							if((!curSelector)||(myCss[curSelector].selScore<myCss[sel].selScore)){
								$(this).attr("jQueryMultipleBgHoverSelector",sel);
								if(!curSelector) $(this).hover(elementMouseover,elementMouseout);
							};
						});
					
					}else if(lsel.indexOf(":active")>-1){
						leftSide=sel.substr(0,lsel.indexOf(":active"));
						rightSide=sel.substr(lsel.indexOf(":active")+7);
					
						//set the reference selector on each element
						$(leftSide+rightSide,root).each(function(){
							var curSelector=$(this).attr("jQueryMultipleBgActiveSelector");
							//make sure the current selector still works
							if((curSelector)&&(!inArray($(replaceWithLower(curSelector,":active").replace(/:active/g,'')),this))) curSelector=undefined;
							if((!curSelector)||(myCss[curSelector].selScore<myCss[sel].selScore)){
								$(this).attr("jQueryMultipleBgActiveSelector",sel);
								if(!curSelector) $(this).mousedown(elementMousedown).mouseup(elementMouseup);
							};
						});
					}else if(lsel.indexOf(":focus")>-1){
						leftSide=sel.substr(0,lsel.indexOf(":focus"));
						rightSide=sel.substr(lsel.indexOf(":focus")+6);
					
						//set the reference selector on each element
						$(leftSide+rightSide,root).each(function(){
							var curSelector=$(this).attr("jQueryMultipleBgFocusSelector");
							//make sure the current selector still works
							if((curSelector)&&(!inArray($(replaceWithLower(curSelector,":focus").replace(/:focus/g,'')),this))) curSelector=undefined;
							if((!curSelector)||(myCss[curSelector].selScore<myCss[sel].selScore)){
								$(this).attr("jQueryMultipleBgFocusSelector",sel);
								if(!curSelector) $(this).focus(elementFocus).blur(elementBlur);
							};
						});
					}
				}else{
					//set the reference selector on each element
					$(sel,root).each(function(){
						var curSelector=$(this).attr("jQueryMultipleBgStaticSelector");
						//make sure the current selector still works
						if(!inArray($(curSelector),this)) curSelector=undefined;
						if((!curSelector)||(myCss[curSelector].selScore<myCss[sel].selScore)){
							$(this).attr("jQueryMultipleBgStaticSelector",sel);
							applyBg(this,"jQueryMultipleBgStaticSelector");
						};
					});
					
				};
			};
		};
	
		//put our functions in the jQuery object
		jQuery.fn.extend({
			multipleBgReadCss: readCss,
			multipleBgApplyCss: applyCss,
			multipleBgApplyBg: applyBg,
			multipleBgRules: myCss
		});

	
		//actually call the functions now
		//read style tags
		$("style").each(function(){
			var conts=$(this).html();
			readCss(conts,"background",false);
		});
		//read linked stylesheets
		$("link[rel=stylesheet]").each(function(){
			var href=$(this).attr("href");
			//dont load any stylesheets from other domains
			if(href.substr(0,7).toLowerCase()!="http://"){
				var path=href.slice(0, href.lastIndexOf("/") + 1);
				$.ajax({
					async: false,
					url: $(this).attr("href"),
					success: function(conts) {
						readCss(conts,"background",path);
						}
				});
			}
		});
	
		applyCss();
	
			
	}else{
		//give every other browser some dummy functions so there aren't errors
		jQuery.fn.extend({
			multipleBgReadCss: function(conts,prop,path){return false;},
			multipleBgApplyCss: function(root){return false;},
			multipleBgApplyBg: function(selector,attr){return false},
			multipleBgRules: {}
		});
	};
		

});
	



