// ------------------------------------------------------------------------
// debugging window
//
// usage: dbg("comment")		// print a comment
//        dbg("x", x)			// print a variable
//        dbg("x", x, "green")	// select a color
//
//
// 2008-06-27 added threading metrics - NM
// 2006-03-27 changes are afoot - BT
// 2006-01-13 added better non-debug handling for dbgObject; it used to recurse, regardless of whether the debugger was on or not
// 2005-11-28 bug fix - AW
// 2005-08-05 added dbgAlert() - AW
// 2005-08-04 fixed scrolling (don't autoscroll unless at bottom) -AW
// 2005-11-29 add unescape flag (arg 4) to Debug.dbg  - AH
// ------------------------------------------------------------------------


// need to prevent showdebuginfo from overriding this object if it has already been created
if (typeof(Debug) == "undefined" || (typeof(Debug) == "object" && typeof(Debug.init) != "function")) {
	var Debug = {
		debugWindow: null,
		out: {
			isLoaded: false
		},
		queue: [],
		url: "/includes/showdebuginfo/index.asp",
		debug:location.href.indexOf("..debugdebug..=on") != -1,
		metrics: [],
		cookieDate:new Date(new Date().setDate(365)),
		isUserPreferenceObject:false
	};
	
	// ------------------------------------------------------------------------
	// Debug.init()
	// Initializes debugging console and dbg() function.
	// Call this function explicitly, or enable showdebuginfo.
	// ------------------------------------------------------------------------
	Debug.initWindow = function () {
		try{
			this.debugWindow = this.openWindow("");
			
			if (this.debugWindow) {
				
				if (typeof(this.debugWindow._sdb) == "undefined") {
					this.debugWindow = this.openWindow(this.getURL());
				} else {
					this.connect(this.debugWindow._sdb);
				}
	
			};
	
			// reset global function
			dbg = this.dbg;
			dbgObject = this.dbgObject;
			drawObj = this.dbgObject;
			
			
		}catch(e){
		
			dbg = this.doNothing;
			dbgObject = this.doNothing;
			drawObj = this.doNothing;
			//exception sometimes thrown
		}
	};
	
	Debug.connect = function(out) {
		this.out = out;
		this.flushQueue();
	};
	
	Debug.disconnect = function() {
		this.out = {
			isLoaded: null
		};
	};
	
	Debug.openWindow = function(url) {
		var winName = "debugWin" + document.domain.replace(/[^a-z]/ig, "");
		return win = window.open(url, winName, "toolbar=no,scrollbars=yes,width=550,height=700,resizable=yes");
	};
	
	Debug.init = Debug.initWindow;
	
	Debug.initDiv = function () {
		// stub
	};
	
	Debug.initFirefoxExtension = function () {
		// stub
	};
	
	Debug.getURL = function () {
		return this.url;
	};
	
	Debug.setURL = function (url) {
		this.url = url;
	};
	
	
	
	Debug.doNothing = function () {
		return false;
	};
	
	Debug.dbgPad = function (s) {
	
		var p = (arguments.length > 1) ? arguments[1] : 5;
		var pO = "";
		var s = new String(s);
	
		if (s.length < p){
			for (var x = 0; x < p - s.length; x++) {
				pO += "0";
			};
		};
	
		return pO + s;
	};
	
	Debug.dbgObject = function (obj, prefix) {
		
		prefix = prefix || "";
	
		for (var prop in obj) {
			var type = typeof obj[prop] ;
			if (type != "object" && type != "function") {
				Debug.dbg(prefix + prop, obj[prop]);
			} else {
				Debug.dbgObject(obj[prop], prefix + prop + ".")
			}
		}
	};
	
	Debug.dbgAlert = function () {
	
		// example: dbgAlert("symbol",symbol,"type",type,"myIndex",indexPrev);
	
		var out = [];
	
		for (var n, v, x=0; x < arguments.length; x+=2){
	
			n = arguments[x];
			v = arguments[x+1];
	
			out.push((n || n == 0)?n:"");
			out.push((v || v == 0)?' = ' + ((typeof v == "string")?'"' + v + '"':v):'');
			out.push((x != arguments.length - 1)?"\n":"");
	
		}
	
		alert(out.join(""));
	};
	
	
	Debug.dbg = function (n, v, color, escapeFlag) {
		if (!Debug.debugWindow || !Debug.debugWindow.document) {
			Debug.init();
		}
	
		var args = [];
		args.push("text");
		
		for (var i=0; i<arguments.length; i++) {
			args.push(arguments[i]);
		}
		
		Debug.addText.apply(Debug, args);
	
	};
	
	// ------------------------------------------------------------------------
	// Manage debug requests
	// ------------------------------------------------------------------------
	Debug.addRequest = function(params) {
		
		if (parent != window && params.requester == "") {
			params.requester = "Iframe";
		}
		
		this.add("request", params);
	};
	
	
	Debug.addObject = function (params) {
		this.add("object", params);
	};
	
	Debug.addWitObject = function (params) {
		this.add("witObject", params);

		this.metrics.push({name:params.name || "",comId:params.comId || ""});
	};
	Debug.addWit = Debug.addWitObject;
	
	Debug.addCollection = function (name) {
		this.add("collection", name);
	};
	Debug.addWitCollection = Debug.addCollection;
	
	Debug.writeCollection = function () {
		this.add("writeCollection")

	};
	Debug.writeWitCollection = Debug.writeCollection;
	
	Debug.writeMetrics = function () {
	
		var startTime = new Date();

		function pad(s,l) {
			s = String(s);
			for (var i=s.length; i<l; i++) {
				s+=" ";
			}
			return s;
		}

		try { // don't blow up the entire page if this errors for some reason

			var userMetrics = {};
	
			var metrics = this.metrics;
	
			for (var i=0; i<metrics.length; i++) {
				if (metrics[i].name == "User" || metrics[i].start == undefined || metrics[i].duration == undefined) {

					if (metrics[i].name == "User") {
						userMetrics = metrics[i];
						/*
						var recentCPU = this.Cookies.setCookie("Debug.UserCPU");

						var CPU = userMetrics.CPU;
						this.Cookies.setCookie("Debug.UserCPU", CPU, this.cookieDate, "/", ".wallst.com");
						this.Cookies.setCookie("Debug.UserCPU", CPU, this.cookieDate, "/", "");
						*/
					}

					metrics.splice(i,1);
					i--
				}
			}
	
			metrics.sort(function(a, b){ if(a.start > b.start){ return 1; }; if(b.start > a.start){ return -1; }; return 0; });
	
			var results = [];
			var total = 1;
			for (var x = 0; x < metrics.length; x++) {
				results.push(pad(metrics[x].start,5) + pad(" (" + metrics[x].duration + ")",7) + " --> " + metrics[x].name + " (" + metrics[x].comId + ")");
				if ((metrics[x+1]) && metrics[x].start != metrics[x+1].start) {
					total++;
					results.push('----------')
				}
			};
	
			if (metrics.length > 0) { // logging 1 request isn't useful
	
				results.push ('----------', 'Threading Ratio: '+total+' of '+(results.length-total+1)+' Requests');
		
				var BWFStatus = ((results.length-total+1) / total > 2) ? "Threading Looks Good" : "Possible Threading Issues";
				BWFStatus += userMetrics.CPU ? (", Total: " + userMetrics.duration + ", CPU: " + userMetrics.CPU) : "";		

	
					//alert(results.join("\n"));
			
				Debug.addWit({name: "Threading Metrics",comId: "WIT",status: "Success, "+BWFStatus});
				//Debug.addObject({ name: "Threading Metrics" });
				Debug.addWitCollection("Threading Metrics");
				Debug.addWitNV("","\n" + pad("Start",6) + pad("Duration",8) + "\n" + results.join("\n"));
				//Debug.addWitNV("Timing",(new Date().getTime())-startTime.getTime());
				Debug.writeCollection();
			}

		} catch(e) { }


		this.metrics = [];
	}

	Debug.addNV = function (n, v) {
		this.add("NV", n, v);

		var map = {
			"DclCore[0].Timing[0]":"duration",
			"DCLCore[0].Timing[0]":"duration",
			"DclCore[0].Timing[0].ClientStart[0]":"start",
			"DCLCore[0].Timing[0].ClientStart[0]":"start",
			"DclCore[0].Timing[0].CPU[0]":"CPU",
			"DclCore[0].Timing[0].CPU[0]":"CPU"
		}

		if (map[n] && this.metrics.length) {
			this.metrics[this.metrics.length-1][map[n]] = v;
		}
	};
	Debug.addWitNV = Debug.addNV;
	
	Debug.addText = function() {
		this.add.apply(this, arguments);
	};
	
	Debug.addConsoleBreak = function() {
		this.add("consoleBreak");
	};
	
	Debug.add = function() {
		if (!this.out.isLoaded || this.queue.length) {
			this.addToQueue.apply(this, arguments);
		} else {
			this.write.apply(this, arguments);
		}
	};
	
	
	// ------------------------------------------------------------------------
	// Request Queueing
	// ------------------------------------------------------------------------
	Debug.addToQueue = function() {
		this.queue.push(arguments);
	};
	
	Debug.flushQueue = function() {
		//var start = new Date().getTime();
		for (var i=0; i<this.queue.length; i++) {
			this.write.apply(this, this.queue[i]);
		}
		this.queue = [];
		//var stop = new Date().getTime();
		//alert("Queue flush took " + (stop-start) + "ms");
	
	};
	
	// ------------------------------------------------------------------------
	// Write
	// ------------------------------------------------------------------------
	Debug.write = function() {
		/*
		var args = [];
		for (var i=1; i<arguments.length; i++) {
			args.push(arguments[i]);
		}
		*/
		var a = arguments;
		
		switch (a[0]) {
			
			case "request" :
				//this.out.addRequest.apply(this.out, args);
				this.out.addRequest(a[1]);
				break;
			
			case "object" :
				//this.out.addWit.apply(this.out, args);
				this.out.addObject(a[1]);
				break;
			
			case "witObject" :
				//this.out.addWit.apply(this.out, args);
				this.out.addWitObject(a[1]);
				break;
				
			case "collection" :
				//this.out.addWitCollection.apply(this.out, args);
				this.out.addCollection(a[1]);
				break;
				
			case "NV" :
				//this.out.addWitNV.apply(this.out, args);
				this.out.addNV(a[1], a[2]);
				break;
			
			case "writeCollection" :
				this.out.writeCollection();
				break;
			
			case "consoleBreak" :
				this.out.addConsoleBreak();
				break;
			
			case "text" : default :
				/* 
				this is moronic, and it's IE's fault
				objects created in another window do not appear to be true js objects
				so, you cannot do function.apply on a function created in another window
				BUT you can call that function and pass it arguments like any other function
				i cannot find another way around this
				*/
				
				//this.out.addText.apply(this.out, args);
				
				switch (a.length) {
				
					case 2 :
						this.out.addText(a[1]);
						break;
						
					case 3 :
						this.out.addText(a[1], a[2]);
						break;
						
					case 4 :
						this.out.addText(a[1], a[2], a[3]);
						break;
						
					case 5 :
						this.out.addText(a[1], a[2], a[3], a[4]);
						break;
						
				}
				break;
				
		}
				
	};
	
	
	
	// ------------------------------------------------------------------------
	// Additional globals for backwards compatibility
	// ------------------------------------------------------------------------
	Debug.drawObj = Debug.dbgObject;
	
	//var drawObj = Debug.dbgObject;
	//var dbgObject = Debug.dbgObject;
	var dbgAlert = Debug.dbgAlert;
	var dbgA = Debug.dbgAlert;
	
	var drawObj = new Function();
	var dbgObject = new Function();
	var dbg = new Function();

	
	Debug.Cookies = {
		/*
	
			this was taken from http://www.webreference.com/js/column8/functions.html...
	
			... the fixDate function doesnt make too much sense to me, but I've left it here for now...
			- ben
	
	
		   name - name of the cookie
		   value - value of the cookie
		   [expires] - expiration date of the cookie
			 (defaults to end of current session)
		   [path] - path for which the cookie is valid
			 (defaults to path of calling document)
		   [domain] - domain for which the cookie is valid
			 (defaults to domain of calling document)
		   [secure] - Boolean value indicating if the cookie transmission requires
			 a secure transmission
		   * an argument defaults when it is assigned null as a placeholder
		   * a null placeholder is not required for trailing omitted arguments
		*/
	
		setCookie: function (name, value, expires, path, domain, secure) {
		  var curCookie = name + "=" + escape(value) +
			  ((expires) ? "; expires=" + expires.toGMTString() : "") +
			  ((path) ? "; path=" + path : "") +
			  ((domain) ? "; domain=" + domain : "") +
			  ((secure) ? "; secure" : "");
		  document.cookie = curCookie;
		},
	
	
		/*
		  name - name of the desired cookie
		  return string containing value of specified cookie or null
		  if cookie does not exist
		*/
	
		getCookie: function (name) {
		  var dc = document.cookie;
		  var prefix = name + "=";
		  var begin = dc.indexOf("; " + prefix);
		  if (begin == -1) {
			begin = dc.indexOf(prefix);
			if (begin != 0) return null;
		  } else
			begin += 2;
		  var end = document.cookie.indexOf(";", begin);
		  if (end == -1)
			end = dc.length;
		  return unescape(dc.substring(begin + prefix.length, end));
		},
	
	
		/*
		   name - name of the cookie
		   [path] - path of the cookie (must be same as path used to create cookie)
		   [domain] - domain of the cookie (must be same as domain used to
			 create cookie)
		   path and domain default if assigned null or omitted if no explicit
			 argument proceeds
		*/
	
		deleteCookie: function (name, path, domain) {
		  if (this.getCookie(name)) {
			document.cookie = name + "=" +
			((path) ? "; path=" + path : "") +
			((domain) ? "; domain=" + domain : "") +
			"; expires=Thu, 01-Jan-70 00:00:01 GMT";
		  }
		},
	
		// date - any instance of the Date object
		// * hand all instances of the Date object to this function for "repairs"
	
		fixDate: function (date) {
		  var base = new Date(0);
		  var skew = base.getTime();
		  if (skew > 0)
			date.setTime(date.getTime() - skew);
		}
	}
	
}