/*

Flash Heading Replacement v0.1

Provides a method of replacing browser-text headings with smooth Flash text.
The script looks for tags with the CSS-specified font and replaces their
text contents with a Flash movie containg the same text.

Font paths are defined in CSS
Example: h1{ font-family:"Swf/FranklinGothicBook.swf",Helvetica,sans-serif"; } 

*/

TL.FlashHeaders = function(){
	
	// TODO: Encapsulate these variables
	var headings = {};
	
	var EMWidthListener;
	var DPI;
	var EMWidth;
	
	// For brevity
	var UA = TL.UserAgent;
	var Utils = TL.Utilities;
	
	// Minimum Requirements
	if(!UA.HasFlashPlayerVersion(6,0,0) || UA.isMacIE || UA.isOpera || !UA.IsModern){
		return {
			init:function(){}
		};
	}

	document.write('<style type="text/css">h1,h2,h3,h4,h5,h6,legend{visibility:hidden;}</style>');
			
	return {
		BUILD:'20060627',
		
		// Not really constants, although they don't change after this point
		VERSION_8_MODE: UA.HasFlashPlayerVersion(8,0,0),
		IS_IE: UA.Browser == "msie",
		IS_WIN_IE: function(){return (UA.Browser == "msie" && UA.OS == "Windows")}(),
		IS_MAC: UA.IsMac,
		IS_WIN_IE5: function(){return (UA.Browser == "msie" && UA.OS == "Windows" && UA.Version < 6)}(),
		IS_SAFARI: function(){return(UA.Browser == "safari")}(),
		BROWSER_VERSION: UA.Version,
		USE_OPAQUE: function(){return ((UA.Browser == "firefox" || UA.Browser == "netscape")&&(!UA.HasFlashPlayerVersion(8,0,0)))}(),
		
		createEMWidthListener: function(){
			
			// Only IE supports element.onresize
			// and IE5 needs special access for iframes
			// Therefore, for IE we will use div.onresize
			if(UA.Browser == "msie"){
				
					EMWidthListener = document.createElement("div");
					document.body.appendChild(EMWidthListener);
					EMWidthListener.counter = 0;
					// Prevent IE 'loading' animation
					setTimeout(function(){
										EMWidthListener.style.visibility = "hidden";
										EMWidthListener.style.width = "1em";
										EMWidthListener.style.height = "1em";
										},10);
					TL.Events.addEvent(EMWidthListener,"resize",function(){	
						EMWidthListener.counter++;
						if(EMWidthListener.counter > 1){
							trace("Resize Fonts");
							//TL.FlashHeaders.resizeFonts();
						}
					});
				
				
			// All other browsers do not support element.onresize
			// Therefore, we use an IFRAME
			}else{
					
					EMWidthListener = document.createElement("iframe");
					EMWidthListener.setAttribute('frameborder',0);
					EMWidthListener.setAttribute('framemargin',0);
					EMWidthListener.setAttribute('framespace',0);
					EMWidthListener.setAttribute('scrolling','no');
					

					if(UA.Browser == "safari"){
						/* 
						IFRAME must be wrapped in a div so it can be absolute-positioned 
						and still broadcast resize events in Safari.  It must also appear
						in the visible portion of the screen.
						*/
						
						// TODO: make sure that this stays in the visible area so it can broadcast events
						// try position:fixed ?
						EMWidthListenerWrapper = document.createElement("div");
						document.body.insertBefore(EMWidthListenerWrapper,document.body.childNodes[0]);
						
						EMWidthListenerWrapper.appendChild(EMWidthListener);
						
						var doc = EMWidthListener.contentWindow.document;
						
						doc.open();
						doc.write('Font Resize Checker');
						doc.close();
						
						EMWidthListener.style.width = "1em";
						EMWidthListener.style.height = "1em";
						EMWidthListener.contentWindow.counter = 1;
					
						// Iframe must be onscreen to broadcast events
						EMWidthListenerWrapper.style.position = "absolute";
						EMWidthListenerWrapper.style.visibility = "hidden";
						EMWidthListener.style.zIndex = "100";
					}else{
						document.body.appendChild(EMWidthListener);
						
						var doc = EMWidthListener.contentWindow.document;
						
						doc.open();
						doc.write('Font Resize Checker');
						doc.close();
						
						EMWidthListener.style.width = "1em";
						EMWidthListener.style.height = "1em";
						EMWidthListener.contentWindow.counter = 0;
						
						EMWidthListener.style.position = "absolute";
						EMWidthListener.style.zIndex = "100";
						EMWidthListener.style.left = "-1000px";
						EMWidthListener.style.top = "-1000px";
					}
					
					TL.Events.addEvent(EMWidthListener.contentWindow,"resize",function(){
						// When the iframe loads, it calls a resize event
						// The counter allows us to ignore this event - we only care about subsequent events
						
						EMWidthListener.contentWindow.counter++; 
						
						if(EMWidthListener.contentWindow.counter > 1){
							trace("Resize Fonts");
							//TL.FlashHeaders.resizeFonts();
						}
					});
			}
		},
		
		// TODO: optimize
		getEMWidth: function(){
			if(!EMWidth){
				EMWidth = document.createElement("div");
				document.body.appendChild(EMWidth);
				EMWidth.style.width = "1em";
				EMWidth.style.height = "1em";
			}
			EMWidth.style.position = "absolute";
			EMWidth.style.visibility = "hidden";
			
			var r = EMWidth.offsetWidth;
			
			return r;
		
		},
		
		// TODO: optimize
		getDPI: function(){
			if(!DPI){
				DPI = document.createElement("div");
				document.body.appendChild(DPI);
			}
			DPI.style.width = "1in";
			DPI.style.height = "1in";
			DPI.style.zIndex = "100";
			DPI.style.position = "absolute";
			DPI.style.left = "-1000px";
			DPI.style.top = "-1000px";
			DPI.style.visibility = "hidden";
			
			var r = DPI.offsetWidth;
			
			return r;
			
		},
		
		
		getFontPts: function($element){
		
			var s = Utils.getElementStyle($element,"font-size");
			var u = s.replace(/[^a-zA-Z%]/g,'');
			var n = parseFloat(s.replace(/[a-zA-Z%]/g,''));
			
			//TOD0: make this a case switch instead of ifs
			if(u == "px"){
				// Safari does not update the ComputedStyle for font-size 
				// when the text is resized.  Some adjustment must be made.
				if(UA.Browser == "safari"){
					var pts = (this.getEMWidth()/(this.getDPI()/72));
					var px = parseFloat(Utils.getElementStyle(document.body,"font-size"));
					var r = pts/px;
					return (n*r);
				}else{
					return (72/this.getDPI())*n;
				}
			}
			
			if(u == "em"){
				return n*this.getFontPts($element.parentElement);
			}
			
			if(u == "pt"){
				return n;
			}
			
			if(u == "%"){
				return (n/100)*this.getFontPts($element.parentElement);
			}
			
			return n;
		},
		
		// TODO: rename - 'nomalizeColor'
		convertColor: function($color){
			if($color.match("transparent")||$color == 'rgba(0, 0, 0, 0)'){
				return "transparent";
			}
			if($color.match("rgb")){
				var tmp = $color.replace(/[a-zA-Z()]/g,'');
				tmp = tmp.split(",");
				
				var r = parseInt(tmp[0]).toString(16);
				var g = parseInt(tmp[1]).toString(16);
				var b = parseInt(tmp[2]).toString(16);
				if (r.length == 1) {r = '0' + r};
				if (g.length == 1) {g = '0' + g};
				if (b.length == 1) {b = '0' + b};
				return '#' + r + g + b;
			} else {
				return $color;
			}
		},
		
		// TODO: rework, reorganize preloading code 
		loader: {},

	/*	prefetchQueue: {},*/
		
		getPrefetchQueue: function(){
			var prefetchQueue = {};
			for(var i in headings){
				var h = headings[i];
				var p = headings[i].paths;
				for(var j=0; j<p.length; j++){
					prefetchQueue[p[j]] = p[j];
				}
			}
			
			return prefetchQueue;
		},
		
		getPrefetchTestStrings: function(){
			var testStrings = '';
			for(var i in headings){
				var h = headings[i];
				testStrings += '<'+h.params.swfId+'>'+h.params.swfTxt;
			}
			return testStrings;
		},
		
		prefetchFonts: function(){
			var queue = this.getPrefetchQueue();
			
			this.loader = document.createElement("div");
			document.body.appendChild(this.loader);
			this.loader.style.position = "absolute";
			this.loader.style.zIndex = "100";
			this.loader.style.width = "0px";
			this.loader.style.height = "0px";
			
			// What's the point of this?
			// They're preloaded in the SWF anyway
			var paths = '';
			/*for(var i in queue){
				paths += ','+i;
			};
			paths = paths.slice(1,paths.length);*/
			
			var testStrings = this.getPrefetchTestStrings();
			
			if(!this.IS_IE||this.IS_MAC){
				var thisFont = document.createElement("div");
				thisFont.setAttribute('style','visibility:hidden');
				this.loader.appendChild(thisFont);
				var str = '<embed src="Swf/Heading.swf?'+this.BUILD+'" id="loader"  width="1px" height="1px" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" allowScriptAccess="sameDomain" swLiveConnect="true" flashvars="swfPrefetch=true&swfId=loader&swfTxt='+paths+'&swfTestStrings='+testStrings+'"/>';
				
				thisFont.innerHTML = str;
			}else{
				var thisFont = document.createElement("div");
				this.loader.appendChild(thisFont);
				var fsScript ="";
				if(this.IS_WIN_IE){
					fsScript = '<script event=FSCommand(command,args) for=loader>\n eval(command)(args); <\/script>';
				}
				
				thisFont.innerHTML = '<object id="loader" type="application/x-shockwave-flash" width="1px" height="1px"><param name="allowScriptAccess" value="sameDomain" /><param name="movie" value="Swf/Heading.swf?'+this.BUILD+'" /><param name="flashvars" value="swfPrefetch=true&swfId=loader&swfTxt='+paths+'&swfTestStrings='+testStrings+'"/></object>'+fsScript;
			}
		},
		
	
		
		onFontReady: function(){
			setTimeout(function(){TL.FlashHeaders.loader.innerHTML = "";},1);
			setTimeout(TL.FlashHeaders.onPrefetchComplete,1);
		},
		
		parseFontPath: function($font){
			return $font.split('(')[1].split(')')[0].split(',');
		},
		
		selectElements: function(){
			var hs = Utils.getHeadingElements();
			var legends = document.body.getElementsByTagName("legend");
			
			if(legends.length > 0){
				hs = TL.Utilities.joinNodeLists(hs, legends);
			}
			
			var r = [];
			var i = hs.length - 1;
			do{
				var h = hs[i];
				
				var family = Utils.getElementStyle(h,"font-family");
				if(family.match("SWF:")){
					
					var id = "flashHeading"+parseInt(i);
					r[id] = {element:h, paths:this.parseFontPath(family)};
					
					/*for(var j=0; j<paths.length; j++){
						this.prefetchQueue[paths[j]] = paths[j];
					}*/
				}
			}
			while(i--);
		
			return r;
		},	
		
		getHeadingData: function($elements){
			
			for(var i in $elements){
				var h = $elements[i].element;
				
	
				var params = {};
				params.swfFilename = "Swf/Heading.swf";
		
				params.swfId = i;
				params.swfTxt = escape(this.parseNode(h));
				
				params.swfBGColor = this.convertColor(Utils.getElementStyle(h,"background-color"));
				params.headingText = h.innerHTML;
				params.swfFSScript = "";
				params.swfWidth = h.offsetWidth;
				params.swfHeight = h.offsetHeight;
				params.isInline = h.style.display == "inline";
				params.headingFloat = Utils.getElementStyle(h,"float");
				if(params.swfBGColor == "transparent"){
					params.swfWMode = "transparent";
				}else{
					params.swfWMode = "opaque";
				}
				
				if(this.USE_OPAQUE){
					// Walk up the tree until you find an element with a non-transparent bg
					var p = h;
					
					do{
						if(p.innerHTML){
							
							params.swfBGColor = this.convertColor(Utils.getElementStyle(p,"background-color"));
							
							p = p.parentNode;
						}else{
							break;
						}
					}
					while(params.swfBGColor == "transparent");
					
					// If there's still no background color set, use white
					if(params.swfBGColor == "transparent"){
						params.swfBGColor = "#FFFFFF";
					}
					params.swfWMode = "opaque";
				}
				
				if(this.IS_WIN_IE){
					params.swfFSScript = '<script event=FSCommand(command,args) for='+params.swfId+'>\n args=args.split(","); eval(command)(args[0],args[1],args[2],args[3]); <\/script>';
				}
		
				params.query = this.buildQueryString(params);
				
				$elements[i].params = params;
				
				// Only elements that are inline need a resize event
				// Floats in IE also need resize
				if(params.isInline || (params.headingFloat != 'none' && this.IS_WIN_IE)){
					this.headingsForResize[this.headingsForResize.length] = $elements[i];
				}
			}
		},

		buildQueryString: function($params){
			
			return 'swfId='+$params.swfId+'&swfTxt='+$params.swfTxt+'&swfPrefetch=false'+'&swfDPI='+this.getDPI();
		},
		
		buildInnerHTML: function($params){
		
			var r = "";
			// FF needs font-size:0px here
			var emb = '<embed style=" margin:0 -2px 0 -2px; border:0; padding:0; font-size:0px; width:100%; height:100%;" id="'+$params.swfId+'" src="'+$params.swfFilename+'?'+this.BUILD+'" flashvars="'+$params.query+'" quality="high" wmode="'+$params.swfWMode+'" scale="noscale" salign="lt" bgcolor="'+$params.swfBGColor+'"  align="top" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" swLiveConnect="true"/>';
			
			if(this.IS_WIN_IE){
				emb = '<object style=" margin:0 -2px 0 -2px; border:0; padding:0; width:100%; height:100%;" id="'+$params.swfId+'" type="application/x-shockwave-flash" align="left"><param name="allowScriptAccess" value="sameDomain" /><param name="bgcolor" value="'+$params.swfBGColor+'" /><param name="wmode" value="'+$params.swfWMode+'" /><param name="movie" value="'+$params.swfFilename+'?'+this.BUILD+'" /><param name="flashvars" value="'+$params.query+'" /><param name="quality" value="high" /><param name="scale" value="noscale" /><param name="salign" value="lt" /></object>'+$params.swfFSScript;
				
				
			}
			
			var flt = '';
			var clr = '';
			var overflow = '';
			var width = ' width:auto;';
			var verticalAlignment = '';
			
			overflow = "overflow:hidden; ";
			if(this.IS_WIN_IE){
				flt = 'float:'+$params.headingFloat+';';
				clr = 'clear:'+$params.headingFloat+';';
			}
			
			if($params.isInline && $params.headingFloat == "none"){
				flt = "float:left;";
				clr = "clear:left;";
				
			}
			
			
			
			// Alignment properties
			// (exs are more accurate than ems)
			if($params.isInline){
				if(this.IS_MAC){
					verticalAlignment = ' margin-top:-.8ex; margin-bottom:-.8ex;';
					if(this.IS_SAFARI){
					   verticalAlignment = 'top:.4ex; margin-top:-1.3ex;';
					}
				}else{
					verticalAlignment = ' margin-top:-.8ex; margin-bottom:-.7ex;';
				}
			}
			
			var r = [
					//Removed: position:relative; for IE 5
					 '<span style=" line-height:1px; ">',
						// This is in a div so that line-height is applied
						
						//Removed:  height:1px; overflow:hidden; to facilitate float wrap in Firefox
						'<div style="'+flt+' font-size:1px; line-height:1px; visibility:hidden;">',
							// 1px border required for PC IE
							'<span style="font-size:1px; line-height:1px;">',
							'</span>',
						'</div>',
						//position:relative; z-index:1; top:0;
						'<div style="background:#efefef;  '+clr+' '+flt+' height:'+$params.swfHeight+'px; '+overflow+' vertical-align:middle;'+verticalAlignment+width+' ">',	
							emb,
						'</div>',
					'</span>'
					];
			
			return r.join('');
			
		},
		
		/*getEmbed:function($params){
			var emb;
			
			if(this.IS_WIN_IE){
				emb = '<object style="position:absolute; z-index:1; margin:0 -.12em 0 -.12em; border:0; padding:0;" id="'+$params.swfId+'" type="application/x-shockwave-flash" width="100%" height="'+$params.swfHeight+'" align="left"><param name="allowScriptAccess" value="sameDomain" /><param name="bgcolor" value="'+$params.swfBGColor+'" /><param name="wmode" value="'+$params.swfWMode+'" /><param name="movie" value="'+$params.swfFilename+'?'+this.BUILD+'" /><param name="flashvars" value="'+$params.query+'" /><param name="quality" value="high" /><param name="scale" value="noscale" /><param name="salign" value="lt" /></object>'+$params.swfFSScript;
			}else{
				emb = '<embed style="position:absolute; z-index:1; margin:0 -.12em 0 -.12em; border:0; padding:0; font-size:0px;" id="'+$params.swfId+'" src="'+$params.swfFilename+'?'+this.BUILD+'" flashvars="'+$params.query+'" quality="high" wmode="'+$params.swfWMode+'" scale="noscale" salign="lt" bgcolor="'+$params.swfBGColor+'"  width="100%" height="'+$params.swfHeight+'" align="top" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" swLiveConnect="true"/>';
			}
			
			return emb;
		},*/
		
		wrapNode: function($node,$props){
			var fontSize = "";
			var fontFace = "";
			var fontColor = "";
			var textIndent = "";
			var textLeading = "";
			
			var textDecorationOpen = "";
			var textDecorationClose = "";
			
			var textAlignOpen = "";
			var textAlignClose = "";
			
			var fontWeightOpen = "";
			var fontWeightClose = "";
			
			var fontStyleOpen = "";
			var fontStyleClose = "";
			
			if($props['font-size']){
				var n = parseFloat($props['font-size'])*(this.getDPI()/72);
				fontSize = ' size="'+Math.round(n)+'"';
			}
			
			if($props['font-family']){
				var face = $props['font-family'];
				if(face.indexOf('"') != -1){
					face = face.replace(/["]/g,"'");
				}
				if(face.indexOf("'") == -1){
					face = "'"+face+"'";
				}
				fontFace = ' face="'+face+'"';
				
			}
			
			if($props['color']){
				fontColor = ' color="'+$props['color']+'"';
			}
			
			if($props['text-indent']){
				textIndent = ' indent="'+$props['text-indent']+'"';
			}
			
			if($props['line-spacing']){
				textLeading = ' leading="'+$props['line-spacing']+'"';
			}
			
			if($props['text-decoration'] == "underline"){
				textDecorationOpen = "<u>";
				textDecorationClose = "</u>";
			}
			
			var parentTextAlign = TL.Utilities.getElementStyle($node.parentNode.parentNode,'text-align');
			
			if($props['text-align'] && $props['text-align'] != parentTextAlign){
				textAlignOpen = '<p align="'+$props['text-align']+'">';
				textAlignClose = "</p>";
			}
			
			if($props['font-weight'] == 'bold' || parseInt($props['font-weight']) > 400){
				fontWeightOpen = '<b>';
				fontWeightClose = "</b>";
			}
			
			if($props['font-style'] == 'italic' || $props['font-style'] == 'oblique'){
				fontStyleOpen = '<i>';
				fontStyleClose = "</i>";
			}
			
			return textAlignOpen+'<textformat'+textIndent+textLeading+'>'+'<font'+fontFace+fontSize+fontColor+'>'+textDecorationOpen+fontWeightOpen+fontStyleOpen+$node.nodeValue+fontStyleClose+fontWeightClose+textDecorationClose+'</font></textformat>'+textAlignClose;
		},
	
		getTextNodes: function($node){
			var results = [];
			var children = $node.childNodes;
		
			for(var i=0; i<children.length; i++){
				if(children[i].nodeType != 3 && children[i].nodeName != 'BR'){
					results = results.concat(this.getTextNodes(children[i]));
				}else{
					results[results.length] = children[i];
				}
			}
			
			return results;
		},
	
		parseNode: function($node){
			
			var nodes = this.getTextNodes($node);
			var newHTML = '';
			for(var i=0; i<nodes.length; i++){
				var n = nodes[i];
				var p = n.parentNode;
				if(n.nodeName == 'BR'){
					newHTML += '<br/>';
				}else{
					var props = {};
					props['text-align'] = TL.Utilities.getElementStyle(p,'text-align');
					props['font-size'] = this.getFontPts(p);
					props['text-decoration'] = TL.Utilities.getElementStyle(p,'text-decoration');
					props['font-weight'] = TL.Utilities.getElementStyle(p,'font-weight');
					props['font-style'] = TL.Utilities.getElementStyle(p,'font-style');
					props['text-indent'] = TL.Utilities.getElementStyle(p,'text-indent');
					props['font-family'] = TL.Utilities.getElementStyle(p,'font-family');
					props['color'] = this.convertColor(TL.Utilities.getElementStyle(p,'color'));
					props['line-spacing'] = TL.Utilities.getElementStyle(p,'line-spacing');
					
					var wrappedNode = this.wrapNode(n,props);
					
					if(p.nodeName == 'A'){
						var t = p.getAttribute('target');
						var h = p.getAttribute('href',2);
						
						if(h.match(/(\.)*/g).length > 1 && h.indexOf('://') == -1){
							h = '"http://'+h+'"';
						}
						
						var target = '';
						if(t != null || t != ''){
							target = ' target="'+t+'"';
						}
						
						wrappedNode = '<a href='+h+target+'>'+wrappedNode+'</a>';
						
					}
					
					newHTML += wrappedNode;
				}
					
				
			}
			
			return newHTML;
		},
	
		replaceHeadings: function($elements){
			for(var i in $elements){
				$elements[i].element.innerHTML = this.buildInnerHTML($elements[i].params);
			}
		},
		
		showHeadings: function($headings){
			for(var i in $headings){
				var h = $headings[i];
				if(h.element.style){
					h.element.style.visibility = "visible";
					
				}
			}
		},
		
		// Only elements that are inline need a resize event
		// Floats in IE also need resize
		headingsForResize:[],
		
		// TODO: optimize this.  Maybe allow each heading to attach to a resize handler individually...
		// separate resize handlers for different needs, rather than looping and using conditionals
		resizeWidths: function(){
				for(var i=0; i<TL.FlashHeaders.headingsForResize.length; i++){
					TL.FlashHeaders.resizeWidth(TL.FlashHeaders.headingsForResize[i]);
				}
		},
		
		
		
		resizeWidth: function($heading){
			
			var heading = $heading.element;
			if(!$heading.params.maxWidth ||!$heading.params.minWidth){
				return false;
			}
			
			var yardstick = heading.firstChild.firstChild.firstChild;
			var placeholder = heading.firstChild.firstChild.nextSibling;
			var swf = placeholder.firstChild;
		
			var w = yardstick.offsetWidth;
			var flt = TL.Utilities.getElementStyle(heading,'float');
			var inl = TL.Utilities.getElementStyle(heading,'display');
			
			var inlineStyles = {"inline":true,"inline-block":true,"table-row-group":true,"-moz-inline-box":true};
			
			// Solving floats in IE
			// Subtract 1 to avoid infinite loop
			if(TL.FlashHeaders.IS_WIN_IE && flt != "none"){
				placeholder.style.width = (w-1)+"px";
			}
			
			//Solving inline elements
			if(inlineStyles[inl]== true && flt == "none"){
				placeholder.style.width = (w-1)+"px";
			}
				
		},
		
		resizeFonts: function(){
		
			var i = headings.length-1;
			do
			{
				var h = headings[i];
				var p = h.params;
				p.swfFontsize = this.getFontPts(h);
				
				h.innerHTML = this.buildInnerHTML(p, this.buildQueryString(p));
				
			}
			while(i--);
			this.resizeWidths();
		},
		
		/*******
		
		Experimental
		Finding the available width via scripting
		
		Probably not feasible:
		The calculations involved would depend greatly on strict-mode 
		(if in strict mode, include margins: if margins are included, units must be normalized)
		
		Do I already preclude quirks mode?
		
		********/
		
		// Available width  = left edge of nearest right neighbor minus right edge of nearest left neighbor 
		getAvailableWidth: function($heading){
			var headingTop = $heading.offsetTop;
			var headingBottom = headingTop + $heading.offsetHeight;
			var headingLeft = $heading.offsetLeft;
			var headingRight = headingLeft + $heading.offsetWidth;
			
			var elementsInFlow = this.getFlowElements();
			
			// Get elements that are in the same horizontal plane as this heading element
			var adjacentNodes = [];
			
			var i = elementsInFlow.length - 1;
			
			do{
				var el = elementsInFlow[i];
				if(el != $heading){
					var elementTop = el.offsetTop;
					var elementBottom = elementTop + el.offsetHeight;
					if(this.isHorizAdjacent(headingTop,headingBottom,elementTop,elementBottom)){
						adjacentNodes[adjacentNodes.length] = el;
					}
				}
			}while(i--);
			
			// Find the nearest left neighbor
			// Its right border may not be greater than the headings right border.
			var i = adjacentNodes.length - 1;
			
			var nearestLeftNeighbor = false;
		
			do{
				var el = adjacentNodes[i];
				
				var elementRight = el.offsetLeft + el.offsetWidth;
				var nearestLeftNeighborRight = nearestLeftNeighbor.offsetWidth + nearestLeftNeighbor.offsetLeft;
				trace(elementRight+" :: "+headingLeft);
				if(elementRight <= headingLeft && el != $heading){
					if(nearestLeftNeighbor == false || elementRight > nearestLeftNeighborRight){
						nearestLeftNeighbor = el;
						
						/*nearestLeftNeighborRight = el.offsetLeft + el.offsetWidth;*/
					}
				}
			}while(i--);
			
			// Find the nearest right neighbor
			// Its left border may not be less than the headings left border.
			var i = adjacentNodes.length - 1;
			var nearestRightNeighbor = false;
			do{
				var el = adjacentNodes[i];
				var elementLeft = el.offsetLeft;
				trace(elementLeft+" :: "+headingRight+" :: "+nearestRightNeighbor.offsetLeft);
				if(elementLeft >= headingRight && el != $heading){
					if(nearestRightNeighbor == false || elementLeft < nearestRightNeighbor.offsetLeft){
						
						nearestRightNeighbor = el;
					}
				}	
			}while(i--);
			
			//TODO: Nearest Right Neighbor doesn't work right
			
		/*	if(($heading.parentNode.offsetLeft + $heading.parentNode.offsetWidth) > nearestLeftNeighborRight){
				nearestLeftNeighborRight = ($heading.parentNode.offsetLeft + $heading.parentNode.offsetWidth);
			}
			
			if($heading.parentNode.offsetLeft < nearestRightNeighbor.offsetLeft){
				nearestRightNeighbor = $heading.parentNode;
			}
			*/
			
			$heading.style.border = "1px solid red;";
			nearestLeftNeighbor.style.border = "1px solid green;";
			nearestRightNeighbor.style.border = "1px solid blue;";
			// The available width is the distance between the right edge of the nearest left neighbor
			// and the left edge of the nearest right neighbor, excluding borders and margins.
			return nearestRightNeighbor.offsetLeft - nearestLeftNeighborRight;
		},
		
		// Finds all the elements in the document that affect flow
		// These are not absolute-positioned, and are not text nodes
		getFlowElements: function(){
			
			var allNodes = document.getElementsByTagName("*"); // This should give us all elements that are not text nodes
			var i = allNodes.length-1;
			var result = [];
			do{
				if(Utils.getElementStyle(allNodes[i],'position') != 'absolute' && Utils.getElementStyle(allNodes[i],'display') != 'inline'){
					result[result.length] = allNodes[i];
				}
			}
			while(i--);
			
			return result;
		},
		
		// Determines if the given coordinates are in the same horizontal plane
		isHorizAdjacent: function($t1,$b1,$t2,$b2){
			if($b1 < $t2){
				return false;
			}
			if($t1 > $b2){
				return false;
			}
			return true;
		},
		
		/*******
		
		End experimental
		
		********/
		
		// TODO: is there something we can put in the yardstick other than images?
		// maybe floated divs?  Can we use a different type of yardstick for different browsers?
		setMinMax:function($id,$minWidth,$maxWidth,$minHeight){
			// A TextField has 2px margins.  Add 4 to compensate.
			$minWidth = parseFloat($minWidth)+4;
			$maxWidth = parseFloat($maxWidth)+4;
			$minHeight = parseFloat($minHeight)+4;
		
			// trace("minWidth: "+$minWidth+" :: minHeight: "+$minHeight+" :: maxWidth: "+$maxWidth);
			var heading = document.getElementById($id);
			var placeholder = heading.parentNode;
			var headingTag = headings[$id].element;
			//var minBlock = placeholder.previousSibling.previousSibling;
			var yardstick = headingTag.firstChild.firstChild.firstChild;
			
			
			
			var fill= '';
			
			
			var minWidth = $minWidth+"px";
			//minBlock.style.width = minWidth;
			fill = '<textarea disabled="true" style="display:inline; width:'+minWidth+'; height:1px; margin:0; padding:0; border:0; border-top:1px solid;" ></textarea>';
			//fill = '<img src="Images/spacer.gif" style="border-top:1px solid; vertical-align:bottom; width:'+minWidth+'; height:0px;" />';
			//fill = '<input style="width:'+minWidth+'; height:1px; margin:0; padding:0; border:0;" />';
			//fill = '<div style="display:-moz-inline-box; width:'+minWidth+'; height:1px; margin:0; padding:0; border:1px solid orange;"></div>';
			//fill = '<div style="display:table; width:'+minWidth+'; height:1px; margin:0; padding:0; border:1px solid orange;"></div>';
			//fill = '<table style="display:inline; border-collapse:collapse; width:'+minWidth+'; height:1px; margin:0; padding:0; border:1px solid orange;"><tr><td style="width:'+minWidth+'; height:1px;">&nbsp;</td></tr></table>';
			
			var fillWidth = $maxWidth-$minWidth;
			
			var fillCount = Math.ceil(fillWidth/10);
			
			if(headings[$id].params.isInline || headings[$id].params.headingFloat != "none"){
		
				for(var i=0; i<fillCount; i++){
					//fill = fill+' .';
					fill = fill + '<textarea disabled="true" style="display:inline; width:10px; height:1px; margin:0; padding:0; border:0; border-top:1px solid;" ></textarea>';
					//fill = fill+'<img src="Images/spacer.gif" style="border-top:1px solid; vertical-align:bottom; width:10px; height:0px;" />';
					//fill = fill + '<input style="width:5px; height:1px; margin:0; padding:0; border:0;" />';
					//fill = fill +'<div style="display:-moz-inline-box; width:5px; height:1px; margin:0; padding:0; border:1px solid orange;"></div>';
					//fill = fill +'<div style="display:table; width:5px; height:1px; margin:0; padding:0; border:1px solid orange;"></div>';
					//fill = fill + '<table style="display:inline; width:10px; height:1px; margin:0; padding:0; border:1px solid orange;"><tr><td style="width:10px; height:1px;">&nbsp;</td></tr></table>';
				}
			}
		
			/*fill = fill+'<span style="clear:left;"></span>'; */
			yardstick.innerHTML = fill;
		
			/*placeholder.style.maxWidth = $maxWidth+"px";*/
		
			headings[$id].params.minHeight = $minHeight;
			headings[$id].params.minWidth = $minWidth;
			headings[$id].params.maxWidth = $maxWidth;
			
		
			/*heading.style.height = parseInt($minHeight)+"px";*/
			/*heading.parentNode.style.height = parseInt($minHeight)+"px";*/
			
			
			
			if(headings[$id].params.isInline || (headings[$id].params.headingFloat != 'none' && TL.FlashHeaders.IS_WIN_IE)){
				TL.FlashHeaders.resizeWidth(headings[$id]);
			}
		},
		
		// TODO: rename this 'setHeadingHeight'
		resizeHeading: function($id,$height,$minWidth,$maxWidth,$minHeight){
			
			if(!headings[$id].initialized){
				/*TL.FlashHeaders.resizeWidth(headings[$id]);*/
				TL.FlashHeaders.setMinMax($id,$minWidth,$maxWidth,$minHeight);
				headings[$id].initialized = true;
			}
			var thisHeading = document.getElementById($id);
			
			// Subtract 4 to compensate for TextField margins
			var h = Math.ceil(parseFloat($height))-4;
			
			//thisHeading.style.height = h+"px";
			thisHeading.parentNode.style.height = h+"px";
		
		},

		init: function(){
			
			headings = TL.FlashHeaders.selectElements();
			TL.FlashHeaders.getHeadingData(headings);
			TL.FlashHeaders.prefetchFonts();
			
			TL.FlashHeaders.onPrefetchComplete = function(){
				var time1 = new Date().getTime();
				TL.FlashHeaders.createEMWidthListener();
				
				var time2 = new Date().getTime();
				TL.FlashHeaders.showHeadings(headings);
				TL.FlashHeaders.replaceHeadings(headings);
				
				TL.Events.addEvent(window,"resize",TL.FlashHeaders.resizeWidths);
				
			}
		
			
			
		}
	}
}();
TL.Events.addOnDOMReadyEvent(TL.FlashHeaders.init);

/*TL.Events.addEvent(window, "load", TL.FlashHeaders.init);*/

