
function Debugger(recordControlAudit, recordControlDetailed, recordRteAudit, recordRteDetailed, 
				  recordSequencingAudit, recordSequencingDetailed, recordLookAheadAudit,
				  recordLookAheadDetailed, version, includeTimestamps){
	this.auditCount = 0;
	
	this.RecordControlAudit = recordControlAudit;
	this.RecordControlDetailed = recordControlDetailed;
	if (this.RecordControlDetailed) {
		this.RecordControlAudit = true;
	}
	
	this.RecordRteAudit = recordRteAudit;
	this.RecordRteDetailed = recordRteDetailed;
	if (this.RecordRteDetailed) {
		this.RecordRteAudit = true;
	}
	
	this.RecordSequencingAudit = recordSequencingAudit;
	this.RecordSequencingDetailed = recordSequencingDetailed;
	if (this.RecordSequencingDetailed) {
		this.RecordSequencingAudit = true;
	}
	
	this.RecordLookAheadAudit = recordLookAheadAudit;
	this.RecordLookAheadDetailed = recordLookAheadDetailed;
	if (this.RecordLookAheadDetailed) {
		this.RecordLookAheadAudit = true;
	}
	
	// Functions
	this.Write = Debugger_Write;
	this.Clear = Debugger_Clear;
	this.AssertError = Debugger_AssertError;
	this.DataIsAvailable = Debugger_DataIsAvailable;
	this.ShowAllAvailableData = Debugger_ShowAllAvailableData;
	
	this.WriteControlAudit = Debugger_WriteControlAudit;
	this.WriteControlDetailed = Debugger_WriteControlDetailed;	
	this.WriteRteAudit = Debugger_WriteRteAudit;
	this.WriteRteAuditReturnValue = Debugger_WriteRteAuditReturnValue;
	this.WriteRteDetailed = Debugger_WriteRteDetailed;
	
	this.WriteSequencingAudit = Debugger_WriteSequencingAudit;
	this.WriteSequencingAuditReturnValue = Debugger_WriteSequencingAuditReturnValue;
	this.WriteSequencingDetailed = Debugger_WriteSequencingDetailed;
	
	this.WriteLookAheadAudit = Debugger_WriteLookAheadAudit;
	this.WriteLookAheadAuditReturnValue = Debugger_WriteLookAheadAuditReturnValue;
	this.WriteLookAheadDetailed = Debugger_WriteLookAheadDetailed;

	//this.items = new Array();
	this.log = new Log(version, includeTimestamps);
	this.logArray = new Array();
	
	this.currentControlEntry = null;
	this.currentRunTimeEntry = null;
	this.currentSequencingEntry = null;
	this.currentLookAheadEntry = null;
	
	this.ErrorDataExists = false;
	
	this.version = version;
	this.includeTimestamps = includeTimestamps;
}

function Debugger_Write(str){
	this.AssertError("Debug.Write function is deprecated. Remove all calls.");
}

function Debugger_Clear(){
    if (this.log.isXmlBased) {  
		// Save off this log so we can still retreive it in this session
		this.logArray[this.logArray.length] = this.log.root.xml;
		this.log = new Log(this.version, this.includeTimestamps);
    }
}

function Debugger_AssertError(arg, errorCondition){
	//TODO: include a compile switch to turn the prompt off in production
	//TODO: make sure to write to the debug log
	if (errorCondition === undefined || errorCondition === null || errorCondition === true){
		Debug.WriteControlAudit("Code Asserted Error-" + arg);
		if (confirm(arg + "\r\nWould you like to enter debug mode?")){
	
			//XXXXXXXXXXXXXXXXXXXXXxx
			var x=a.b.c;
		}
	}
}

function Debugger_DataIsAvailable(){

	var dataIsAvailable =	this.RecordControlAudit ||
							this.RecordControlDetailed ||
							this.RecordRteAudit ||
							this.RecordRteDetailed ||
							this.RecordSequencingAudit ||
							this.RecordSequencingDetailed ||
							this.RecordLookAheadAudit ||
							this.RecordLookAheadDetailed ||
							this.ErrorDataExists;
	
	return dataIsAvailable;
}


function Debugger_ShowAllAvailableData(){
	
	if (this.log.isXmlBased) {
		var cnt = 0;
		
		var completeLog = new Log(this.version, this.includeTimestamps);

		// Concatonate all log data in the logArray then display it.
		for(var i = 0; i < this.logArray.length; i++) {
			var nextLog = zXmlDom.createDocument();
			nextLog.async = false;
			nextLog.validateOnParse = false;
			nextLog.resolveExternals = false;
			nextLog.loadXML(this.logArray[i]);

			for(var j = 0; j < nextLog.documentElement.childNodes.length; j++) {
				completeLog.root.appendChild(nextLog.documentElement.childNodes[j].cloneNode(true));
				cnt++;
			}
		}
		
		// Finally concat the current log records
		for(var i = 0; i < this.log.root.childNodes.length; i++) {
			completeLog.root.appendChild(this.log.root.childNodes[i].cloneNode(true));
			cnt++;
		}
		
		completeLog.display();
		completeLog = null;
		
	} else {
		this.log.display();
	}
}

//
// Control
//
function Debugger_WriteControlAudit(args, parentEntry, isError){

	//alert("this.RecordControlAudit=" + this.RecordControlAudit);
	
	if (isError) {
		this.ErrorDataExists = true;
	}

	if (this.RecordControlAudit || isError) {
		if (parentEntry === undefined || parentEntry === null){
			this.currentControlEntry = this.log.startNew("c", args);
		}
		else{
			this.currentControlEntry = parentEntry.startNew("c", args);
		}
		
		this.currentControlEntry.setAttribute("id", this.auditCount++);
		return this.currentControlEntry;
	} else {
		return disabledLogEntry;
	}
}

function Debugger_WriteControlAuditReturnValue(str, parentEntry, isError){
	
	// Only possibility for null is when dynamically turning on debugging at runtime
	if (this.currentControlEntry == null) {
		return;
	}
	
	if (this.RecordControlAudit || isError) {
		this.currentControlEntry.setReturn(str);
	}
	
	if (parentEntry !== null && parentEntry !== undefined) {
		this.currentControlEntry = parentEntry;
	} else {
		this.AssertError("Debugger_WriteControlAuditReturnValue() called without parentEntry");
	}		
}

function Debugger_WriteControlDetailed(str, parentEntry, isError){

	// Only possibility for null is when dynamically turning on debugging at runtime
	if (this.currentControlEntry == null) {
		return;
	}

	if (isError) {
		var errorEntry = this.WriteControlAudit("Control ERROR", null, true)
		errorEntry.write(str);
	}
	else if (this.RecordControlDetailed) {
		if (parentEntry !== undefined && parentEntry !== null){
			parentEntry.write(str);
		}
		else{
			this.currentControlEntry.write(str);
		}
	}
}

//
// RunTime
//
function Debugger_WriteRteAudit(args, parentEntry){

	if (this.RecordRteAudit) {
		if (parentEntry === undefined || parentEntry === null){
			this.currentRunTimeEntry = this.log.startNew("rt", args);
		}
		else{
			this.currentRunTimeEntry = parentEntry.startNew("rt", args);
		}	
			
		this.currentRunTimeEntry.setAttribute("id", this.auditCount++);		
		return this.currentRunTimeEntry;
	} else {
		return disabledLogEntry;
	}
}

function Debugger_WriteRteAuditReturnValue(str, parentEntry){

	// Only possibility for null is when dynamically turning on debugging at runtime
	if (this.currentRunTimeEntry == null) {
		return;
	}

	if (this.RecordRteAudit) {
		this.currentRunTimeEntry.setReturn(str);
	}
	
	if (parentEntry !== null && parentEntry !== undefined) {
		this.currentRunTimeEntry = parentEntry;
	} else {
		//this.AssertError("Debugger_WriteRteAuditReturnValue() called without parentEntry");
	}		
}

function Debugger_WriteRteDetailed(str, parentEntry){
	
	// Only possibility for null is when dynamically turning on debugging at runtime
	if (this.currentRunTimeEntry == null) {
		return;
	}	
	
	if (this.RecordRteDetailed) {
		if (parentEntry === undefined || parentEntry === null){
			this.currentRunTimeEntry.write(str);
		}
		else{
			parentEntry.write(str);
		}
	}
}

//
// Sequencing
//
function Debugger_WriteSequencingAudit(args, parentEntry){

	if (this.RecordSequencingAudit) {
		
		if (parentEntry === undefined || parentEntry === null){
			this.currentSequencingEntry = this.log.startNew("s", args);
		}
		else{
			this.currentSequencingEntry = parentEntry.startNew("s", args);
		}
		
		this.currentSequencingEntry.setAttribute("id", this.auditCount++);		
		return this.currentSequencingEntry;
	} else {
		return disabledLogEntry;
	}
}

function Debugger_WriteSequencingAuditReturnValue(str, parentEntry){
	
	// Only possibility for null is when dynamically turning on debugging at runtime
	if (this.currentSequencingEntry == null) {
		return;
	}		
	
	if (this.RecordSequencingAudit) {
		this.currentSequencingEntry.setReturn(str);
	}
	
	if (parentEntry !== null && parentEntry !== undefined) {
		this.currentSequencingEntry = parentEntry;
	} else {
		this.AssertError("Debugger_WriteSequencingAuditReturnValue() called without parentEntry");
	}	
}

function Debugger_WriteSequencingDetailed(str, parentEntry){

	// Only possibility for null is when dynamically turning on debugging at runtime
	if (this.currentSequencingEntry == null) {
		return;
	}	

	if (this.RecordSequencingDetailed) {
		if (parentEntry === undefined || parentEntry === null){
			this.currentSequencingEntry.write(str);
		}
		else{
			parentEntry.write(str);
		}
	}
}

//
// Look Ahead
//
function Debugger_WriteLookAheadAudit(args, parentEntry){

	if (this.RecordLookAheadAudit) {
		if (parentEntry === undefined || parentEntry === null){
			this.currentLookAheadEntry = this.log.startNew("l", args);
		}
		else{
			this.currentLookAheadEntry = parentEntry.startNew("l", args);
		}
			
		this.currentLookAheadEntry.setAttribute("id", this.auditCount++);		
		return this.currentLookAheadEntry;
	} else {
		return disabledLogEntry;
	}
}

function Debugger_WriteLookAheadAuditReturnValue(str, parentEntry){
	
	// Only possibility for null is when dynamically turning on debugging at runtime
	if (this.currentLookAheadEntry == null) {
		return;
	}	
	
	if (this.RecordLookAheadAudit) {
		this.currentLookAheadEntry.setReturn(str);
	}	
	
	if (parentEntry !== null && parentEntry !== undefined) {
		this.currentLookAheadEntry = parentEntry;
	} else {
		this.AssertError("Debugger_WriteLookAheadAuditReturnValue() called without parentEntry");
	}
}

function Debugger_WriteLookAheadDetailed(str, parentEntry){
	
	// Only possibility for null is when dynamically turning on debugging at runtime
	if (this.currentLookAheadEntry == null) {
		return;
	}		
	
	if (this.RecordLookAheadDetailed) {
		
		if (parentEntry === undefined || parentEntry === null){
			this.currentLookAheadEntry.write(str);
		}
		else{
			parentEntry.write(str);
		}
	
	}
}

// "Dummy" disabled LogEntry to be returned by disabled logging functions
function DisabledLogEntry() {}
DisabledLogEntry.prototype.write = function() {};
DisabledLogEntry.prototype.error = function() {};
DisabledLogEntry.prototype.startNew = function() { return disabledLogEntry };
DisabledLogEntry.prototype.setAttribute = function() {};
DisabledLogEntry.prototype.setReturn = function() {};

// Create a single global instance
disabledLogEntry = new DisabledLogEntry();
