/**
 * a simple *logger* to print trace on window's title bar
 *
 * usage:
 * 		Tracer.trace('blah') will update the title to 'blah'.
 *		Tracer.log('blah') will buffer the 'blah'.
 *		Tracer.show() will update the title with all buffered messages
 *		Tracer.clear() will reset the Tracer.
 *		Tracer.callstack() shows an alert box with the callstack
 */

/**
 * based on 
 * @author http://blog.pastie.org/
 */
(function () {

this.__getStackTracer__ = (function () {

var mode;
try {(0)()} catch (e) {
    mode = e.stack ? 'Firefox' : window.opera ? 'Opera' : 'Other';
}

switch (mode) {
    case 'Firefox' : return function () {
        try {(0)()} catch (e) {
            return e.stack.replace(/^.*?\n/,'').
                           replace(/(?:\n@:0)?\s+$/m,'').
                           replace(/^\(/gm,'{}(' ).
                           split("\n");
        }
    };

    case 'Opera' : return function () {
        try {(0)()} catch (e) {
            var lines = e.message.split("\n"),
                ANON = '{}',
                lineRE = /Line\s+(\d+).*?in\s+(http\S+)(?:.*?in\s+function\s+(\S+))?/i,
                i,j,len;

            for (i=4,j=0,len=lines.length; i<len; i+=2) {
                if (lineRE.test(lines[i])) {
                    lines[j++] = (RegExp.$3 ?
                        RegExp.$3 + '()@' + RegExp.$2 + RegExp.$1 :
                        ANON + RegExp.$2 + ':' + RegExp.$1) +
                        ' -- ' + lines[i+1].replace(/^\s+/,'');
                }
            }

            lines.splice(j,lines.length-j);
            return lines;
        }
    };

    default : return function () {
        var curr  = arguments.callee.caller,
            FUNC  = 'function', ANON = "{}",
            fnRE  = /function\s*([\w\-$]+)?\s*\(/i,
            stack = [],j=0,
            fn,args,i;

        while (curr) {
            fn    = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
            args  = stack.slice.call(curr.arguments);
            i     = args.length;

            while (i--) {
                switch (typeof args[i]) {
                    case 'string'  : args[i] = '"'+args[i].replace(/"/g,'\\"')+'"'; break;
                    case 'function': args[i] = FUNC; break;
                }
            }

            stack[j++] = fn + '(' + args.join() + ')';
            curr = curr.caller;
        }

        return stack;
    };
}

});

})();

var Tracer = {

	trace : function(msg, clearFirst) {
		if ( this.title == undefined && top.document ) {
			this.title = top.document.title;
		} 
		if ( clearFirst ) {
			this.clear();
		}
		this.msgs.push(msg);
		this.show();
	},

	log : function(msg) {
		this.msgs.push(msg);
	},

	show : function() {
		var title = ( this.title == undefined && top.document ) ? top.document.title : this.title; 
		top.document.title = title + ' ' + this.msgs.join(' -> ');
		if ( typeof(console) != 'undefined' &&
			typeof(console.log) == 'function' ) { 
			console.log(this.msgs.join(' -> '));
		} 
	},

	clear : function() {
		this.msgs = [];
		if ( this.title != undefined && top.document ) {
			top.document.title = this.title;
		}
	},

	callstack: function() {
		var tracer = __getStackTracer__();
		var frames = tracer();
		var traces = '';
		for(var i=1; i<frames.length; i++) {
			if ( i > 1 ) {
				traces += "\n";
			} 
			traces += '#' + i + '. ' + frames[i];
		}
		alert(traces);
	},

	msgs: [],
	title:	undefined	

}
