/*
================================================================================
 .............     ......                                                       
    ....   .....     ....                                                       
    ....    ....     ....                                                       
    ....     ....    ....                                                       
    ....     ....    ....                                                       
    ....     ....    ....                                                       
    ....    ....     ....      ......        ......... .....  .....     ...  .  
    ....   ....      ....    ..   ....     .... ....    ....   ....    ..  ...  
    ..........       ....   ...    ....   ....   ....   ....   ....   ...   ..  
    ....   .....     ....   ....   ....   ....   ....   ....   ....   ....   .  
    ....     ....    ....    ..    ....   ....   ....   ....   ....   ......    
    ....     .....   ....        ......   ....   ....   ....   ....    ......   
    ....     .....   ....      ..  ....   ....   ...    ....   ....      .....  
    ....     .....   ....    ...   ....    .... ...     ....   ....       ..... 
    ....     .....   ....   ....   ....     ......      ....   ....   .    .... 
    ....    .....    ....   ....  .....    .            ....  .....   ..    ... 
    ....   .....     ....   ...... .....  ..            ...........   ...   ..  
 .............     ........  ....   ...   ..........     ..... .....  .  ....   
                                          ............                          
                                            ...........                         
                                           ..        ..                         
                                           ..        ..                         
                                           ...      ..                          
                                             .......                            
================================================================================
D   e   b   u   g       T   r   a   c   i   n   g      L   i   b   r   a   r   y
================================================================================
version 1.53                             by Alexander Blagus <blagus@pop.com.br>
This  software is  available under the General Public License
GPL - The GNU General Public License         http://www.gnu.org/licenses/gpl.txt 

*/
// Library settings (you may change this values)
// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
// activate the debug output window.
// 0: debug disabled
// 1: only highlighted messages
// 2: all messages
var debugMode = 0;

// persist the last used color
var persistColor = false;

// set CSS path&file
var traceCSSFile = "trace.css";

// allow trace to be allways on top
var allwaysOnTop = true;

// Trace server-side tags
var ssTagName          = "trace";
var ssAttributeColor   = "color";
var ssAttributeMessage = "message";

// Automatic allow trace to this domains
var traceThisDomains = [
	"rdd.tools",
	"rdd.mouses",
	"rdd.apache"
];

// Automatic allow trace when querystring is enabled
if ( traceGetQueryVariable("debugMode") != "" ) {
	debugMode = traceGetQueryVariable("debugMode")
}

// Global variables (do not change this ones)
// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
// Last used color
var lastUsedColor = "";

// Automatic allow trace to this domains
for (loopDomains=0; loopDomains<traceThisDomains.length; loopDomains++){
	if( traceThisDomains[loopDomains] == location.hostname ){
		debugMode = 2;
	}
}


// =============================================================================
function trace(outputText, highLight, identSize){
	// Purpose       Debug application.
	// Assumptions   None
	// Effects       Create the canvasTraceMessages (if it does not exist) and add text on it.
	// Inputs        outputText: Text to display. HTML allowed.
	//               highLight:  Color to highlight an important text, e.g. "#f00"
	//                           Sugestions for colors:
	//                           client-side aplication-specific libs:           #309
	//                           client-side default libs (like httprequest.js): #69f
	//                           server-side aplication-specific libs:           #f00
	//                           server-side default libs (like common.asp):     #f93
	// Return        undefined.

	// check if the debug is on
	if ( debugMode ) {
		// create fly-out
		if ( !document.getElementById("canvasTrace") ) {
			traceInit(); 
		}

		// show debug text
		if ( ( debugMode == 1 && highLight ) || ( debugMode == 2 ) ) {
			// always on top
			if ( allwaysOnTop ) { setTimeout("traceBringToFront();", 100); }

			// fix text
			if ( outputText )	{
				outputText = outputText.toString(); 
			} else {
				outputText = ""; 
			}
			
			// set output variable
			var outputHTML = "";

			// consumption
			outputHTML += "<span class=\"consumption\">" + traceGetConsumptionTime() + "</span>&nbsp;";

			// highlight
			if ( highLight ) { outputHTML += "<span style=\"color:" + highLight + ";font-weight:bold;\">"; lastUsedColor = highLight; }
				if ( !highLight && lastUsedColor != "" && persistColor ) { outputHTML += "<span style=\"color:" + lastUsedColor + ";\">" }
					if ( identSize ) {  outputHTML += "<span style=\"margin-left:" + (arguments[2]*10) + "px;\">";}
						outputHTML += outputText.replace("<!>", "&lt;!&gt;");
					if ( identSize ) {  outputHTML += "</span>";}
				if ( !highLight && lastUsedColor != "" && persistColor ) { outputHTML += "</span>" }
			if ( highLight ) { outputHTML += "</span>" }
			outputHTML += "<br />" + "\n";

			// render in page
			document.getElementById("canvasTraceMessages").innerHTML += outputHTML;
			// traceDump(outputHTML);
			// Use Firebug
			// console.info(outputText);
		}
	}
	// exit function
	return undefined;
}

// =============================================================================
function traceExpandCollapse(objToChange, visibilityState)
{
 // Purpose      Expand or collapse a given object.
 // Assumptions	 None.
 // Effects      Change the style display of the given element.
 // Inputs 	     objToChange:     a valid object that suport display:none.
 //                               It may be a div, wich is the more usual.
 //              visibilityState: Boolean value. For visible or not.
 //                               May be "invert" (or only "i") wich will invert 
 //                               the current visibility. If not provided, 
 //                               "invert" will be the default value.
 // Return       True or false, acording the new state.

 // if visibilityState is not provided, the invert will be default
 if (visibilityState == undefined ){ visibilityState = "i" };
 
 if ( visibilityState.toString().charAt(0).toLowerCase() == "i" )
    {
     // invert element state
     if ( 
         objToChange.style.display == "none" ||
         objToChange.style.visibility == "hidden"
        )
        {
         objToChange.style.display = ""; 
         objToChange.style.visibility = "visible";
        }
     else
        { 
         objToChange.style.display = "none"; 
         objToChange.style.visibility = "hidden";
        }   
    }
 else
   {
    if (visibilityState)
       {
        // show, expand the element
        objToChange.style.display = ""; 
        objToChange.style.visibility = "visible";
       }
    else
       {
        // hide, colapse the element
        objToChange.style.display = "none";
        objToChange.style.visibility = "hidden";
       }
   }
 return undefined;
}

// =============================================================================
function traceGetConsumptionTime(){
	// set current date & time
	rightNow = new Date();

	// get data
	var returnDateTime = "";
	returnDateTime += traceFillChars("0", 1-rightNow.getHours().toString().length)        + rightNow.getHours()        + ":";
	returnDateTime += traceFillChars("0", 1-rightNow.getMinutes().toString().length)      + rightNow.getMinutes()      + ":";
	returnDateTime += traceFillChars("0", 1-rightNow.getSeconds().toString().length)      + rightNow.getSeconds()      + "'";
	returnDateTime += traceFillChars("0", 2-rightNow.getMilliseconds().toString().length) + rightNow.getMilliseconds() + "\"";
	
	// return string
	return returnDateTime;
}
// =============================================================================
function traceReturnArguments(func)
{
 var returnStr = "";
 for (loop=0; loop<func.arguments.length; loop++)
     {
      returnStr += "\"" + func.arguments[loop] + "\"";
      if (loop < func.arguments.length-1)
         { returnStr += ", "; }
     }
 return returnStr;
}
// =============================================================================
function traceFillChars(charToFill, quantity)
{
 var returnStr = "";
 for (loop=0;loop<=quantity;loop++)
     {
      returnStr += charToFill;
     }
 return returnStr;
}

// =============================================================================
function traceClear(){
	document.getElementById("canvasTraceMessages").innerHTML = "";
}

// =============================================================================
function traceMinimize(){
	traceExpandCollapse(document.getElementById("canvasTraceCollapsible"));
	traceExpandCollapse(document.getElementById("buttonRestore"));
	traceExpandCollapse(document.getElementById("buttonMinimize"));
}

// =============================================================================
function traceRestore(){
	traceExpandCollapse(document.getElementById("canvasTraceCollapsible"));
	traceExpandCollapse(document.getElementById("buttonRestore"));
	traceExpandCollapse(document.getElementById("buttonMinimize"));
}

// =============================================================================
function traceClose(){
	debugMode = 0;
	document.body.removeChild(document.getElementById("canvasTrace"));

}

// =============================================================================
function traceJSExec(){
	eval(document.getElementById("inputTraceJSCode").value);
}

// =============================================================================
function traceJSClear(){
	document.getElementById("inputTraceJSCode").value = "";
}

// =============================================================================
function traceLastZIndex() {
	/*
	Purpose: Return the last (or maximum) used zIndex in this page. Usefull to 
	         create new layers or move the existent ones to the top
	Inputs:  none;
	Return:  number, last zIndex.
	*/
	// create output variable
	var lastZI = 0;
	// set all nodes (I wish document.all would be a W3C standard)
	var allElements = document.getElementsByTagName("*");
	// loop among all objects
	for ( loopAll=0; loopAll<allElements.length; loopAll++ ) {
		// if ( allElements[loopAll].style.zIndex != "" ) { trace("allElements[" + loopAll + "].style.zIndex: " + allElements[loopAll].style.zIndex + " (" + typeof(allElements[loopAll].style.zIndex) + ")"); }
		// analise current element z-index
		if ( parseInt(allElements[loopAll].style.zIndex) > parseInt(lastZI) ) {
			// set last z-index
			lastZI = parseInt(allElements[loopAll].style.zIndex);
		}
	}
	// return last z-index
	return lastZI;
}

// =============================================================================
function traceGetQueryVariable(variable) {
	// function made by Pete Freitag (pete@cfdev.com)
	// edited by Alexander Blagus (blagus@santander.com.br / blagus@pop.com.br)
	// this function gets the URL variables, for example http://desenv/test.htm?var=hello
	// the input variable called "variable" is the parsed variable in URL
	// this function returns the variable value

	var query = window.location.search.substring(1);
	var vars = query.split("&");
	for (var i=0;i<vars.length;i++) {
		var pair = vars[i].split("=");
		if ( pair[0] == variable) { return pair[1]; }
	} 
	// if the variable doesn't exist
	return "";
}

// =============================================================================
function traceBringToFront(){
	/*
	Purpose: Bring a flyout to front.
	Inputs:  objectToBring: string id|object, object to set zIndex;
	Return:  undefined.
	*/
	
	if (document.getElementById("canvasTrace")){
		objectToBring = document.getElementById("canvasTrace");

		if (objectToBring.style.zIndex == "") {
			var objZIndex = 1;
		} else {
			var objZIndex = parseInt(objectToBring.style.zIndex);
		}
		
		if (objZIndex < traceLastZIndex()) {
			objectToBring.style.zIndex = traceLastZIndex()+1;
		}
	}
	// exit function
	return false;
}

// =============================================================================
function traceProcessServerSideTags(){
	/*
	Purpose: Process the server-side tags.
	Inputs:  none;
	Return:  undefined.
	*/
	
	// get server-side tags
	var serverSideTags = document.getElementsByTagName(ssTagName);
	// insert all texto into a variable to better performance (javascript may freeze the browser if many innerHTML calls is made at once)
	var outputTrace = "<br />";

	// loop among all objects
	for ( loopSST=0; loopSST<serverSideTags.length; loopSST++ ) {
		
		// get highlighted text
		if ( serverSideTags[loopSST].getAttribute(ssAttributeColor) ) { 
			outputTrace += "<span style=\"color:" + serverSideTags[loopSST].getAttribute(ssAttributeColor) + ";font-weight:bold;\">";
		}
		// get message
		outputTrace += serverSideTags[loopSST].getAttribute(ssAttributeMessage);
		
		// end highlighted text
		if ( serverSideTags[loopSST].getAttribute(ssAttributeColor) ) {
			outputTrace += "</span>" 
		}
		// get highlighted text
		outputTrace += "<br />" + "\n";
	}
	// throw message
	var debugModeOriginal = debugMode;
	debugMode = 2;
	trace(outputTrace);
	debugMode = debugModeOriginal;
	
	if ( serverSideTags.length == 0){
		trace("<span style=\"color:#808080\">There are no server-side tags to process (tag: &lt;" + ssTagName + " ... &gt;)</span>");
	}
	// exit function
	return undefined;
}

// =============================================================================
function traceInit(){
	// attach CSS
	nodeDebugCSS = document.body.appendChild(document.createElement("link"));
	nodeDebugCSS.rel = "Stylesheet";
	nodeDebugCSS.type="text/css";
	nodeDebugCSS.id="traceCSS";
	nodeDebugCSS.href = traceCSSFile + "?rnd=" + Math.floor(Math.random() * 0xFFFFFF).toString(16);
	// insert canvas
	nodecanvasTraceMessages = document.body.appendChild(document.createElement("div"));
	nodecanvasTraceMessages.id="canvasTrace";
	nodecanvasTraceMessages.onclick=function(){ setTimeout("traceBringToFront();", 100); }
	var traceHTML = "";
	// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
	traceHTML += "		<div id=\"canvasTraceHeader\">		";
	traceHTML += "			<div id=\"canvasTraceTitle\">		";
	traceHTML += "				<span id=\"title\">Trace lib</span>&nbsp;		";
	traceHTML += "				<span id=\"author\">by Alexander Blagus</span>		";
	traceHTML += "			</div> 		";
	traceHTML += "			<div id=\"canvasTraceWindowControls\">		";
	traceHTML += "				<a href=\"javascript:traceClear();\" title=\"Clear console messages\">clear</a>		";
	traceHTML += "				|		";
	traceHTML += "				<a href=\"javascript:void(debugMode=0);\" title=\"Disable debuging\">disabled</a>		";
	traceHTML += "				|		";
	traceHTML += "				<a href=\"javascript:void(debugMode=1);\" title=\"Show highlighted messages only\">simple</a>		";
	traceHTML += "				|		";
	traceHTML += "				<a href=\"javascript:void(debugMode=2);\" title=\"Display all messages\">detailed</a>		";
	traceHTML += "				|		";
	traceHTML += "				<a href=\"javascript:traceProcessServerSideTags();\" title=\"Process server-side tags\">server-side</a>		";
	traceHTML += "				<span id=\"buttonMinimize\">		";
	traceHTML += "					|		";
	traceHTML += "					<a href=\"javascript:traceMinimize();\" title=\"Minimize this fly-out\">minimize</a>		";
	traceHTML += "				</span>";
	traceHTML += "				<span id=\"buttonRestore\" style=\"display:none\">		";
	traceHTML += "					|		";
	traceHTML += "					<a href=\"javascript:traceRestore();\" title=\"Restore this fly-out\">restore</a>		";
	traceHTML += "				</span>";
	traceHTML += "				|		";
	traceHTML += "				<a href=\"javascript:traceClose();\" title=\"Close this fly-out\">close</a>		";
	traceHTML += "			</div> 		";
	traceHTML += "		</div>		";
	traceHTML += "		<div id=\"canvasTraceCollapsible\">"
	traceHTML += "			<div style=\"float: none;\" id=\"canvasTraceMessages\"></div>		";
	traceHTML += "			<div id=\"canvasTraceJS\">		";
	traceHTML += "				<input		";
	traceHTML += "					 type=\"text\"		";
	traceHTML += "					 name=\"inputTraceJSCode\"		";
	traceHTML += "					 id=\"inputTraceJSCode\"		";
	traceHTML += "					 onkeyup=\"javascript:		";
	traceHTML += "						if (event.keyCode==13) {		";
	traceHTML += "							traceJSExec();		";
	traceHTML += "						} else if (event.keyCode==27) {		";
	traceHTML += "							traceJSClear();		";
	traceHTML += "						}		";
	traceHTML += "					\"		";
	traceHTML += "				 />		";
	traceHTML += "				&nbsp;		";
	traceHTML += "				<input		";
	traceHTML += "					 type=\"button\"		";
	traceHTML += "					 name=\"buttonTraceJSCode\"		";
	traceHTML += "					 id=\"buttonTraceJSCode\"		";
	traceHTML += "					 value=\"run\"		";
	traceHTML += "					 onclick=\"javascript:traceJSExec();\"		";
	traceHTML += "				 />		";
	traceHTML += "						";
	traceHTML += "						";
	traceHTML += "			</div>		";
	traceHTML += "		</div> 		";
	traceHTML += "				";
	traceHTML += "				";
	// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
	nodecanvasTraceMessages.innerHTML = traceHTML;
}

// =============================================================================
function getInfo(inData){
	/*
	Purpose: retrieve information about any element, function or object.
	Inputs:  inData: the element, function or object;
	Return:  string, the contents of the object in HTML form.
	*/
	// trace("Function getInfo(" + inData + ")", "red", loopDepth);
	// trace("typeof(inData): " + typeof(inData), undefined, loopDepth);
	loopDepth++;
	// trace("loopDepth: " + loopDepth, undefined, loopDepth);

	var stringOutput = "";
	var openTag = "<span style=\"color:#808080;font-weight:normal;\">";
	var closeTag = "</span>";
	var fillChars = function(charToFill, quantity){
		var returnStr = "";
		for (loop=0;loop<=quantity;loop++){
			returnStr += charToFill;
		}
		return returnStr;
	}


	if ( typeof(inData) == "string" ){
		// Type string
		// trace("Type string", undefined, loopDepth);
		stringOutput = openTag + "string:" + closeTag + inData;
	} else if (typeof(inData) == "number") {
		// Type number
		// trace("Type number", undefined, loopDepth);
		stringOutput = openTag + "number:" + closeTag + inData;
	} else if (typeof(inData) == "boolean") {
		// Type boolean
		// trace("Type boolean", undefined, loopDepth);
		stringOutput = openTag + "boolean:" + closeTag + inData;
	} else if (typeof(inData) == "undefined") {
		// Type undefined
		// trace("Type undefined", undefined, loopDepth);
		stringOutput = "undefined";
	} else if (typeof(inData) == "function") {
		// Type function
		// trace("Type function", undefined, loopDepth);
		stringOutput = openTag + "function:" + closeTag + inData;
	} else if (typeof(inData) == "object") {
		// Type object
		// trace("Type object", undefined, loopDepth);
		// make replacements to get the constructor
		var inDataConstructor = "";
		if (!inData == null) {
			var inDataConstructor = inData.constructor.toString().replace(/ +/gi, " ").replace(/\n/gi, "").replace(/\f/gi, "")
			// trace("inData.valueOf(): " + inData.valueOf(), undefined, loopDepth);
		}
		// trace("inDataConstructor: " + inDataConstructor);

		if (inData == null){
			// Subtype null
			// trace("Subtype null", undefined, loopDepth);
			stringOutput = "null";
		
		} else if (inData.nodeType != undefined) {
			// Subtype HTML element
			// trace("Subtype HTML element", undefined, loopDepth);
			stringOutput = "objectDOM";
			if (inData.nodeType ==  1 ) {stringOutput = "objectDOMelement"               ;}
			if (inData.nodeType ==  2 ) {stringOutput = "objectDOMattribute"             ;}
			if (inData.nodeType ==  3 ) {stringOutput = "objectDOMtext"                  ;}
			if (inData.nodeType ==  4 ) {stringOutput = "objectDOMcdata_section"         ;}
			if (inData.nodeType ==  5 ) {stringOutput = "objectDOMentity_reference"      ;}
			if (inData.nodeType ==  6 ) {stringOutput = "objectDOMentity"                ;}
			if (inData.nodeType ==  7 ) {stringOutput = "objectDOMprocessing_instruction";}
			if (inData.nodeType ==  8 ) {stringOutput = "objectDOMcomment"               ;}
			if (inData.nodeType ==  9 ) {stringOutput = "objectDOMdocument"              ;}
			if (inData.nodeType == 10 ) {stringOutput = "objectDOMdocument_type"         ;}
			if (inData.nodeType == 11 ) {stringOutput = "objectDOMdocument_fragment"     ;}
			if (inData.nodeType == 12 ) {stringOutput = "objectDOMnotation"              ;}
		
		} else if (inData.length != undefined) {
			// Subtype array
			// trace("Subtype array", undefined, loopDepth);
			// trace("inData.length (depth " + loopDepth + "): " + inData.length, undefined, loopDepth);
			stringOutput = openTag + "array:" + closeTag + "[";
			// loopItens must be declared because for makes the variable public
			var loopItens=0;
			// loop among array itens
			for(loopItens=0;loopItens<inData.length;loopItens++){
				// trace("loopItens (depth " + loopDepth + "): <b>" + loopItens + "</b>", undefined, loopDepth);
				// trace("inData[loopItens]: " + inData[loopItens], undefined, loopDepth);
				// use this function in recursive mode to retrieve array data
				stringOutput += getInfo(inData[loopItens]);
				// add comma separator between elements
				if( loopItens+1 < inData.length ){
					stringOutput += ", ";
				}
			}
			stringOutput += "]";
		
		} else if (inDataConstructor == "function Date() { [native code]}") {
			// Subtype date
			// trace("Subtype date", undefined, loopDepth);
			// format output
			var formatedDate = "";
			formatedDate += fillChars("0", 1-inData.getDate().toString().length)         + inData.getDate()         + "/";
			formatedDate += fillChars("0", 1-(inData.getMonth()+1).toString().length)    + (inData.getMonth()+1)    + "/";
			formatedDate +=                                                                     inData.getFullYear()     + " ";
			formatedDate += fillChars("0", 1-inData.getHours().toString().length)        + inData.getHours()        + ":";
			formatedDate += fillChars("0", 1-inData.getMinutes().toString().length)      + inData.getMinutes()      + ":";
			formatedDate += fillChars("0", 1-inData.getSeconds().toString().length)      + inData.getSeconds()      + "'";
			formatedDate += fillChars("0", 2-inData.getMilliseconds().toString().length) + inData.getMilliseconds() + "\"";
			stringOutput = openTag + "date:" + closeTag + formatedDate;
		
		} else if (inDataConstructor == "function Object() { [native code]}") {
			// Subtype native code
			// trace("Subtype native code", undefined, loopDepth);
			// trace("inData.toSource(): " + inData.toSource(), undefined, loopDepth);

			if (inData.toString() == "[object Object]") {
				// User-defined object
				// trace("Sub-subtype user-defined object", undefined, loopDepth);
				stringOutput = openTag + "userObject:" + closeTag + inData.toSource();
			
			} else {
				// Built-in Javascript function
				// trace("Sub-subtype native function", undefined, loopDepth);
				stringOutput = openTag + "object:" + closeTag + "nativeCode";
			}
		
		} else {
			// Subtype unknown
			// trace("Subtype unknown", undefined, loopDepth);
			stringOutput = "unknown object";
		}
	
	} else {
		// trace("Type unknown", undefined, loopDepth);
		stringOutput = "unknown";
	}

	// exit function
	loopDepth--;
	return stringOutput;
}
var loopDepth = -1;

// =============================================================================
