/*================================================================
  Trace Plugin
  version: 0.1
  for: jquery 1.2.6
  Justin Walduck, March 2009
  
  Creates a trace panel in the browser and displays passed messages.
  Individual messages can then be removed from the panel.
  
  Use:
  $.trace.disable();
  - Turn off tracing and remove trace objects from stage;
  
  $.trace.enable([options]);
  - Turn on tracing and add trace objects to stage;
  
  $.trace(message:String|Number|Array|Object, [clearTrace:Boolean], [options]); 
  - If trace is enabled: 
    -- Will add trace objects to stage if not already there;
	-- Appends message to trace output;
	-- If message is an array or object it will be srtingified.
	-- If clearTrace = true, the trace screen will be cleared before adding message.
  Note: options only applied if trace objects are created by the call.
	
  options (& defaults):
  id ('trace'): prefix for ids of trace objects
  background ('#FFFF99'): Background color of all trace elements 
  border ('1px solid #FFCC00'): Border style of all trace elements
  width (500): Width of open trace pane in pixels
  height (400): Height of open trace pane in pixels
  useConsoleIfAvailable (true): If the firebug console can be found output with be dumped to it
  
  For safest use you should check for the existance of the trace plugin before using it;
  if ($.trace) $.trace('Trace found');
  
================================================================*/

(function($) {

	$.trace = function(objToTrace, clearTrace, options) {
		if (data.enabled) {
			var opts = $.extend({}, $.trace.defaults, options);
			var traceStr = '';
			
			if (getType(objToTrace) != 'String' && getType(objToTrace) != 'Number') {
				traceStr = makeString(objToTrace);
			} else {
				traceStr = objToTrace;
			}
			
			if (opts.useConsoleIfAvailable && window.console && window.console.log) {
				window.console.log(traceStr);
			} else {
				if(!data.initiated) { $.trace.enable(options); };
				var display = $(data.display);
				if (clearTrace) { data.stack = []; };
				data.stack.push(traceStr);
				if(display) {
					display.html('');
					for (var i=0; i<data.stack.length; i++) {
						$('<div></div>').css({"border-bottom":opts.border, "padding":"8px 0"})
						.append(
							$('<pre>' + data.stack[i] + '</pre>')
							.css({"padding":"0", "margin":"0"})
						)
						.prepend(
							$('<div>X</div>')
							.css({	'padding':'0', 
								 	'margin':'0', 
									'width':'8px',
									'height':'8px',
									'text-align':'center',
									'font-size':'8px',
									'line-height':'8px', 
									'border':opts.border, 
									'cursor':'pointer', 
									'float':'right'})
							.bind('click', {stack:data.stack, i:i}, function(e){ $(this).parent().hide(); e.data.stack.splice(e.data.i, 1); })
						)
						.appendTo(display);
					}
					var scrollHeight = document.getElementById(data.idUsed+'_display').scrollHeight;
					if (scrollHeight - display.height()) display.scrollTop( scrollHeight - display.height() );
				}
				return false;
			}
		}
	}
	
	$.trace.disable = function() {
		data.enabled = false;
		data.initiated = false;
		$(data.display).remove();
		$(data.control).remove();
	}
	
	$.trace.enable = function(options) {
		var opts = $.extend({}, $.trace.defaults, options);
		if (!data.initiated) {
			if (!opts.useConsoleIfAvailable || !window.console || !window.console.log) {
				data.display = $('<div id="'+opts.id+'_display"></div>').css(
					{
						'position':'absolute',
						'top':'0',
						'right':'0',
						'border':opts.border,
						'background-color':opts.background,
						'overflow':'auto',
						'padding':'10px',
						'z-index':'99',
						'color':'#000000'
					}
				).width(opts.width).height(opts.height).hide();
				data.state = 'hide';
				$('body').append(data.display);
				
				data.control = $('<div id="'+opts.id+'_control"></div>').css(
					{
						'position':'absolute',
						'top':'0',
						'right':'0',
						'border':opts.border,
						'background-color':opts.background,
						'width':'10px',
						'height':'10px',
						'text-align':'center',
						'font-size':'10px',
						'line-height':'10px',
						'color':'#000000',
						'cursor':'pointer',
						'z-index':'100'
					}
				).bind('click', $.trace.toggle).html('T');
				$('body').append(data.control);
				data.idUsed = opts.id;
			}
		}
		
		data.enabled = true;
		data.initiated = true;
		
	}
	
	$.trace.toggle = function() {
		if (data.state == 'show') {
			data.state = 'hide';
			$(data.display).hide();
		} else {
			data.state = 'show';
			$(data.display).show();
		}
	}
	
	getType = function(o) {
		return Object.prototype.toString.call(o).match(/^\[object\s(.*)\]$/)[1]; 
	}
	
	// Turn trace object into string
	makeString = function(o, n) {
		var traceStr = '';
		if (!n) n=0;
		switch (getType(o)){
			case 'String':
				traceStr = '"' + o + '"';
				break;
			case 'Number':
				traceStr = '' + o;
				break;
			case 'Array':
				traceStr = '[';
				for (var i in o) {
					if(traceStr != '['){traceStr += ', '};
					traceStr += makeString(o[i]);
				}
				traceStr += ']';
				break;
			case 'Object':
				var indentStr = '';
				for (var i=0;i<n;i++) { indentStr += '    '; };
				traceStr = "{";
				for (var i in o) {
					traceStr += "\n    " + indentStr + i + ": " + makeString(o[i], n+1) + ",";
				}
				if (traceStr.substr(traceStr.length-1) == ',') { traceStr = traceStr.substr(0, traceStr.length-1) };
				traceStr += "\n" + indentStr + "}";
				break;
		};
		
		return traceStr;
	};
	
	// Defaults
	$.trace.defaults = {
		id: 'trace',
		background: '#FFFF99',
		border: '1px solid #FFCC00',
		width: 500,
		height: 400,
		useConsoleIfAvailable: true
	};
	
	// Private data
	data = {
		enabled: true,
		initiated: false,
		stack: [],
		idUsed: '',
		display: null,
		control: null,
		state: 'show'
	};
	
})(jQuery);
	  	  
	  
	