
// com/qv/lang/StackTrace.js



/*******************************************************************************
 * Public methods
 ******************************************************************************/

/**
 * Returns the stacktrace of the calling function.
 */
function getStackTrace()
{
	var sStackTrace = null;

	//var oCaller = getStackTrace.caller;            -> method that called this method: end point for stack trace
	//var oCallee = getStackTrace.arguments.callee;  -> this (getStackTrace) method

	var oCaller = getStackTrace.caller;
	if ( ! oCaller ) { return null; }   // should not be possible

	sStackTrace = getStackTraceImpl(oCaller);

	return sStackTrace;
}

function getFunctionName(f) 
{
	var sFunctionName = null;

	if ( ! f                    ) { return null; }
	if ( typeof f != "function" ) { alert("[StackTrace::getFunctionName] Exception, not a function: " + f); return null; }

	var sFunctionName = f.toString().match(/function (\w*)/)[1];

	if ((sFunctionName == null) || (sFunctionName.length==0)) { sFunctionName = "anonymous"; }

	return sFunctionName;
}


/*******************************************************************************
 * Private methods
 ******************************************************************************/

function getStackTraceImpl(oFunction)
{
	var s = null;

	if ( ! oFunction                    ) { return null; }
	if ( typeof oFunction != "function" ) { return null; }

	var oCaller = oFunction.caller;
	var oCallee = oFunction; // oFunction.arguments.callee;
	// oCallee was called by oCaller

	var sFunctionNameCallee = getFunctionName(oCallee);

	if ( s == null ) { s = ""; }
    s += "->";
    s += sFunctionNameCallee;
    s += "\n";

	if ( oCaller ) 
	{
		var sFunctionNameCaller = getFunctionName(oCaller);

		if ( oCaller.caller == oCaller ) {
			alert("end of chain");
		} else {
			s += getStackTraceImpl(oCaller);
		}
	}

	return s;
}
