/*********************************************************
 * WHO:			Michael Philippone
 * 
 * WHAT:		collection of functions and algorithms 
 * 				helping the jsDump file's functions
 * 
 * WHEN:		28 July - 03 Aug 2009
 * 
 * VERSION:		1.1
 * 
 * COPYRIGHT:	2009 Corporate Zen
 * 
 * HOW:		
 * 		PROPERTIES / GLOBALS:
 * 			--> For each dump(..) call:
 *	 			->	window['dumpElement_<UNIQUE_ID>'] 
 *					::	overarching javascript object element being inspected
 *				->	window['opts_<UNIQUE_ID>'] 
 *					::	collection of options passed from initial call (top of the function call stack)
 * 
 * 		FUNCTIONS:
 * 			-->	isArray - test array nature of argument
 * 			-->	isObject - test object nature of argument
 * 			-->	scrubHTML - remove HTML code and format for output
 * 			--> makeButton - put a button on the page to trigger output display
 * 			--> UID - update and return unique number
 * 			-->	minidump - for debuggin, a barebones object dumping function
 * 			-->	getKeys - return a sorted list of object property keys
 * 
 * CHANGELOG:	
 * 	-->	03 Aug 2009 (michael@corporatezen.com)
 * 		-> file created
 * 
 *********************************************************/



/* ********************************************************************************************* */
/*
 * function to obtain keys for an object, returns them as a SORTED array if desired
 */
function getKeys( obj , sort ) {
	var arr = [];
	var ix = 0;
	
	sort = Boolean(sort);
	
	for(var key in obj) {
		arr[ix] = key;
		ix++;
	}
	
	if (sort) {
		//var sortFunc = function(a,b){ };
		//arr.sort(sortFunc);
		arr.sort();
	}
	return arr;
}
/* ********************************************************************************************* */
/*
 * X-Browser isArray(), including Safari
 */
function isArray(obj) { 
	try {
		if(obj && obj.toString().match(/[aA][rR]{2}[aA][yY]/))
			return true;			
		else if(obj && obj.constructor)
			return Boolean(
					!(obj.constructor.toString().match(/[sS][tT][rR][iI][nN][gG]/)) &&
					( 
						( obj.constructor.toString().match(/[aA][rR]{2}[aA][yY]/) ) || 
						( obj.constructor == Array ) 
					) 
					);
		else return false;
	} 
	catch(err) {
		alert("There was an error in determining the array nature of the obj.");
		return false;
	}
}

/* ********************************************************************************************* */
/*
 * X-Browser isArray(), including Safari
 */
function isObject(obj) {
	try {
		if( obj && obj.toString().match(/[oO][bB][jJ][eE][cC][tT]/) )
			return true;
		else if(obj && obj.constructor)
			return Boolean(
					!(obj.constructor.toString().match(/[sS][tT][rR][iI][nN][gG]/)) &&
					( 
						( obj.constructor.toString().match(/[oO][bB][jJ][eE][cC][tT]/) ) || 
						( obj.constructor == Object ) 
					)
					);
		else return false;
	} 
	catch(err) {
		alert("There was an error in determining the object nature of the obj.");
		return false;
	}
}

/* ********************************************************************************************* */
/*
 * remove all <'s and >'s and replace all & with '&amp;' in the given string argument
 * Also, HTML format the whitespace in the sourcecode
 */
function scrubHTML(txt) {
	var newTxt = txt;
	if (Boolean(txt) && txt != "" && txt != " ") 
	{
		newTxt = newTxt.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
		newTxt = newTxt.replace(/[\n\r]+/g, "<br/>");
		newTxt = newTxt.replace(/\t/g, "&nbsp;&nbsp;&nbsp;");
		newTxt = newTxt.replace(/\ /g, "&nbsp;");
	}
	return newTxt;
}

/* ********************************************************************************************* */
/*
 * Create a global, unique identifier counter
 */
function UID() {
	try {
		if(!Boolean(window.uid)) window.uid = 0;
		return window.uid++;
	}
	catch(error) {
		alert("There was an error generating a unique identifier. \nUsing milliseconds since the Epoch instead.  \n(UID function)");
		return new Date().getTime(); 
	}
}

/* ********************************************************************************************* */

/*
 * Given an element (not the ID, the actual object)
 * dump out its contents (verbosely!)
 * into a div that gets tacked onto the BODY tag
 * This is a MINI version of the dump function above, 
 * 	it uses much more limited functionalities (NO RECURSION)
 * 	and exists primarily for debugging the robust one
 */
function minidump(element) 
{	
	try {
		var txt = "";
		var ret = document.createElement('div');
		ret.innerHTML = "";
		ret.style.display = 'block';
		ret.style.border = '3px solid red';
		ret.style.padding = '10px 10px 10px 10px';
		ret.style.backgroundColor = "#CCCCCC";
		
		if (isArray(element)) 
			for (var i = 0; i < element.length; i++) 
				txt += "ELEMENT[" + i + "] = " + element[i] + "<br/>";
		else if (isObject(element)) 
			for (var X in element) 
				txt += "ELEMENT[" + X + "] = " + element[X] + "<br/>";
		else {
			txt += "ELEMENT = " + element /*.replace(/</g , "&lt;").replace(/>/g , "&gt;").replace(/[\n]/g , "<br/>")*/ + "<br/>";
		}
	}
	catch(err1) {
		alert(
			"there was an error setting up the local variables. \n" +
			"txt = " + txt + "\n" +
			"Boolean(element) = " + Boolean(element) + "\n" +
			"Boolean(ret) = " + Boolean(ret) + "\n" + 
			"\n(minidump function)"
		);
	}
	
	try {
		ret.innerHTML += txt;
		
		var closure = function() {
			document.getElementsByTagName("body")[0].insertBefore( 
				ret , 
				document.getElementsByTagName("body")[0].firstChild 
			);
		};
		setTimeout( closure , 1500 );
		return;
		
		if( document )
			if( document.getElementsByTagName )
				if( document.getElementsByTagName("body") )
					if( document.getElementsByTagName("body")[0] )
						if (document.getElementsByTagName("body")[0].insertBefore) {
							document.getElementsByTagName("body")[0].insertBefore( 
								ret , 
								document.getElementsByTagName("body")[0].firstChild 
							);			
						}
						else 
							alert("document.getElementsByTagName('body')[0].insertBefore is not specified");
					else
						alert('document.getElementsByTagName("body")[0] is not specified');
				else
					alert('document.getElementsByTagName("body") is not specified');
			else
				alert('document.getElementsByTagName is not specified');
		else
			alert('document is not specified');
	}
	catch(err2)	{
		alert("There was an error adding the text to, and appending the element to the page body. \n(minidump function)");
	}
}

/* ********************************************************************************************* */

/*
 * Build a button that will call the dump print-out
 */
function makeButton(eName , fxn) {
	try {		
		var txt = "";
		
		fxn = fxn.toString().replace(/^[\s]+/g , "").replace(/[\s]+$/g , "");
		
		if(!Boolean( fxn.match(/();$/) ) ) fxn += "();";
		
		txt += "<br/><div style='border:2px solid #FF0000; padding:10px; margin:10px; text-align:center; '>";
		txt += 
			"<input " + 
				"type='button' " + 
				"value=' Dump " + eName.replace(/'/g , '"') + " ' " + 
				"onclick='javascript:" +fxn+ "' " + 
				"/>"
		txt += "</div><br/>";
		
		document.writeln(txt);
	}  
	catch(err) {
		alert("There was an error making the dump function button. \n[makeButton( eName = '"+eName+"' , fxn = '"+fxn+"') function]");
	}
}