var Debug;

(function() {
	
	// ------------------------------------------------------------------------
	// Additional globals for backwards compatibility
	// ------------------------------------------------------------------------
	function initOldGlobals(handler) {
		window.dbgAlert = handler || Debug.dbgAlert;
		window.dbgA = handler || Debug.dbgAlert;
		window.drawObj = handler || Debug.dbgObject;
		window.dbgObject = handler || Debug.dbgObject;
		window.dbg = handler || Debug.dbg;
	}
	
	// already initialized somewhere
	var currentFrame = window; 
	while (true) { // scary!
		try {
			if (currentFrame.Debug && currentFrame.Debug.addWitObject)  {
				Debug = currentFrame.Debug;
				initOldGlobals();
				return;
			}
		} catch(e) {
			// cross domain errors perhaps
		}
		
		if (currentFrame != top) {
			currentFrame = currentFrame.parent;
		}
		else {
			break;
		}
		
	}
		
	Debug = {
		debugWindow: null,
		out: {
			isLoaded: false
		},
		queue: [],
		url: "/includes/showdebuginfo/index.asp?v=2.0.2"
	};
	
	// ------------------------------------------------------------------------
	// Debug.init()
	// Initializes debugging console and dbg() function.
	// Call this function explicitly, or enable showdebuginfo.
	// ------------------------------------------------------------------------
	Debug.initWindow = function (isClassicASP) {
		
		if (this.isInit) {
			return;
		}
		
		this.isInit = true;
		
		try{
			
			this.debugWindow = this.openWindow("");
			
			if (this.debugWindow) {
				
				if (isClassicASP) {
					this.initClassicASP();
				};
				
				
				if (typeof(this.debugWindow._sdb) == "undefined") {
					this.debugWindow = this.openWindow(this.getURL());
				} else {
					this.connect(this.debugWindow._sdb);
				}
	
			}
			
		} catch(e){
			// does this ever throw?
		}
		
		this.isInit = false;
	};
	
	Debug.initClassicASP = function() {
		
		this.isClassicASP = true;
		this.addWitNV = this.addWitNVClassic;
		this.addWit = this.addWitObjectClassic;
		this.timing = [];
		this.timingMap = {
			"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"
		};
	};
	
	Debug.connect = function(out) {
		this.out = out;
		this.out.isClassicASP = this.isClassicASP;
		
		this.debugWindow.document.title = "Debug - " + document.domain;
		
		this.flushQueue();
	};
	
	Debug.disconnect = function() {
		this.out = {
			isLoaded: null
		};
	};
	
	Debug.openWindow = function(url) {
		var winName = "debug_" + document.domain.replace(/\./g, "");
		return 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) {
		this.add("request", params);
	};
	
	
	Debug.addObject = function (params) {
		this.add("object", params);
	};
	
	Debug.addWitObject = function (params) {
		this.add("witObject", params);
	};
	
	Debug.addWitObjectClassic = function(params) {
		this.add("witObject", params);
		this.params = params;
	};
	
	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.addNV = function (n, v, dclType, dotNetType) {
		this.add("NV", n, v, dclType, dotNetType);
	};
	
	Debug.addWitNV = Debug.addNV;
	
	Debug.addWitNVClassic = function(n, v, dclType) {
		this.add("NV", n, v, dclType);
		
		
		var type = this.timingMap[n];
		
		// For Timing (newer version).
		if (!!type) {

			var name = this.params.name;
			var id = this.params.comId;
			var isUser = name == "User";
			var label = "Timing." + (id.replace(/^WIT[.]/g,"")) + "." + name;
			this.cpu = this.params.CPU || 0;
			var timing =
				type == "duration" ? {label:label + ".Retrieve", value:v} :
				type == "start" ? {label:label + ".ClientStart", value:v} :
				false;
			
			if (type == "CPU") {
				this.cpu += parseInt(v, 10);
			}
			if (type == "duration" && isUser) {
				this.overall = parseInt(v, 10);
			}
			if (!!timing && !isUser) {
				this.timing.push( timing );
			}
		}
	};
	
	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);
		}
	};
	
	Debug.writeMetrics = function() {
		// For Timing (newer version)
		Debug.addObject({name:"Trace"});
		Debug.addWitCollection("Timing");

		var timing = this.timing;
		var i = this.timing.length;

		while(i--) { this.add("NV", timing[i].label, timing[i].value); }
		this.add("NV", "Timing.CPU", this.cpu);
		this.add("NV", "Timing.Overall", this.overall);
		Debug.writeCollection();
	}
	
	// ------------------------------------------------------------------------
	// 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], a[3], a[4]);
				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;
				
		}
				
	};
			
	Debug.drawObj = Debug.dbgObject;
	
	initOldGlobals(Debug.doNothing);
	
})();

