/*
Please note:
This is an exact duplicate of asplib/standardlib/recurseObject.asp
with the opening/closing tags stripped out.  Please remember to keep
the ASP and JS versions in sync.

*/

/*
recurseObject(myObject)
Displays formatted properties of an object either server side or client side

Optional properties when passing argument with Object notation
o - object to debug
n - name of object for reference
i - ignore ..showdebuginfo.. - true will still run even if show debug info is not on (Server Side Only).
l - levels to recurse down - int|true - default 15 - true sets no limit
f - show functions - true|false|text - text will show actual function text
t - true/false - to output raw text with no HTML - useful when using Firebug or other HTTP Response tools that don't render HTML
c - color for referencing multiple objects - examples: "red" or "#f00" or "random".
inline - client side only.  Will document.write rather than write to the popup
w/h - client side only. Width and height of popup window
dbg - client side only - true will use JS Debugger (debug.js) window for output rather than the recurseObject popup
firebug/console - output to firebug's consolue (requires Firebug 0.4 or later)
buffer - server side only - surrounds output in JavaScript block comments as to not interfere with Content Buffer ouput
textarea - server side only - surrounds output in <textarea> tags and forces raw text output. This combination is useful for reading output in both a buffered window, and in Firebug's "Response" tab. 
r|nowrite - return results only, don't write anything to the screen (useful for displaying at a later time)
autohide - shows only name of object.  Mouseover to expand.  Click to lock open
clear - clear popup or debug window first
autohide/collapse - wraps output in a click to expand/collapse container.

Example usage (server side or client side):

recurseObject(myObject); // no optional properties, use defaults
recurseObject({o:myObject,n:"My Object",l:5}); // 5 levels down
recurseObject({o:myObject,n:"My Object",c:"green"}); // highlight in green
recurseObject({o:myObject,f:true,t:1}); // show functions and display raw text output
recurseObject({o:myObject,i:1,buffer:1}); // ignore showdebuginfo and output buffer safe content

Use client side by first including this somewhere in your document (note: replace ! with % below)

<script type="text/javascript">
<! recurseObjectClientSide(); !>
</script>

*/

function recurseObject(props) {

	if (typeof props != "object") {
		return;
	}
	if (!props.o) {
		var obj = props;
		props = {o:obj};
	}

	var serverSide = (typeof document == "undefined");

	var showDebugInfoOn = !serverSide ? true : (User.Session("Secure.Flags.ShowDebugInfo") == "on");
	var ignoreShowDebugInfo = props.i || false;
	var objName = props.n || props.name || "Object";
	var bColor = props.c || props.color || "black";
	if (bColor == "random") {
		var colors = ["red","blue","black","green","orange"];
		bColor = colors[(Math.round(Math.random()*(colors.length-1)))];
	}
	var displayText = props.d || props.display || props.text || props.t || false;
	var obj = props.o || props.object || null;
	var showFunctions = props.f || props.functions || false;
	var recurseLevel = props.l || props.level || 15;
	var width = props.w || 500;
	var height = props.h || 500;
	var element = props.element || null;
	var inline = props.inline || false;
	var useDbg = props.debug || props.dbg || false;
	var useFireBug = props.firebug || props.console || false;
		if (useFireBug) { displayText = true; }
	var clearWindow = props.clear || false;

	var returnOnly = props.r || props.nowrite || false;
	var autoHide = (props.autohide && !displayText) || false;

	var contentBuffer = props.buffer || false;
	var textarea = props.textarea || false;
		if (textarea) {
			displayText = true;
			if (textarea === true || (isNaN(textarea) && !/%/.test(textarea))) { textarea = "400px"; }
			if (!isNaN(textarea)) { textarea += "px"; }
		}


	var rand = "Random"+Math.round(Math.random()*100000);


	var outputVals = [];

	function show(obj) {
 		outputVals = [];
		if (typeof obj == "undefined") { outputVals = "recurseObject: Object not defined"; }
		else { recurse(obj); }
		return output();

	}

	function recurse(obj,level) {
		var l = level || 0;
	
		if (l == 0 && typeof obj == "string") {
			displayText = true;
			outputVals.push(obj)
		}
		for (var i in obj) {

			if (typeof obj[i] == "function" && !showFunctions) {
				continue;
			}
			outputVals.push((displayText ?  (indention(l)+i) : ("<blockquote "+((l == 0) ? "style='margin-left:0px;' " : "")  + ">" + "<b>" + i + "</b>")) + " (" + (typeof obj[i]).charAt(0) + (obj[i] && (typeof obj[i] == "object" && obj[i] instanceof Array) ? (":Array("+obj[i].length+")"):"") + "): " + ((typeof obj[i] == "function" && showFunctions != "text") ? "Function" : (!typeof obj[i] == "function" && obj[i] instanceof Object || obj[i] instanceof Array)?"":obj[i])+"\n");
			if (obj[i] && typeof obj[i] != "string" && (recurseLevel === true || l < recurseLevel)) {
				recurse(obj[i],(l+1));
			}
			outputVals.push(displayText ? "" : "</blockquote>");
		}
	}

	function output() {

		var outputTitle = objName + ((!serverSide) ? " (Client Side) " : " (Server Side)");
		var outputS = (displayText) ? ((outputTitle+"\n"+outputVals.join(""))) : ("<hr /><style>div.recurseObject { background:#fefefe; font-size:11px; text-align:left;} pre.recurseObject { white-space:normal; } div.recurseObject blockquote {margin:0px;margin-left:35px;border-bottom:1px solid #EEE;padding-left:5px;} div#recurseObject"+rand+" blockquote {border-left:1px solid "+bColor+";} </style><div id='recurseObject"+rand+"' class='recurseObject'>\n<div style='background:#fcfcfc; padding:2px; border:2px solid "+bColor+"'>"+objName+((!serverSide) ? " (Client Side) " : " (Server Side)")+"</div>\n<pre class='recurseObject'>"+outputVals.join("")+"</pre></div>");

		if (textarea) {
			outputS = "<br /><textarea class='recurseObject' style='width:99%;height:"+textarea+"'>\n" + outputS + "</textarea><br />\n";
		}

		if (autoHide) {
			outputS = "<div style=\"padding:4px; border:1px dashed "+bColor+";\"><div style=\"overflow:hidden; height:1.2em;\">\
			 <div style='cursor:pointer;margin-right:5px;' title='Click to Expand/Collapse' onclick=\"var ROOpen = this.getAttribute('open'); this.parentNode.style.height = ROOpen?'1.2em':'auto'; this.parentNode.style.overflow=ROOpen?'hidden':'auto'; this.parentNode.parentNode.style.borderStyle = ROOpen?'dashed':'solid'; this.setAttribute('open',ROOpen?'':'yes'); \" />\
				"+outputTitle+"</div>\
				"+outputS+"\
			</div></div>";
		}

		if (contentBuffer) {
			outputS = "/*\n"+outputS+"\n*/";
		}

		if (!returnOnly) {
			if (serverSide) { // Server side JScript
				Response.write(outputS);
			}
			else { // Client side JavaScript
				if (inline) {
					document.write("<hr />"+outputS);
				}
				else if (element) {
					try {
						
						if (typeof element == "string") element = document.getElementById(element);
						element.innerHTML += "<hr />"+outputS;
					}
					catch(e) {}
				}
				else if (useDbg) {
					try {
						if (clearWindow) {
							Debug.debugWindow._sdb.clear(null,null,{ pane: "console" })
						}
						dbg(outputS);
					}
					catch(e) {}
				}
				else if (useFireBug) {
					try {
						console.log(outputS);
					}
					catch(e) {}
				}
				else {

					if (!window.dWindow || window.dWindow.closed) { // +Math.round(Math.random()*1000)
						dWindow = window.open('','recurseObject','width='+width+',height='+height+',top=0,left=0,scrollbars=1,resizable=1');
					}
					if (clearWindow) {
						dWindow.document.close();
						dWindow.document.open()
					}
					dWindow.rand = rand;

					//	dWindow.document.write("<a style='position:absolute;top:0px;right:0px;background:#fff;border:1px solid black;font-size:12px;padding:3px;' href='javascript:void(0);' onclick='document.body.innerHTML = \"\";'>Clear Window</a>");
					dWindow.document.write("<hr />"+(new Date)+outputS);
					
					try {
						// scroll to object div
						var dTop = dWindow.document.getElementById("recurseObject"+rand).offsetTop;dWindow.window.scrollTo(0,1000000);
						dWindow.window.scrollTo(0,dTop-40);
					}
					catch(e) {
						dWindow.window.scrollTo(0,1000000)
					}
				}
			}
		}
		return outputS;
		outputVals = [];
		
	}

	function indention(level) {
		var indents = [];
		for (var i=0;i<level;i++) { indents.push("\t") }
		//for (var i=0;i<level;i++) { indents.push("    ") }
		return indents.join("");
	}


	if (serverSide && (ignoreShowDebugInfo || showDebugInfoOn)) { // Server side JScript
		return show(obj)
	}	
	else if (!serverSide && (ignoreShowDebugInfo || showDebugInfoOn)) { // Client side JavaScript
		return show(obj);
	}

	return "";

}

function recurseObjectClientSide() {

	var recurseObjectFunction = recurseObject.toString();

	if (User.Session("Secure.Flags.ShowDebugInfo") == "on") {
		recurseObjectFunction = recurseObjectFunction.replace("var showDebugInfoOn = false;","var showDebugInfoOn = true;");
		Response.write("\n"+recurseObjectFunction+"\n\n");
	}
	else {
		Response.write("\nfunction recurseObject() { \n\/\/please turn on debug or include client side version\n }\n\n");
	}

}
