/*                                                                  
* Copyright © 1999-2009 TeaLeaf Technology, Inc.  
* All rights reserved.
*
* THIS SOFTWARE IS PROVIDED BY TEALEAF ``AS IS'' 
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED.  
* IN NO EVENT SHALL TEALEAF BE LIABLE FOR ANY DIRECT, INDIRECT, 
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
* THE POSSIBILITY OF SUCH DAMAGE.
*
* @fileoverview 
* This is the main UI Client Event Capture JavaScript file that is  
* used by other JavaScript to register their onload routines.
*
* @requires 
* TeaLeaf.js
* TeaLeafEvent.js
* TeaLeafClientCfg.js
*
* @version 2009.01.15.1
*                                                                   
*/
if(TeaLeaf.Client && TeaLeaf.Client.Configuration){
	
	TeaLeaf.Client.tlTimeoutID = -1;
	
	/**
    * Enable all event handlers specified in the configuration.
    * @param obj parameter that determines to enable handlers to the window or document object or both.
    * @requires
    * TeaLeafClientCfg.js 
    * @addon
    */            	                                           
    TeaLeaf.Client.tlEnableAllEventHandlers = function(obj) {         
        if(obj){
            if(obj == window){
                TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, true, "all");
            }
            else if(obj == document){
                TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, true, "all");
            }
        } 
        else{
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, true, "all");
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, true, "all");        
        }        
    }
	/**
    * Enable a specific event handler defined in the configuration.
    * @param obj parameter that determines to enable handlers to the window or document object.
    * @param domEventName name of the event to enable.
    * @requires
    * TeaLeafClientCfg.js 
    * @addon
    */            	                                               
    TeaLeaf.Client.tlEnableEventHandler = function(obj, domEventName) { 
        if(obj == window){  
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, true, domEventName); 
        }
        else{
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, true, domEventName); 
        }        
    }
	/**
    * Disable all event handlers specified in the configuration.
    * @param obj parameter that determines to disable handlers to the window or document object or both.
    * @requires
    * TeaLeafClientCfg.js 
    * @addon
    */            	                                           
    TeaLeaf.Client.tlDisableAllEventHandlers = function(obj) { 
        if(obj){
            if(obj == window){
                TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, false, "all");
            }
            else if(obj == document){
                TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, false, "all");
            }
        } 
        else{
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, false, "all");
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, false, "all");        
        }        
    }
	/**
    * Disable a specific event handler defined in the configuration.
    * @param obj parameter that determines to disable handlers to the window or document object.
    * @param domEventName name of the event to enable.
    * @requires
    * TeaLeafClientCfg.js 
    * @addon
    */            	                                                   
    TeaLeaf.Client.tlDisableEventHandlers = function(obj, domEventName) { 
        if(obj == window){                
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, false, domEventName); 
        }
        else{
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, false, domEventName); 
        }        
    }    
	/**
    * Utility that helps enabling or disabling of event handlers.
    * @param tlJSONConfig configuration array.
    * @param tlEnable enable (true or false flag).
    * @param domEventName event name to enable or disable.
    * @addon
    */            	                                                       
    TeaLeaf.Client.tlClientJSONCfgUtil = function(tlJSONConfig, tlEnable, domEventName) {         
        for(var i = 0; i<tlJSONConfig.length; i++){
            if(domEventName == "all"){
                tlJSONConfig[i].load = tlEnable;
            }
            else if (domEventName == tlJSONConfig[i].domevent){
                tlJSONConfig[i].load = tlEnable;
            }
        }  
    }  
	TeaLeaf.Client.tlHasUserMovement = false;
	/**
    * Detect user movement.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                           
	TeaLeaf.Client.tlUserMovement = function() {
		TeaLeaf.Client.tlHasUserMovement = true;
		TeaLeaf.Event.tlRemoveHandler(document, "mousemove", TeaLeaf.Client.tlUserMovement, false);
	}
	/**
    * Add a unique Id to a DOM element.
    * @param itemSource DOM element that needs an id.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                
    TeaLeaf.Client.tlAddIdToControl = function(itemSource) {  	    
	    if ((itemSource.id && itemSource.id != "") || (itemSource.name && itemSource.name != "")) {
		    return;
	    }
	    var idTag = itemSource.tagName;

	    var thereYet = TeaLeaf.Client.Configuration.tlIdCounter[idTag];
	    if (thereYet == undefined)
		    TeaLeaf.Client.Configuration.tlIdCounter[idTag] = 0;

        var idElement = "_TL_" + idTag + "_"
            + TeaLeaf.Client.Configuration.tlIdCounter[idTag];
        var item  = document.getElementById(idElement);
        var baseId = idElement;
        
        if(item){
            //loop through to check if there are items with such ids
            while(document.getElementById("_TL_" + idTag + "_"
                + TeaLeaf.Client.Configuration.tlIdCounter[idTag]++));
        }
        
        itemSource.id = baseId;
        TeaLeaf.Client.Configuration.tlIdCounter[idTag]++;
	}  

	/**
    * Loops through a JSON array to find the elemement if exists.
    * @param name or id of element.
    * @param JSON.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                
	TeaLeaf.Client.tlFindinJSON = function(tlElement, tlJSON) {        
        var tlNameorId = TeaLeaf.Client.tlGetName(tlElement);
        if(tlNameorId){
            for(var i=0; i<tlJSON.length; i++){ 
                if(tlNameorId == tlJSON[i].tlfieldname){  
                    return tlJSON[i];
                }
            }
        }
    }

	/**
    * Check if element is silent.
    * @param name or id of element.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                
	TeaLeaf.Client.tlIsReplace = function(name) {
		//	Nothing there
		if( !name ) {
			return false;
		}
		//	If this an object
		if( typeof name == "object" ) {			
			if( name.TeaLeafReplace) { 	
 				return true;
			}		    
		}
		else{
		    var tlReplace = document.getElementById(name);  
		    if(tlReplace.TeaLeafReplace == true){
 		        return true;		    
		    }		    
		    if(!tlReplace){
		        tlReplace = document.getElementsByName(name);     
		        for(var i=0; i<tlSilent.length; i++){
		            if(tlReplace[i].TeaLeafReplace == true){
 		                return true;
		            }
		        }
		    }
		}
		
		if( name.type == "password" ) {
			return TeaLeaf.Client.Configuration.tlpassword == 2;
		}

		return false;
	}

	/**
    * Replace element with dummy value, needed in some cases
    * when there is client validation.
    * @param elem
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                	
	TeaLeaf.Client.tlReplaceValue = function(elem) {
		var name = TeaLeaf.Client.tlGetName(elem);
		TeaLeaf.Client.tlMakeFieldBlockMap();
		var map_item = TeaLeaf.Client.Configuration.tlFieldBlockMap[name.toLowerCase()];
		if(map_item == null) return "";
		if(map_item["eventvaluereplace"].length > 0) return map_item["eventvaluereplace"];
		else return "";
    }
    
	/**
    * Check if element is excluded from capture.
    * @param name or id of element.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                	
	TeaLeaf.Client.tlIsExcluded = function(name) {
		//	Nothing there
		if( !name ) {
			return false;
		}
		//	If this an object
		if( typeof name == "object" ) {			
			if( name.TeaLeafExclude ) {
				return true;
			}		    
		}
		else{
		    var tlExclude = document.getElementById(name);   		    
		    if(tlExclude){
		        if(tlExclude.TeaLeafExclude){   
		            return true;		    
		        }		       
		    }
		    else{
		        tlExclude = document.getElementsByName(name);     
		        if(tlExclude){
		            for(var i=0; i<tlExclude.length; i++){
		                if(tlExclude[i].TeaLeafExclude){
		                    return true;
		                }
		            }
		        }		    
		    }
		    return false;
		}
		
		if( name.type == "password" ) {
			return TeaLeaf.Client.Configuration.tlpassword == 2;
		}

		return false;
	}
	/**
    * Get the name from a DOM node.
    * @param theNode DOM element.
    * @addon
    */            	                                                                
	TeaLeaf.Client.tlGetName = function(theNode) {
		if( theNode == null ) {
			return null;
		}
		var		id = theNode.id;
		if( id && id != "" ) {
			return id;
		}
		var		name = theNode.name;
		if( name && name != "" ) {
			return name;
		}
		return null;
	}
	/**
    * Get event source DOM element.
    * @param theEvent DOM event.
    * @addon
    */            	                                                                
    TeaLeaf.Client.tlGetEventSource = function(theEvent) {
        var	itemSource = null;       
        if(theEvent){	
	        if( theEvent.srcElement ) {	//	MSFT
	            itemSource = theEvent.srcElement;
	        }
	        else {	//	Mozilla
	            itemSource = theEvent.target;
		        if( itemSource == null ) {
		            itemSource = theEvent.explicitOriginalTarget;			
			        if( itemSource == null ) {
			            itemSource = theEvent.originalTarget;
			        }
	    	    }
	        }
	        if(itemSource && (itemSource.name == null || itemSource.name == "")) {
	            //	If an Anchor or link, I can look info up in the list
		        if( itemSource.parentNode && itemSource.parentNode.tagName ) {
		            if( itemSource.parentNode.tagName == "A" ||
			            itemSource.parentNode.tagName == "LINK" ) {
				            itemSource = itemSource.parentNode;
			            }
		            }
	            }
	        }
	    return itemSource;
    }	
	/**
    * If we don't have an name, get the index from either the anchors
    * or the links collection.
    * @param theNode DOM element.
    * @param full XML format.
    * @addon
    */            	                                                                
	TeaLeaf.Client.tlGetAnchor = function(theNode, full) {
		if( theNode == null ) {
			return null;
		}
		if( theNode.name && theNode.name != "" ) {
			return null;
		}
		var		idx;
		for(idx = 0; idx < document.anchors.length; idx++) {
			if( document.anchors[idx] == theNode ) {
				if( full ) {
					return "<AnchorElement>" + idx + "</AnchorElement>\r\n";
				}
				else {
					return "Anchor-" + idx;
				}
			}
		}
		for(idx = 0; idx < document.links.length; idx++) {
			if( document.links[idx] == theNode ) {
				if( full ) {
					return "<LinkElement>" + idx + "</LinkElement>\r\n";
				}
				else {
					return "Link-" + idx;
				}
			}
		}	
		return null;
	}

	/**
	 * Check if element is of type input
	 */
	TeaLeaf.Client.checkIsInput = function(elem) {
	    if(typeof(elem) == "string") elem = document.getElementById(elem);
	
            switch(elem.tagName) 
	    {
		case "INPUT":
		case "SELECT":
		case "TEXTAREA":
		    return true;
	    }

	    return false;
	}


	/**
    * If we don't have an name, get the index from either the anchors
    * or the links collection.
    * @param str XML string.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                	
	TeaLeaf.Event.tlFormatXMLName = function(str) {
		//	Nothing handed in
		if( ! str || str.length <= 0 )
			return null;

		var	rtn = "";
		if( ! TeaLeaf.Event.tlNameStartChar(str.charCodeAt(0)) ) {
			rtn = "_";
		}
		var	max = str.length;
		var	ind;
		for(ind = 0; ind < max; ind++) {
			if( TeaLeaf.Event.tlNameChar(str.charCodeAt(ind)) ) {
				rtn = rtn + str.charAt(ind);
			}
			else {
				rtn = rtn + "_";
			}
		}
		return rtn;
	}
	/**
	* Utility function to help format the XML.
    * @param chr character.
    * @addon
    */            	                                                                	
    TeaLeaf.Event.tlNameStartChar = function(chr) {
		//	":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] |
		//	[#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] |
		//	[#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] |
		//	[#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD]
		//	Note:  ":" was removed because it is only valid when a namespace
		//	is defined
		return (chr >= 0x41 && chr <= 0x5A) || chr == 0x5F ||
			(chr >= 0x61   && chr <= 0x7A)   || (chr >= 0xC0   && chr <= 0xD6)   ||
			(chr >= 0xD8   && chr <= 0xF6)   || (chr >= 0xF8   && chr <= 0x2FF)  ||
			(chr >= 0x370  && chr <= 0x37D)  || (chr >= 0x37F  && chr <= 0x1FFF) ||
			(chr >= 0x200C && chr <= 0x200D) || (chr >= 0x2070 && chr <= 0x218F) ||
			(chr >= 0x2C00 && chr <= 0x2FEF) || (chr >= 0x3001 && chr <= 0xD7FF) ||
			(chr >= 0xF900 && chr <= 0xFDCF) || (chr >= 0xFDF0 && chr <= 0xFFFD);
	}
	/**
	* Utility function to help format the XML.
    * @param chr character.
    * @addon
    */            	                                                                	
    TeaLeaf.Event.tlNameChar = function(chr) {
		//	NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
		return TeaLeaf.Event.tlNameStartChar(chr) || chr == 0x2D || chr == 0x2E ||
			(chr >= 0x30 && chr <= 0x39) || chr == 0xB7  ||
			(chr >= 0x0300 && chr <= 0x036F) || (chr >= 0x203F && chr <= 0x2040);
	}

	TeaLeaf.Client.tlQueuedKeys = "";

	/**
    * Queues the keys
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                	
	TeaLeaf.Client.tlQueueKey = function(theEvent) {
        TeaLeaf.Client.tlSendResize();
        TeaLeaf.Client.tlSendScroll();
		if( ! theEvent ) {
			theEvent = window.event;
		}
		if( theEvent.keyCode < 0x20 ) {
			return;
		}
		//	Residual keys to send in?  Save the source for next time around
		var	itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
		if( ! itemSource ) {
			return;
		}
		//	Do we need to set the onFocus time?
		if( ! itemSource.TeaLeafFocusTime ) {
			itemSource.TeaLeafFocusTime = new Date();
		}
		if( TeaLeaf.Client.tlQueuedKeySource ) {
			if( TeaLeaf.Client.tlQueuedKeySource != itemSource ) {
				if( TeaLeaf.Client.tlQueuedKeys && TeaLeaf.Client.tlQueuedKeys.length > 0 )
                    TeaLeaf.Client.tlSendKeys();
				TeaLeaf.Client.tlQueuedKeySource = itemSource;
			}
		}
		else {
			TeaLeaf.Client.tlQueuedKeySource = itemSource;
		}
		//	Get the name/anchor where the key happened.  If both are null,
		//	don't worry about logging
		var	name  = TeaLeaf.Client.tlGetName(itemSource);

		var	lev = null;
		if( ! name ) {
			lev = TeaLeaf.Client.tlGetAnchor(itemSource, false);
			if( ! lev ) {
				TeaLeaf.Client.tlQueuedKeySource = null;
				return;
			}
		}
		else {
			if( TeaLeaf.Client.tlIsReplace(itemSource) ) {
				TeaLeaf.Client.tlQueuedKeysCount++;
				return;
			}
			if( TeaLeaf.Client.tlIsExcluded(itemSource) ) {
			    TeaLeaf.Client.tlQueuedKeys=null;
				TeaLeaf.Client.tlQueuedKeysCount++;
				return;
			}
		}
		//	Put in the seperator if we need it
		if( TeaLeaf.Client.tlQueuedKeys ) {
			if( TeaLeaf.Client.tlQueuedKeys.length > 0 ) {
				TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + ";";
			}
		}
		//	build the string
		if( theEvent.ctrlKey ) {
			if( TeaLeaf.Client.tlQueuedKeys ) {
				TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + "ctrl-";
			}
			else {
				TeaLeaf.Client.tlQueuedKeys = "ctrl-";
			}
		}
		if( theEvent.altKey ) {
			if( TeaLeaf.Client.tlQueuedKeys ) {
				TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + "alt-";
			}
			else {
				TeaLeaf.Client.tlQueuedKeys = "alt-";
			}
		}
		if( theEvent.shiftKey ) {
			if( TeaLeaf.Client.tlQueuedKeys ) {
				TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + "shift-";
			}
			else {
				TeaLeaf.Client.tlQueuedKeys = "shift-";
			}
		}
		TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + theEvent.keyCode;
	}
	/**
    * Send the keys.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                	
	TeaLeaf.Client.tlSendKeys = function() {	
		if( ! TeaLeaf.Client.tlQueuedKeySource ||
			( ! TeaLeaf.Client.tlQueuedKeys && ! TeaLeaf.Client.tlQueuedKeysCount ) ) {
				return;
		}
		//	Save the values to temp variables and null out the
		//	queue variables
		var	qSource = TeaLeaf.Client.tlQueuedKeySource;
		var	qKeys   = TeaLeaf.Client.tlQueuedKeys;
		var	qCount  = TeaLeaf.Client.tlQueuedKeysCount;
		TeaLeaf.Client.tlQueuedKeySource = null;
		TeaLeaf.Client.tlQueuedKeys      = "";
		TeaLeaf.Client.tlQueuedKeysCount = 0; 
    
        var tlreplace = false; 
		if( TeaLeaf.Client.tlIsReplace(qSource) ) {		
			tlreplace = true;
			return;
		}
		var	excluded = false;
 
		if( TeaLeaf.Client.tlIsExcluded(qSource) ) {

			excluded = true;
			qKeys = null;
		}
		//	Get the name/anchor where the key happened.  If both are null,
		//	don't worry about logging
		var	name  = TeaLeaf.Client.tlGetName(qSource);
		var	lev = null;
		if( name == null ) {
			lev = TeaLeaf.Client.tlGetAnchor(qSource, false);
			if( lev == null ) {
				return;
			}
		}
		else {
			if( TeaLeaf.Client.tlIsExcluded(name) ) {
				return null;
			}
		}
		//	The Reporting Event
		var	tlevt = new TeaLeaf.Event("GUI", "KeyUp");
        var tlAddNameValueArray = ["Name", qSource.name,
			                       "Id", qSource.id,
			                       "Lev", lev,
			                       "ElementType", qSource.type,
			                       "TagName", qSource.tagName,
			                       "KeyCount", qCount];
        tlevt.tlAddData(tlAddNameValueArray);

		if(excluded) {
		    var tlAddNameValueArrayExcluded = ["Excluded", "true"];
            tlevt.tlAddData(tlAddNameValueArrayExcluded);
		}
		else if(tlreplace){
			
			var tlRepValue = TeaLeaf.Client.tlGetReplaceValue(qSource);			
			var tlAddNameValueArrayReplaceName = ["ValueIn", name,
				                                  name,   tlRepValue,
				                                  "KeyCode", qKeys];                                          
			tlevt.tlAddData(tlAddNameValueArrayReplaceName);
		}
		else {
			var	tlManualName = TeaLeaf.Event.tlFormatXMLName(name);			
			var tlAddNameValueArrayManualName = ["ValueIn", tlManualName,
				                                 tlManualName,   qSource.value,
				                                 "KeyCode", qKeys];                                          
			tlevt.tlAddData(tlAddNameValueArrayManualName);
		}
		//	Now send the data in
		tlevt.tlSend();
	}
	/**
    * Send resize event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                	
	TeaLeaf.Client.tlSendResize = function() {	
		if( ! TeaLeaf.Client.ResizeClientX && ! TeaLeaf.Client.ResizeClientY ) {
			return;
		}
		var	tlevt = new TeaLeaf.Event("GUI", "Resize");
        var tlAddNameValueArray = ["ClientX", TeaLeaf.Client.ResizeClientX,
			                       "ClientY", TeaLeaf.Client.ResizeClientY,
			                       "ScreenX", TeaLeaf.Client.ResizeScreenX,
			                       "ScreenY", TeaLeaf.Client.ResizeScreenY];
        tlevt.tlAddData(tlAddNameValueArray);
		TeaLeaf.Client.ResizeClientX = null;
		TeaLeaf.Client.ResizeClientY = null;
		TeaLeaf.Client.ResizeScreenX = null;
		TeaLeaf.Client.ResizeScreenY = null;
		//	Now send the data in
		tlevt.tlSend();
	}
	
	/**
    * Queue scroll event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	
    TeaLeaf.Client.tlQueueScroll = function(tlEvent) {

	    TeaLeaf.Client.tlSendKeys();
	    TeaLeaf.Client.tlSendResize();

	    if( ! tlEvent ) {
		    tlEvent = window.event;
	    }
	    
	    if( tlEvent.clientX ) {
		    //	IE
		    TeaLeaf.Client.ScrollClientX = tlEvent.clientX;
		    TeaLeaf.Client.ScrollClientY = tlEvent.clientY;
		    TeaLeaf.Client.ScrollScreenX = tlEvent.screenX;
		    TeaLeaf.Client.ScrollScreenY = tlEvent.screenY;
	    }
	    else {
		    //	Other
		    TeaLeaf.Client.ScrollHeight = tlEvent.target.scrollHeight;
		    TeaLeaf.Client.ScrollWidth  = tlEvent.target.scrollWidth;
		    TeaLeaf.Client.ScrollTop    = tlEvent.target.scrollTop;
		    TeaLeaf.Client.ScrollLeft   = tlEvent.target.scrollLeft;
	    }
    }

	/**
    * Send scroll event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                	
	TeaLeaf.Client.tlSendScroll = function() {	
		if( ! TeaLeaf.Client.ScrollClientX && ! TeaLeaf.Client.ScrollHeight ) {
			return;
		}
		var	tlevt = new TeaLeaf.Event("GUI", "Scroll");
        var tlAddNameValueArray = ["ClientX",      TeaLeaf.Client.ScrollClientX,
			                                "ClientY",      TeaLeaf.Client.ScrollClientY,
			                                "ScreenX",      TeaLeaf.Client.ScrollScreenX,
			                                "ScreenY",      TeaLeaf.Client.ScrollScreenY,
			                                "ScrollHeight", TeaLeaf.Client.ScrollHeight,
			                                "ScrollWidth",  TeaLeaf.Client.ScrollWidth,
			                                "ScrollTop",    TeaLeaf.Client.ScrollTop,
			                                "ScrollLeft",   TeaLeaf.Client.ScrollLeft];	
		tlevt.tlAddData(tlAddNameValueArray);	
		TeaLeaf.Client.ScrollClientX = null;
		TeaLeaf.Client.ScrollClientY = null;
		TeaLeaf.Client.ScrollScreenX = null;
		TeaLeaf.Client.ScrollScreenY = null;
		TeaLeaf.Client.ScrollHeight  = null;
		TeaLeaf.Client.ScrollWidth   = null;
		TeaLeaf.Client.ScrollTop     = null;
		TeaLeaf.Client.ScrollLeft    = null;
		//	Now send the data in
		tlevt.tlSend();
	}

    /**
    * Find the nearest ancestor for a DOM node of the given type
    * @param node The original node
    * @param tag The tag to match on
    * @addon
    */  
	TeaLeaf.Client.tlFindAncestorByTag = function(node, tag)
    {
        var cur_node = node.parentNode;
        while(cur_node && cur_node != window.document)
        {
            if(cur_node.nodeType != 1) continue;
            if(cur_node.tagName == tag) break;
            else cur_node = cur_node.parentNode;
        }
        
        return cur_node;
    }

    /**
    * Generate an XPath for the node, consumable by TeaLeaf.Client.tlGetNodeFromXPath
    * @param node The starting node
    * @param tag The tag to match on
    * @addon
    */
    TeaLeaf.Client.tlGetXPathFromNode = function(node)
    {
        if(node == null) return null;
        var xpath = [];
        var cur_node = node;
        var nodes_arr = null;
        var parent_node = null;

	 // Hack fix to handle tags that are not normally visual elements
	 for(var i in TeaLeaf.Client.Configuration.tlSpecialChildNodeTags)
	 {
		if(cur_node.tagName.toString()==i)
			cur_node = cur_node.parentNode;
	 }
        
       while(cur_node != window.document && (cur_node.id == null || cur_node.id == ""))
       {
            nodes_arr = null;
            parent_node = null;
            switch(cur_node.tagName)
            {
                case "TD":
                    if(parent_node = TeaLeaf.Client.tlFindAncestorByTag(cur_node, "TR"))
                        nodes_arr = parent_node.cells;
                    break;
                case "TR":
                    if(parent_node = TeaLeaf.Client.tlFindAncestorByTag(cur_node, "TABLE"))
                        nodes_arr = parent_node.rows;
                    break;
	        case "OPTION":
		            if(parent_node = TeaLeaf.Client.tlFindAncestorByTag(cur_node, "SELECT"))
		                nodes_arr = parent_node.options;
		    break;
                default:
                    parent_node = cur_node.parentNode;
		            if(!parent_node) parent_node = window.document;
		            nodes_arr = parent_node.childNodes;
		            break;
            }
            
            if(nodes_arr == null) return null;
            var j=0;
            for(var i=0; i<nodes_arr.length; i++)
            {
	            if(nodes_arr[i].nodeType == 1 && nodes_arr[i].tagName == cur_node.tagName)
                {
                    if(nodes_arr[i] == cur_node)
                    {
                        xpath[xpath.length] = [cur_node.tagName.toUpperCase(), j];
                        break;
                    }
                    
                    j++;
                }
            }
            
	    cur_node = parent_node;
        }
        
        if(cur_node.id != null && cur_node.id != "") xpath[xpath.length] = [cur_node.id];
        
        var parts = [];
        for(var i=xpath.length-1; i>=0; i--)
        {
            if(xpath[i].length > 1)
                parts[parts.length] = "['"+xpath[i][0]+"',"+xpath[i][1]+"]";
            else
                parts[parts.length] = "['"+xpath[i][0].replace(/'/g, "\\'")+"']";
        }
        
        return "["+parts.join(",")+"]";
    }

    /**
    * Find a node specified by an XPath generated by TeaLeaf.Client.tlGetXPathFromNode
    * @param path The XPath
    * @addon
    */      
    TeaLeaf.Client.tlGetNodeFromXPath = function(path, decode)
    {
        if(path == null) return null;
	if(decode) path = TeaLeaf.Event.tlXMLDecode(path);
        var xpath = eval(path);
        if(xpath == null) return null;
        var cur_node = window.document;
        
        for(var i=0; i<xpath.length; i++)
        {
	        found = false;
            if(xpath[i].length == 1)
            {
                cur_node = document.getElementById(xpath[i]);
                if(cur_node == null) return null; 
            }
            else
            {
                k = 0;
	            switch(cur_node.tagName)
	            {
		            case "TABLE": children = cur_node.rows; break;
		            case "TR": children = cur_node.cells; break;
		            case "SELECT": children = cur_node.options; break;
		            default: children = cur_node.childNodes; break;
	            }

                for(var j=0; j<children.length; j++)
                {
	                if(children[j].nodeType != 1) continue;
                    if(children[j].tagName.toUpperCase() == xpath[i][0])
                    {
                        if(k == xpath[i][1])
                        {
                            cur_node = children[j];
		                    found = true;
                            break;
                        }
                        
                        k++;
                    }
                }

	            if(!found) return null;
            }
        }
       
        return cur_node;
    }

    // Added to have a globally accessible version (not under TeaLeaf namespace)
    window.TeaLeaf_Client_tlGetNodeFromXPath = TeaLeaf.Client.tlGetNodeFromXPath;

	/**
    * Add an event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                	
	TeaLeaf.Client.tlAddEvent = function(theEvent) {
		//	Check for a null
		if( ! theEvent ) theEvent = window.event;

		//	Try to mark the event so that it is not reprocessed. It will
		//	depend on the browsers event model, whether the same event is
		//	bubbled or a duplicate instance of it is.
		if(theEvent.tealeafMarked === true) return;
		//theEvent.tealeafMarked = true;

		//	Get the target - If we have no way to identify then discard
		var	itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
		if( ! itemSource ) return;

		//	Send in any queued keys and resizes		
        	TeaLeaf.Client.tlSendKeys();
        	TeaLeaf.Client.tlSendResize();
        	TeaLeaf.Client.tlSendScroll();		

		//	Do we need to set the onFocus time?
		if( ! itemSource.TeaLeafFocusTime ) {
			switch(theEvent.type)
			{
				case "keyup":
				case "change":
				case "click":
				case "dblclick":
				case "mousedown":
					itemSource.TeaLeafFocusTime = new Date();
					break;
			}
		}
		
		//	Ignore flash for blur
		if( theEvent.type == "blur" && itemSource.type == "application/x-shockwave-flash" ) {
			return;
		}
	
			

		if(theEvent.type == "click" && TeaLeaf.Client.checkIsInput(itemSource)){
		    TeaLeaf.Event.Configuration.tlidoflastvisitedcontrol = TeaLeaf.Client.tlGetName(itemSource);	      
		}
		//	The Reporting Event
		var	tlevt = new TeaLeaf.Event("GUI", theEvent.type);
		//	Start the node tag
		
		var tlAddNameValueArray = ["Name", itemSource.name,
			                       "Id", itemSource.id,
			       			       "ElementType", itemSource.type,
			                       "TagName", itemSource.tagName,
			                       "AltKey", theEvent.altKey?"True":null,
			                       "CtrlKey", theEvent.ctrlKey?"True":null,
			                       "ShiftKey", theEvent.shiftKey?"True":null,
			                       "NodeName", theEvent.nodeName,
			                       "NodeValue", theEvent.nodeValue,
							       "XPath", TeaLeaf.Client.tlGetXPathFromNode(itemSource)];
        tlevt.tlAddData(tlAddNameValueArray);


		var tlName = TeaLeaf.Client.tlGetName(itemSource);

		if( theEvent.type == "blur" && itemSource.TeaLeafFocusTime ) {
			var	now = new Date();
			var tlAddNameValueArrayTimeIn = ["TimeInControl", TeaLeaf.Event.tlDateDiff(now, itemSource.TeaLeafFocusTime)];
            tlevt.tlAddData(tlAddNameValueArrayTimeIn);
			itemSource.TeaLeafFocusTime = null;
		}

        if(itemSource.TeaLeafExclude) {
		    var tlAddNameValueArrayExcluded = ["Excluded", "true"];
		    tlevt.tlAddData(tlAddNameValueArrayExcluded);
		}		 
        else{
            var tlManualName = TeaLeaf.Event.tlFormatXMLName(tlName);
            var tlRepValue = itemSource.TeaLeafReplace ? TeaLeaf.Client.tlReplaceValue(itemSource) : itemSource.value;
            var tlAddNameValueArrayManualName = ["ValueIn", tlManualName, 
                                                 tlManualName, tlRepValue,
				                                 "KeyCode", theEvent.keyCode];                            
           tlevt.tlAddData(tlAddNameValueArrayManualName);		
       }

		tlevt.tlSend();
	}	
	/**
    * Send all the form field values with the form submit.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                			
	TeaLeaf.Client.tlHandleFormSubmit = function(theEvent) {
		//	Log that we did a submit - this will be send in the unload
		TeaLeaf.Client.Configuration.tlactiontype = "Submit";	
		//	Send in any queued keys and resizes
        TeaLeaf.Client.tlSendKeys();
        TeaLeaf.Client.tlSendResize();
        TeaLeaf.Client.tlSendScroll();

		//	Check for a null
		if( ! theEvent ) {
			theEvent = window.event;
		}
		//	Get the target - If we have no way to identify then discard
		var	itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
		if( ! itemSource ) {
			return;
		}
		//	If item Source.name is not definded, let's make one up
		var	i;
		if( ! itemSource.name ) {
			var	forms = document.forms;
			for(i = 0; i < forms.length; i++) {
				if( forms[i] == itemSource ) {
					itemSource.name = "Ordinal-" + i;
					break;
				}
			}
		}
		//	We have no name - forget it.
		if( ! itemSource.name ) {
			return;
		}
		//	Is this one of our silent controls
        if( TeaLeaf.Client.tlIsReplace(itemSource) ) {
            var tlRepValue = TeaLeaf.Client.tlGetReplaceValue(itemSource);			
            var name = TeaLeaf.Client.tlGetName(itemSource);
            var tlAddNameValueArrayReplaceName = ["ValueIn", name, name,   tlRepValue]; 

            tlevt.tlAddData(tlAddNameValueArrayReplaceName);      
        }
		//	The Reporting Event
		var	tlevt = new TeaLeaf.Event("GUI", theEvent.type);
		//	Start the node tag
        var tlAddNameValueArray = ["Name", itemSource.name,
			                       "Id", itemSource.id,
			                       "ElementType", itemSource.type,
			                       "TagName", itemSource.tagName,
			                       "AltKey", theEvent.altKey?"True":null,
			                       "CtrlKey", theEvent.ctrlKey?"True":null,
			                       "ShiftKey", theEvent.shiftKey?"True":null,
			                       "NodeName", theEvent.nodeName,
			                       "NodeValue", theEvent.nodeValue,
			                       "VisitOrder", TeaLeaf.Event.Configuration.tlvisitorder];
        tlevt.tlAddData(tlAddNameValueArray);
		var	children = itemSource.getElementsByTagName("INPUT");
		var tlAddNameValueArrayInputFieldCount = ["InputFieldCount", children.length];
        tlevt.tlAddData(tlAddNameValueArrayInputFieldCount);
		tlevt.tlPushXML("InputFields");	
		//	Do through the children
		for(i = 0; i < children.length; i++) {
			var	child = children[i];
			//	No name, skip
			if( ! child.name ) {
				continue;
			}
			//	Put the field tag in
			tlevt.tlPushXML("Field"+i);
            var tlAddNameValueArrayNode = ["Name", child.name,
				                           "Id", child.id,
				                           "ElementType", child.type,
				                           "TagName", child.tagName];
            tlevt.tlAddData(tlAddNameValueArrayNode);
				
			if( TeaLeaf.Client.tlIsExcluded(name) ) {
			    var tlAddNameValueArrayExcluded = ["Excluded", "true"];
			    tlevt.tlAddData(tlAddNameValueArrayExcluded);
			}
			//	Is this one of our silent controls
			else if( TeaLeaf.Client.tlIsReplace(child.name) ) {
                var tlRepValue = TeaLeaf.Client.tlGetReplaceValue(child);			
                var name = TeaLeaf.Client.tlGetName(child);
                var tlAddNameValueArrayReplaceName = ["ValueIn", name,name,   tlRepValue]; 

                tlevt.tlAddData(tlAddNameValueArrayReplaceName);      
			}
			else {
				var	tlManualName = TeaLeaf.Event.tlFormatXMLName(child.name);
			    var tlAddNameValueArrayManualName = ["ValueIn", tlManualName, tlManualName, child.value];
                tlevt.tlAddData(tlAddNameValueArrayManualName);
			}
			tlevt.tlPopXML();
		}
		tlevt.tlPopXML();
		tlevt.tlSend();
		TeaLeaf.Event.Configuration.tlvisitorder = "";
	}
	/**
    * Handle the resize event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                			
	TeaLeaf.Client.tlQueueResize = function(tlEvent) {
		TeaLeaf.Client.tlSendKeys();
		TeaLeaf.Client.tlSendScroll();
		if( ! tlEvent ) {
			tlEvent = window.event;
		}
		if( tlEvent.clientX) {
			TeaLeaf.ResizeClientX = tlEvent.clientX;
			TeaLeaf.ResizeClientY = tlEvent.clientY;
			TeaLeaf.ResizeScreenX = tlEvent.screenX;
			TeaLeaf.ResizeScreenY = tlEvent.screenY;
		}
		else {
			TeaLeaf.ResizeClientX = tlEvent.target.width;
			TeaLeaf.ResizeClientY = tlEvent.target.height;
		}
	}
	/**
    * Handle the form reset event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                			
	TeaLeaf.Client.tlHandleFormReset = function(theEvent) {
		//	Send in any queued keys and resizes
		TeaLeaf.Client.tlSendKeys();
		TeaLeaf.Client.tlSendResize();
		TeaLeaf.Client.tlSendScroll();
		//	Check for a null
		if( ! theEvent ) {
			theEvent = window.event;
		}
		//	Get the target - If we have no way to identify then discard
		var	itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
		if( ! itemSource ) {
			return;
		}
		//	If item Source.name is not definded, let's make one up
		var	i;
		if( ! itemSource.name ) {
			var	forms = document.forms;
			for(i = 0; i < forms.length; i++) {
				if( forms[i] == itemSource ) {
					itemSource.name = "Ordinal-" + i;
					break;
				}
			}
		}
		//	We have no name - forget it.
		if( name == null ) {
			return;
		}
		//	Is this one of our silent controls
		if( TeaLeaf.Client.tlIsReplace(itemSource) ) {
		    var tlRepValue = TeaLeaf.Client.tlGetReplaceValue(itemSource);			
            var tlname = TeaLeaf.Client.tlGetName(itemSource);
            var tlAddNameValueArrayReplaceName = ["ValueIn", tlname,
                                                tlname,   tlRepValue]; 
            tlevt.tlAddData(tlAddNameValueArrayReplaceName);

		}
		//	The Reporting Event
		var	tlevt = new TeaLeaf.Event("GUI", theEvent.type);
		//	Start the node tag
        var tlAddNameValueArray = ["Name", itemSource.name,
			                       "Id", itemSource.id,
			                       "ElementType", itemSource.type,
			                       "TagName", itemSource.tagName,
			                       "AltKey", theEvent.altKey?"True":null,
			                       "CtrlKey", theEvent.ctrlKey?"True":null,
			                       "ShiftKey", theEvent.shiftKey?"True":null,
			                       "NodeName", theEvent.nodeName,
			                       "NodeValue", theEvent.nodeValue,
			                       "VisitOrder", TeaLeaf.Event.Configuration.tlvisitorder];
        tlevt.tlAddData(tlAddNameValueArray);
		tlevt.tlSend();
		TeaLeaf.tlVisitOrder = "";
	}	
	/**
    * Handle the before unload event and flush the queue of events client events captured.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                			
	TeaLeaf.Client.tlBeforeUnload = function() {
	    // Only let this fire once
	    if(TeaLeaf.Client.tlBeforeUnloadFired) return;
	    TeaLeaf.Client.tlBeforeUnloadFired = true;

	    // If configured to do so, store the current event queue xml in a cookie
	    // so if it fails to send up it can be sent with the next page's events
	    if(typeof TeaLeaf.Cookie != "undefined" && TeaLeaf.Client.Configuration.tlStoreQueueInCookie){
		    var d = new Date();
		    d.setTime(d.getTime()+300000);
		    var cookie_val = TeaLeaf.Event.tlQueuedXML.replace(/(\r|\n)/g, "").replace(/;/g, "%3B");
		    TeaLeaf.Cookie.tlSetCookieValue("tlQueuedXML", cookie_val, d, "/");
	    }
        if(TeaLeaf.Client.Configuration.tlbeforeunloadflag == true){ 
            TeaLeaf.Event.Configuration.tllastdwelltime = new Date();
            TeaLeaf.Client.Configuration.tlunloadflag = false;   
		 
		    //	Send in the notice
		    var	tlevt = new TeaLeaf.Event("PERFORMANCE", "BeforeUnload");	
		    TeaLeaf.Event.SetType = tlevt.EventType;

		    if(TeaLeaf.Event.SetSubType == ""){
                TeaLeaf.Event.SetSubType = tlevt.EventSubType;
            }
            else{
                TeaLeaf.Event.SetSubType += "; " + tlevt.EventSubType;
            }                    
            TeaLeaf.Event.Configuration.tlbeforeunloadflag = true;
            var tlAddNameValueArray = ["MouseMove", TeaLeaf.Client.tlHasUserMovement?"TRUE":"FALSE",
		                                        "Action", TeaLeaf.Client.Configuration.tlactiontype, 
		                                        "VisitOrder", TeaLeaf.Event.Configuration.tlvisitorder];          
            tlevt.tlAddData(tlAddNameValueArray);
            TeaLeaf.Event.Configuration.tlasync = false;        		
		    tlevt.tlSend();
	
		    TeaLeaf.Event.tlFlushQueue(true);
		    TeaLeaf.Event.Configuration.tlvisitorder = "";
		    TeaLeaf.Client.tlDetachFromAllControls();
		}
	}
	/**
    * Handle the unload event and flush the queue of events client events captured.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                				
	TeaLeaf.Client.tlUnload = function(){
        if( TeaLeaf.Client.Configuration.tlunloadflag ){         
            TeaLeaf.Event.Configuration.tllastdwelltime = new Date();
            TeaLeaf.Client.Configuration.tlbeforeunloadflag = false;

		    //	Send in the notice
		    var	tlevt = new TeaLeaf.Event("PERFORMANCE", "Unload");
		    TeaLeaf.Event.SetType = tlevt.EventType;
		    
		    if(TeaLeaf.Event.SetSubType == ""){
                TeaLeaf.Event.SetSubType = tlevt.EventSubType;
            }
            else{
                TeaLeaf.Event.SetSubType += "; " + tlevt.EventSubType;
            }
            var tlAddNameValueArray = ["MouseMove", TeaLeaf.Client.tlHasUserMovement?"TRUE":"FALSE",
		                               "Action", TeaLeaf.Client.Configuration.tlactiontype, 
		                               "VisitOrder", TeaLeaf.Event.Configuration.tlvisitorder];
            tlevt.tlAddData(tlAddNameValueArray);
            TeaLeaf.Event.Configuration.tlasync = false;
		    tlevt.tlSend();
		    TeaLeaf.Event.tlFlushQueue(true);
		    TeaLeaf.Event.Configuration.tlvisitorder = "";
		    TeaLeaf.Client.tlDetachFromAllControls();
        }
	}
	/**
    * Attach listeners to all controls including controls in frames.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                			
	TeaLeaf.Client.tlAttachToAllControls = function() {
        //TeaLeaf.Client.tlMarkBlocked();
		TeaLeaf.Client.Configuration.tlcontrolsattached = true;
		//	Attach to the main window
		TeaLeaf.Client.tlAttachToControls(window);
		//	Attach to the frame controls
        try{
			var	ind;
			for(ind = 0; ind < window.frames.length; ind++) {
				if(window == window.frames[ind]) continue;
				TeaLeaf.Client.tlAttachToControls(window.frames[ind]);
			}
		}
		catch(e){}
	}
	
	/**
    * Attach listeners for specified events to specified controls.
    * 
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                			
	TeaLeaf.Client.tlSingleAttach = function() {	
	    var tldomsingleelements = TeaLeaf.Client.Configuration.tlSingleAttach;
	
        for(var i=0; i<tldomsingleelements.length; i++){      
            if(tldomsingleelements[i].domelementID
                    && tldomsingleelements[i].domelementID !=""){                
                var tlelement = document.getElementById(tldomsingleelements[i].domelementID);
                if(tlelement){
                    var func = eval(tldomsingleelements[i].tlhandler);
                    TeaLeaf.Event.tlAddHandler(tlelement, tldomsingleelements[i].domevent, func, false);   
                }            
            }
        }
	}

	/**
    * Attach listeners to controls based on the configuration. It also attaches 
    * 'beforeunload' and 'unload' handlers.
    * @param win window object.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                			
	TeaLeaf.Client.tlAttachToControls = function(win) {
            try{
                TeaLeaf.Event.tlAddHandler(win, "beforeunload", eval(TeaLeaf.Client.tlBeforeUnload), false);
                TeaLeaf.Event.tlAddHandler(win, "unload", eval(TeaLeaf.Client.tlUnload), false);
                // Attach to all listeners for all the window and document
                //controls.
                var handlers = TeaLeaf.Client.Configuration.tlWindowHandlers;
                for(var i=0; i<handlers.length; i++) {
                    if(handlers[i].load == true){
                        var func = eval(handlers[i].tlhandler);
                        TeaLeaf.Event.tlAddHandler(win, handlers[i].domevent, func, false);
                    }
                }

                handlers = TeaLeaf.Client.Configuration.tlDocumentHandlers;
                for(var i=0; i<handlers.length; i++) {
                    if(handlers[i].load == true){
                        var func = eval(handlers[i].tlhandler);
                        TeaLeaf.Event.tlAddHandler(win.document, handlers[i].domevent, func, false);
                    }
                }

                // Look for the individual controls
		TeaLeaf.Client.tlProcessNode(win.document.body);

                //TeaLeaf.Client.tlCheckIndControls(win);
            }
            catch (e) { }
	}
	/**
    * Check if a handler is attached to a control, otherwhise,
    * if the control is INPUT or SELECT attach focus, blur and change 
    * @param control control to check.
    * @requires 
    * TeaLeafEvent.js
    * @addon
    */            	                                                                				
	TeaLeaf.Client.tlCheckAttach = function(control) {	
		//	Already got this control
		if( control.TeaLeaf || control.TeaLeafExclude) return;
		control.TeaLeaf = true;

		if(TeaLeaf.Client.Configuration.tlassignTLID)
			TeaLeaf.Client.tlAddIdToControl(control);

	  	TeaLeaf.Client.tlMakeFieldBlockMap();

		//	Double check for the listed tagnames. If it matches, attach
		//	for focus, blur and change, since the document object won't see these
		switch(control.tagName)
		{
			case "INPUT":
			case "SELECT":
			case "TEXTAREA":
				if( TeaLeaf.Client.Configuration.tlsendfocus ) {
                    			TeaLeaf.Event.tlAddHandler(control, 'focus',  TeaLeaf.Client.tlSetFocusTime, false);
				}				
				if( TeaLeaf.Client.Configuration.tlsendblur ) {
                        		TeaLeaf.Event.tlAddHandler(control, 'blur',   TeaLeaf.Client.tlHandleBlur, false);
				}
				TeaLeaf.Event.tlAddHandler(control, 'change', TeaLeaf.Client.tlAddEvent, false);

				// check if we need to block this node
				item_name = TeaLeaf.Client.tlGetName(control);

				if(item_name == null) break;
				lower_item_name = item_name.toLowerCase();
				map_item = TeaLeaf.Client.Configuration.tlFieldBlockMap[lower_item_name];

				if(map_item == null) break;
				if(map_item["tlfieldname"] == item_name ||
		   	  	   (map_item["caseinsensitive"] && map_item["tlfieldname"] == lower_item_name))
				{
					control.TeaLeafExclude = map_item["eventnovalue"];
					control.TeaLeafReplace = map_item["eventvaluereplace"].length > 0;
				}
				break;
		}

		if(TeaLeaf.Client.Configuration.tlUniversalAttach)	
		{
	 	    var handlers = TeaLeaf.Client.Configuration.tlDocumentHandlers;
		    for(var i=0; i<handlers.length; i++)
	  	    {
	    		    if(handlers[i]["load"])
				    TeaLeaf.Event.tlAddHandler(control, handlers[i]["domevent"], eval(handlers[i]["tlhandler"]), false);
		    }
		}
	}
	/**
    * Attach to INPUT and SELECT. 
    * @param win window object.
    * @addon
    */            	                                                                					
	TeaLeaf.Client.tlCheckIndControls = function(win) {
            try{
                if(win.document){  
                    var items = win.document.getElementsByTagName("INPUT");				    
                    for(var i = 0; i < items.length; i++) {			
                        TeaLeaf.Client.tlCheckAttach(items[i]);
                    }	
                    items = win.document.getElementsByTagName("SELECT");
                    for(var i = 0; i < items.length; i++) {
                        TeaLeaf.Client.tlCheckAttach(items[i]);
                    }
                    items = win.document.getElementsByTagName("BODY"); 
                    if(items.length>0){		
                        items = items[0].getElementsByTagName("*");		       
                        for(var i = 0; i < items.length; i++) {
                            TeaLeaf.Client.tlCheckAttach(items[i]);
                        }
                    }
                }
            }
            catch(e) { }
        }
      
    /**
    * Attach to the given DOM node and all descendants 
    * @param obj DOM object
    * @param ignore_descendants (Optional) boolean to ignore child nodes
    * @addon
    */  
    TeaLeaf.Client.tlProcessNode = function(obj, ignore_descendants) {
	if(typeof(obj) == "string") obj = document.getElementById(obj);
	if(obj == null) return;
        try{
		switch(obj.tagName)
		{
			case "INPUT":
			case "SELECT":
			case "TEXTAREA":
				TeaLeaf.Client.tlCheckAttach(obj);
				break;
			default:
        			if(TeaLeaf.Client.Configuration.tlUniversalAttach && TeaLeaf.Client.tlTagNameAllowed(obj.tagName))
					TeaLeaf.Client.tlCheckAttach(obj);
				break;
		}

		if(!ignore_descendants)
		{
			var explicit_tags = ["INPUT","SELECT","TEXTAREA"];
			for(var i=0; i<explicit_tags.length; i++)
			{
				items = obj.getElementsByTagName(explicit_tags[i]);
                    		for(var j=0; j<items.length; j++)
                        		TeaLeaf.Client.tlCheckAttach(items[j]);
			}

			if(TeaLeaf.Client.Configuration.tlUniversalAttach)
			{
				if(TeaLeaf.Client.Configuration.tlExcludeTags)
				{
           				items = obj.getElementsByTagName("*");
            				for(var i = 0; i < items.length; i++) {
            					if(TeaLeaf.Client.tlTagNameAllowed(items[i].tagName))
                  					TeaLeaf.Client.tlCheckAttach(items[i]);
            				}
				}
				else
				{
					for(var i in TeaLeaf.Client.Configuration.tlNodeTags)
					{
						items = obj.getElementsByTagName(i);
						for(var j=0; j<items.length; j++)
							TeaLeaf.Client.tlCheckAttach(items[j]);
					}
				}
			}
		}
        }
	catch(e) {}
    }
	/**
    * Handle focus event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                						
	TeaLeaf.Client.tlSetFocusTime = function(theEvent) {
		//	Check for a null
		if( ! theEvent ) {
			theEvent = window.event;
		}
		//	We need the item source.  Ignore flash
		var	itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
		if( ! itemSource || itemSource.type == "application/x-shockwave-flash" ) {
			return;
		}
		//	Get the target - If we have no way to identify then discard
		var	itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
		if( ! itemSource ) {
			return;
		}
		if( ! itemSource.TeaLeafFocusTime ) {
			itemSource.TeaLeafFocusTime = new Date();
		}
		//	If we are sending the focus event, then send it!
		if(TeaLeaf.Client.Configuration.tlsendfocus ) {
			TeaLeaf.Client.tlAddEvent(theEvent);
		}
	}	
	/**
    * Handle blur event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                						
	TeaLeaf.Client.tlHandleBlur = function(theEvent) {
		//	Check for a null
		if( ! theEvent ) {
			theEvent = window.event;
		}
		//	We need the item source.  Ignore flash
		var	itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
		if( ! itemSource || itemSource.type == "application/x-shockwave-flash" ) {
			return;
		}
		TeaLeaf.Client.tlEndVisit(itemSource);
		if(TeaLeaf.Client.checkIsInput(itemSource))
			TeaLeaf.Event.Configuration.tlidoflastvisitedcontrol = TeaLeaf.Client.tlGetName(itemSource);
		//	Send the event?
		if( TeaLeaf.Client.Configuration.tlsendblur ) {
			TeaLeaf.Client.tlAddEvent(theEvent);
		}
	}
	/**
    * Last element visited.
    * @param itemSource DOM element.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                						
	TeaLeaf.Client.tlEndVisit = function(itemSource) {
		if( itemSource.TeaLeafFocusTime ) {
			var name = TeaLeaf.Client.tlGetName(itemSource);
			if( ! name ) {
				name = TeaLeaf.Client.tlGetAnchor(itemSource, false);
				if( name ) {
					name = "LEVEL" + name;
				}
				else {
					name = "unnamed";
				}
			}
			var diff = TeaLeaf.Event.tlDateDiff(itemSource.TeaLeafFocusTime, new Date());
			var entry = name + ':' + diff;

			if( TeaLeaf.Event.Configuration.tlvisitorder != "")
				TeaLeaf.Event.Configuration.tlvisitorder = TeaLeaf.Event.Configuration.tlvisitorder + ";" + entry;
			else
				TeaLeaf.Event.Configuration.tlvisitorder = entry;
		}
	}
	/**
    * Detach from all controls including frames.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */            	                                                                						
	TeaLeaf.Client.tlDetachFromAllControls = function() {
		//	Mark as not attached
		TeaLeaf.Client.Configuration.tlcontrolsattached = false;

		//	Attach to this window
		TeaLeaf.Client.tlDetachFromControls(window);

		//	Do the frames
		try{
			var	ind;
			for(ind = 0; ind < window.frames.length; ind++) {
				var	w = window.frames[ind];
				TeaLeaf.Client.tlDetachFromControls(w);
			}
		}
		catch(e){}
	}
	/**
    * Detach listeners to controls based on the configuration. 
    * @param win window object.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */            	                                                                			
	TeaLeaf.Client.tlDetachFromControls = function(win) {
	try{
	    var handlers = TeaLeaf.Client.Configuration.tlWindowHandlers;
	    for(var i=0; i<handlers.length; i++) {
	        var func = eval(handlers[i].tlhandler);
	        TeaLeaf.Event.tlRemoveHandler(win, handlers[i].domevent, func, false);
	    }
	    handlers = TeaLeaf.Client.Configuration.tlDocumentHandlers;
	    for(var i=0; i<handlers.length; i++) {
	        var func = eval(handlers[i].tlhandler);
	        TeaLeaf.Event.tlRemoveHandler(win.document, handlers[i].domevent, func, false);
	    }

	    // Detach from Individual Items
	    var items = win.document.getElementsByTagName("INPUT");
	    var i;
	    for(i = 0; i < items.length; i++) {
	        TeaLeaf.Event.tlRemoveHandler(items[i], 'change', TeaLeaf.Client.tlAddEvent, false);
	        TeaLeaf.Event.tlRemoveHandler(items[i], 'focus',  TeaLeaf.Client.tlSetFocusTime, false);
            TeaLeaf.Event.tlRemoveHandler(items[i], 'blur',   TeaLeaf.Client.tlHandleBlur, false);
	        items[i].TeaLeaf = false;
	    }
	    items = win.document.getElementsByTagName("SELECT");
	    for(i = 0; i < items.length; i++) {
	        TeaLeaf.Event.tlRemoveHandler(items[i], 'change', TeaLeaf.Client.tlAddEvent, false);
	        TeaLeaf.Event.tlRemoveHandler(items[i], 'focus',  TeaLeaf.Client.tlSetFocusTime, false);
            TeaLeaf.Event.tlRemoveHandler(items[i], 'blur',   TeaLeaf.Client.tlHandleBlur, false);
	        items[i].TeaLeaf = false;
	    }
	} 
	catch(e) { }
  }
  /**
  * Attach a listener to a specific control. 
  * @param domelement DOM element.
  * @param eventtype TeaLeaf Event type.
  * @param eventHandler Event handler.
  * @requires 
  * TeaLeafEvent.js
  * @addon
  */            	                                                                			  
  TeaLeaf.Client.tlAttachToControl = function(domelement, eventtype, eventHandler) {
    if(eventHandler){
        TeaLeaf.Event.tlAddHandler(domelement, eventtype, eventHandler, false);
    }
    else{
        TeaLeaf.Event.tlAddHandler(domelement, eventtype, eval(TeaLeaf.Client.tlAddEvent), false);
    }
  }
  /**
  * Detach a listener to a specific control. 
  * @param domelement DOM element.
  * @param eventtype TeaLeaf Event type.
  * @param eventHandler Event handler.
  * @requires 
  * TeaLeafEvent.js
  * @addon
  */            	                                                                			  
  TeaLeaf.Client.tlDetachFromControl = function(domelement, eventtype, eventHandler) {
    if(eventHandler){
        TeaLeaf.Event.tlRemoveHandler(domelement, eventtype, eventHandler, false);
    }
    else{
        TeaLeaf.Event.tlRemoveHandler(domelement, eventtype, eval(TeaLeaf.Client.tlAddEvent), false);
    }
  }
  /**
  * Mark the blocked fields based on the configuration. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */       
  TeaLeaf.Client.tlMarkBlocked = function(items) { 
	//	Got through all the input fields and see which ones
	//	should be blocked.
	  TeaLeaf.Client.tlMakeFieldBlockMap();
	  if(items == null) items = document.getElementsByTagName("INPUT");

	  for(var i=0; i<items.length; i++)
	  {
		item_name = TeaLeaf.Client.tlGetName(items[i]);
		if(item_name == null) continue;
		lower_item_name = item_name.toLowerCase();
		map_item = TeaLeaf.Client.Configuration[lower_item_name];
		if(map_item == null) continue;
		if(map_item["tlfieldname"] == item_name ||
		   (map_item["caseinsensitive"] && map_item["tlfieldname"] == lower_item_name))
		{
			items[i].TeaLeafExclude = map_item["eventnovalue"];
			items[i].TeaLeafReplace = map_item["eventvaluereplace"].length > 0;
		}
	 }
  }  

  /**
  * Scan the DOM based on a timer set in the configuration and attach
  * to controls that might have been rendered due to a DOM update. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */            	                                                                			  
   TeaLeaf.Client.tlScanForAdditions = function() {
	   	if(!TeaLeaf.Client.Configuration.tlScheduledScan) return;

		//	Attach to the main window
		//TeaLeaf.Client.tlCheckIndControls(window);
		TeaLeaf.Client.tlProcessNode(document.body);
		//	attach to the frames
		try{
			for(var i=0; i<window.frames.length; i++) {
				var w = window.frames[i];
				TeaLeaf.Client.tlProcessNode(w.document.body);
				//TeaLeaf.Client.tlCheckIndControls(w);
			}			
		}
		catch(e){}	
		
		window.clearTimeout(TeaLeaf.Client.tlTimeoutID);	
		TeaLeaf.Client.tlTimeoutID = window.setTimeout(TeaLeaf.Client.tlScanForAdditions, TeaLeaf.Client.Configuration.tlscanupdate);		
	}

	TeaLeaf.Client.tlTagNameAllowed = function(tag) {
	    if(tag == null) 
	        return false;
	    var tagVal = TeaLeaf.Client.Configuration.tlNodeTags[tag];	    
	    if(tagVal == null) 
	        tagVal = false; 
	    if(TeaLeaf.Client.Configuration.tlExcludeTags) 
	        return !tagVal;
	    else 
	        return tagVal;
	}

	TeaLeaf.Client.tlMakeFieldBlockMap = function() {
	    if(TeaLeaf.Client.Configuration.tlFieldBlockMap != null) return;
		TeaLeaf.Client.Configuration.tlFieldBlockMap = {};

		var fields = TeaLeaf.Client.Configuration.tlFieldBlock;
		for(var i=0; i<fields.length; i++){
		    name = fields[i]["tlfieldname"];
			if(name == null) continue;
			else name = name.toLowerCase();
			if(fields[i]["caseinsensitive"]) fields[i]["tlfieldname"] = name;
			TeaLeaf.Client.Configuration.tlFieldBlockMap[name] = fields[i];
		}
	}

  /**
  * Start registering DOM listeners based on the config options. 
  * NOTE: This function is ment to be used in SDK mode. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */            	                                                                			  
   TeaLeaf.Client.tlStartListeners = function() {
   		//	Get the lists we want to get
		TeaLeaf.Client.tlAttachToAllControls();	
		TeaLeaf.Client.tlSingleAttach();
   }

  /**
  * Unregister DOM listeners based on the config options. 
  * NOTE: This function is ment to be used in SDK mode. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */            	                                                                			  
   TeaLeaf.Client.tlEndListeners = function() {
   		TeaLeaf.Event.tlFlushQueue(true);
        TeaLeaf.Client.tlDetachFromAllControls();
   }
	
  /**
  * Setup function that attaches to all the controls on the page. 
  * @addon
  */            	                                           
  TeaLeaf.Client.tlSetup = function() {
	  	// If a previous event queue was stored in the cookie, apply it to the current queue
		if(typeof TeaLeaf.Cookie != "undefined")
		{
			var queuedXML = TeaLeaf.Cookie.tlGetCookieValue("tlQueuedXML");
			if(queuedXML != null && queuedXML != "")
				TeaLeaf.Event.tlQueuedXML += queuedXML.replace(/%3B/g, ";");
		}

		//	Get the lists we want to get
		TeaLeaf.Client.tlAttachToAllControls();	
		TeaLeaf.Client.tlSingleAttach();
		
		//	Hook on to the window open
		window.OrigOpen = window.open;
		window.open = function(url,name,features,replace) {
			var numberArgs = arguments.length;
			var	status = "blocked";
			var subWin = window.OrigOpen(url, name, features, replace);
			try {
				if(!subWin.closed)
					status = "visible";
			}
			catch(exc) {
				if( TeaLeaf.Event.Configuration.tlshowexceptions ) {
					alert(exc.name + ": " + exc.message + "\r\n\r\nPos 8");
				}
			};
			var	tlevt = new TeaLeaf.Event("GUI", "WindowOpen");	
			var tlAddNameValueArray = ["Status", status, 
				                       "Url", escape(url),
				                       "Name", name, 
				                       "Features", features, 
				                       "Replace", replace];
			tlevt.tlAddData(tlAddNameValueArray);
			tlevt.tlSend(); 
			return subWin;
		};	
		
		//	At this point, lets scan periodically for added controls
		window.clearTimeout(TeaLeaf.Client.tlTimeoutID);
		
		if(TeaLeaf.Client.Configuration.tlscanupdate >0 ){
            TeaLeaf.Client.tlTimeoutID = window.setTimeout(TeaLeaf.Client.tlScanForAdditions, TeaLeaf.Client.Configuration.tlscanupdate);
        }
    }		
	/**
    * Initialize the call to tlSetup UI Client Event
    * Capture is not used as an SDK.
    * @requires
    * TeaLeafEvent.js
    * @addon
    */            	                                           
	TeaLeaf.Client.CallInit = function() {	
        TeaLeaf.Event.tlRemoveHandler(window, "beforeunload", eval(TeaLeaf.Client.tlBeforeUnload), false);
        TeaLeaf.Event.tlRemoveHandler(window, "unload", eval(TeaLeaf.Client.tlUnload), false);
    	TeaLeaf.addOnLoad(TeaLeaf.Client.tlSetup);
	}

    if(TeaLeaf.Client.Configuration.tlinit == false){
        TeaLeaf.Client.Configuration.tlinit = true;
	    TeaLeaf.Client.CallInit();		
	}
}