﻿// Error Utilities
// This utility requires global variable 'itsClientExceptionUrl' to be defined by an external script
var itsClientExceptionUrl = "../client-exception.ashx";
//if (typeof(itsClientExceptionUrl) == "undefined" || itsClientExceptionUrl == null)
//	alert("The javascript global variable 'itsClientExceptionUrl' needs to be defined for client-side exception management to operate.");

/**
* ExceptionManager Constructor
*/
function ExceptionManager(theArguments, theMessage, theURL, theLineNumber) {

    if (typeof (theArguments) != "undefined" && theArguments != null && theArguments.length > 0)
        this._init(theArguments, theMessage, theURL, theLineNumber);
}

/*********************
* Start Static Methods
*********************/

// This method will generate a diagnostic report for debugging errors
ExceptionManager.GetDiagnosticReport = function(theMessage, theURL, theLineNumber) {
    try {
        if (typeof (itsClientExceptionUrl) == "undefined" ||
			itsClientExceptionUrl == null ||
			itsClientExceptionUrl == "")
            return false;

        // Create a new instance of the exception manager
        var aExceptionManager = new ExceptionManager(arguments, theMessage, theURL, theLineNumber);

        // Set the error to the server
        aExceptionManager.SendError();
    }
    catch (aException) {
        //alert("The error '" + aException.message + "' occurred while trying to resolve the error '" + theMessage + "'");
    }

    return true;
}

// This is the global handler setting
window.onerror = ExceptionManager.GetDiagnosticReport;

/*
* This method will check to see if the string is null
* or empty and return a boolean
*/
ExceptionManager.IsStringEmpty = function(theString) {
    if (theString == null || theString.length == 0)
        return true;
    else
        return false;
}

/*
* This method will remove the leading and following
* spaces and new lines and return the newly trimmed string
*/
ExceptionManager.TrimString = function(theString) {
    if (theString == null || theString == "")
        return "";

    // Trim the beginning of the string
    var aIndex = -1;

    // Loop forwards to the first non-space character
    while (++aIndex < theString.length && (
		    theString.charAt(aIndex) == " " ||
			theString.charAt(aIndex) == "\n" ||
			theString.charAt(aIndex) == "\r"));

    theString = theString.substring(aIndex - 1);

    // Trim the end of the string...
    aIndex = theString.length;

    // Loop backwards to the first non-space character
    while (--aIndex >= 0 && (theString.charAt(aIndex) == " " ||
		    theString.charAt(aIndex) == "\r" ||
			theString.charAt(aIndex) == "\n"));

    theString = theString.substring(0, aIndex + 1);

    return theString;
}

/**
* This method will XML encode a string. It returns
* an encoded copy of the passed string
*/
ExceptionManager.EncodeXml = function(theString) {

    if (ExceptionManager.IsStringEmpty(theString))
        return "";

    var c;
    var aReturnString = "";

    for (var i = 0; i < theString.length; i++) {
        c = theString.charAt(i);
        switch (c) {
            case "<":
                aReturnString += "&lt;";
                break;
            case ">":
                aReturnString += "&gt;";
                break;
            case "&":
                aReturnString += "&amp;";
                break;
            case "'":
                aReturnString += "&apos;";
                break;
            case "\"":
                aReturnString += "&quot;";
                break;
            default:
                aReturnString += c;
                break;
        }
    }

    return aReturnString;
}


/*********************
* End Static Methods
*********************/

/*********************
* Start Instance Methods
*********************/

/*
* ExceptionManager init
*/
ExceptionManager.prototype._init = function(theArguments, theMessage, theURL, theLineNumber) {
    var aXml = "<ClientExceptionInformation id='' timestamp='" +
		new Date().toLocaleString() + "' message='" +
		ExceptionManager.EncodeXml(theMessage) + "'>";

    aXml += this.GetEnvironmentXml();
    aXml += this.GetRequestXml();
    aXml += this.GetUserXml();
    aXml += this.GetBuildXml();

    var aStackTrace = "";
    var aFunctionName = "";

    if (theArguments.caller != null) {
        aStackTrace = this.GetStackTrace(theArguments.caller);
        aFunctionName = this.GetFunctionName(theArguments.caller.callee);
    }

    aXml += this.GetThrowableXml(theMessage, aFunctionName, theLineNumber, aStackTrace);
    aXml += "</ClientExceptionInformation>";



    // Create a XML Document
    this.itsExceptionDoc = this._createXmlDocument();

    try {
        this.itsExceptionDoc.loadXML(aXml);
    }
    catch (e) {
        var parser = new DOMParser(); // For Firefox and rest browsers
        this.itsExceptionDoc = parser.parseFromString(aXml, "text/xml");
    }

}

/**
* This is the document creator
*/
ExceptionManager.prototype._createXmlDocument = function() {
    try {
        if (document.implementation && document.implementation.createDocument) {
            var aDocument = document.implementation.createDocument("", "", null);

            //aDocument.async = false;
            //aDocument.resolveExternals = false;
            // Turn on the XPath query stuff
            //aDocument.setProperty("SelectionLanguage", "XPath");
            // Add the blank default namespace
            //aDocument.setProperty("SelectionNamespaces", "");

            return aDocument;
        }
        else if (window.ActiveXObject) {
            var aDocument = null;
            var aObjectName = "DOMDocument";


            if (aDocument == null) {
                try {
                    aDocument = new ActiveXObject("MSXML2." + aObjectName + ".5.0");
                }
                catch (e) { }
            }
            if (aDocument == null) {
                try {
                    aDocument = new ActiveXObject("MSXML2." + aObjectName + ".3.0");
                }
                catch (e) { }
            }
            if (aDocument == null)
                aDocument = new ActiveXObject("MSXML2." + aObjectName);

            aDocument.async = false;
            // Make sure this is on so imported stylesheets are allowed
            aDocument.resolveExternals = true;

            // Turn on the XPath query stuff
            aDocument.setProperty("SelectionLanguage", "XPath");
            // Add the blank default namespace
            aDocument.setProperty("SelectionNamespaces", "");

            return aDocument;
        }
    }
    catch (e) { }

    throw new Error("Your browser does not support XmlDocument objects a");
}

// Create the request object
ExceptionManager.prototype._createRequest = function() {
    try {

        if (window.XMLHttpRequest) {
            // If IE7, Mozilla, Safari, etc: Use native object
            this.itsHttpRequest = new XMLHttpRequest()
        }
        else {
            if (window.ActiveXObject) {
                // ...otherwise, use the ActiveX control for IE5.x and IE6
                this.itsHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
            }
        }
    }
    catch (e) { }

    if (this.itsHttpRequest == null)
        throw new Error("Your browser does not support XmlHttp objects b");
}

// This is the main function that posts the error to the server
ExceptionManager.prototype.SendError = function() {

    if (this.itsExceptionDoc == null || typeof (this.itsExceptionDoc) == "undefined")
        return;
    if (typeof (itsClientExceptionUrl) == "undefined" ||
		itsClientExceptionUrl == null ||
		itsClientExceptionUrl == "")
        return;

    // Create an instance of the HTTP object
    this._createRequest();

    if (this.itsHttpRequest != null && itsClientExceptionUrl != "") {
        // Open a connection with synchronous communication
        this.itsHttpRequest.open("POST", itsClientExceptionUrl, false);
        this.itsHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");

        // Post the data
        if (this.itsExceptionDoc.xml) {
            this.itsHttpRequest.send(this.itsExceptionDoc.xml); // XML to String for IE
        }
        else {
            this.itsHttpRequest.send(new XMLSerializer().serializeToString(this.itsExceptionDoc));
        }

        // Handle the response
        var aResponse = ExceptionManager.TrimString(this.itsHttpRequest.responseText);
        if (aResponse == null || aResponse.toUpperCase() == "FALSE") {
            // Display the error message
            //alert("A scripting error has occurred. Please try again.\nIf the error continues to occur then use the following code when contacting the HelpDesk.");
        }
    }



}

// converting the function to a string, then using a regular expression
// to extract the function name from the resulting code.
ExceptionManager.prototype.GetFunctionName = function(theFunction) {
    if (theFunction == null || typeof (theFunction) == "undefined" ||
		theFunction == "")
        return "anonymous";

    var aName;
    try {
        aName = theFunction.toString().match(/function (\w*)/)[1];
    }
    catch (e) {

    }

    if ((aName == null) || (aName.length == 0))
        aName = "anonymous";

    return aName;
}

ExceptionManager.prototype.GetArguments = function(theArguments) {
    var aInfo = "";

    for (var i = 0; i < theArguments.length; i++) {
        if (i == theArguments.length - 1)
            aInfo += (typeof theArguments[i]) + ": '" + theArguments[i] + "'";
        else
            aInfo += (typeof theArguments[i]) + ": '" + theArguments[i] + "', ";
    }

    return aInfo;
}

// This function returns a string that contains a "stack trace."
ExceptionManager.prototype.GetStackTrace = function(theFunction) {
    var aInfo = "";
    var aTrace = "";

    // Loop through the stack of functions, using the caller property of
    // one arguments object to refer to the next arguments object on the
    // stack.
    for (var aFunction = theFunction; aFunction != null; aFunction = aFunction.caller) {
        // Add the name of the current function to the return value.
        aInfo = this.GetFunctionName(aFunction.callee);
        aInfo += "(" + this.GetArguments(aFunction) + ")";
        aTrace += aInfo + "\n";

        // Because of a bug in Navigator 4.0, we need this line to break.
        // a.caller will equal a rather than null when we reach the end
        // of the stack. The following line works around this.
        if (aFunction.caller == aFunction)
            break;
    }

    return aTrace;
}

// This method will generate XML that represents the client environment
ExceptionManager.prototype.GetEnvironmentXml = function() {
    var aClient = navigator;

    //var aClient = window.clientInformation;

    var aXML = "<Environment>";
    aXML += "<Browser appCodeName='" +
		    aClient.appCodeName + "' appName='" +
		    aClient.appName + "' appVersion='" +
			aClient.appVersion + "' language='" +
			aClient.language + "' systemLanguage='" +
			aClient.systemLanguage + "' userLanguage='" +
			aClient.userLanguage + "' userAgent='" +
			aClient.userAgent + "' javaEnabled='" +
			aClient.javaEnabled() + "'/>";

    aXML += "<OS name='" +
		    aClient.platform + "' version='" +
		    "" + "' arch='" +
			"" + "'/>";

    aXML += "</Environment>";

    return aXML;
}

// This method will generate XML that represents the user
var itsMemberId = "";
var itsLoginName = "";
var itsUserName = "";

ExceptionManager.prototype.GetUserXml = function() {

    var aXML = "<User member_id='" +
			itsMemberId + "'"
			+ " login='" +
		    ExceptionManager.EncodeXml(itsLoginName) + "'"
			+ " full_name='" +
			ExceptionManager.EncodeXml(itsUserName) + "'/>";

    return aXML;
}


// This method will generate XML that represents the build information
var itsApplicationName = "";
var itsApplicationVersion = "";

ExceptionManager.prototype.GetBuildXml = function() {
    var aXML = "<Build name='" +
			ExceptionManager.EncodeXml(itsApplicationName) + "'"
			+ " version='" +
		    ExceptionManager.EncodeXml(itsApplicationVersion) + "'/>";

    return aXML;
}

// This method will generate XML that represents the exception
ExceptionManager.prototype.GetThrowableXml = function(theMessage, theFunctionName, theLineNumber, theStackTrace) {
    var aXML = "<Throwable message='" +
		    ExceptionManager.EncodeXml(theMessage) + "' functionName='" +
			(theFunctionName == "" ? "N/A" : theFunctionName) + "' lineNumber='" +
			theLineNumber + "'>" +
			ExceptionManager.EncodeXml(theStackTrace) + "</Throwable>";

    return aXML;
}


// This method will generate XML that represents the request
ExceptionManager.prototype.GetRequestXml = function() {
    var aLocation = window.location;
    var aScheme = aLocation.protocol.substring(0, aLocation.protocol.length - 1);

    // Strip the '?' off
    var aQuery = aLocation.search;
    if (ExceptionManager.IsStringEmpty(aQuery)) {
        aQuery = "";
    }
    else {
        aQuery = aQuery.substring(1);
    }

    var aRemoteAddress = "";
    var aReferrer = (document.referrer ? document.referrer : "");

    var aXML = "<HttpRequest requestURL='" + ExceptionManager.EncodeXml(aLocation.href) + "' referrer='" +
		    aReferrer + "'>";

    aXML += "<Request remoteHost='" +
		    ExceptionManager.EncodeXml(aRemoteAddress) + "' scheme='" +
		    aScheme + "' protocol='" +
			aLocation.protocol + "' queryString='" +
			ExceptionManager.EncodeXml(aQuery) + "' href='" +
			ExceptionManager.EncodeXml(aLocation.href) + "' serverName='" +
			aLocation.hostname + "' serverPort='" +
			(aLocation.port == "" ? "N/A" : aLocation.port) + "' servletPath='" +
			aLocation.pathname + "' isSecure='" +
			(aLocation.protocol.indexOf("https") != -1 ? "true" : "false") + "'>";

    aXML += this.GetParametersXml(aLocation.search);
    aXML += this.GetCookiesXML();
    aXML += "</Request></HttpRequest>";

    return aXML;
}

// This method will generate XML that represents the cookies
ExceptionManager.prototype.GetCookiesXML = function() {
    if (document.cookie == null)
        return "";

    var aCookieArray = document.cookie.split(";");
    var aXML = "";
    var aCookie = "";
    var aName = "";
    var aValue = "";
    var aIndex;

    for (var i = 0; i < aCookieArray.length; i++) {
        aCookie = aCookieArray[i];
        aIndex = aCookie.indexOf("=");

        if (aIndex > 0) {
            aName = aCookie.substring(0, aIndex);
            aValue = aCookie.substring(aIndex + 1);
        }
        else if (aIndex == 0) {
            aName = "Unknown";
            aValue = aCookie;
        }
        else {
            aName = aCookie;
            aValue = "";
        }

        aXML += "<Cookie name='" +
			    ExceptionManager.EncodeXml(aName) + "' value='" +
			    ExceptionManager.EncodeXml(aValue) + "' maxAge='" +
				"-1" + "' secure='" +
				"false" + "'/>";
    }

    return aXML;
}

// This method will generate XML that represents the parameters in a query string
ExceptionManager.prototype.GetParametersXml = function(theQueryString) {
    var aParameterList = this.GetParameters(theQueryString);

    if (aParameterList == null || aParameterList.length == 0)
        return "";

    var aXML = "";

    for (var i = 0; i < aParameterList.length; i++) {
        aXML += "<Parameter name='" +
			    ExceptionManager.EncodeXml(aParameterList[i].name) + "' size='" +
			    aParameterList[i].value.length + "'>" +
			    ExceptionManager.EncodeXml(aParameterList[i].value) +
			    "</Parameter>";
    }

    return aXML;

}

// This method will generate the list of parameters in a query string
ExceptionManager.prototype.GetParameters = function(theQueryString) {
    if (ExceptionManager.IsStringEmpty(theQueryString))
        return null;

    if (theQueryString.length == 1)
        return null;

    var aParameterList = new Array();

    var aQuery = theQueryString;
    if (theQueryString.charAt(0) == '?')
        aQuery = theQueryString.substring(1);

    var aPairs = aQuery.split("&");

    // Parse the query string and fill an array
    for (var i = 0; i < aPairs.length; i++) {
        var aPos = aPairs[i].indexOf("=");
        if (aPos == -1) continue;

        var aParameter = new Object();
        aParameter.name = unescape(aPairs[i].substring(0, aPos));
        aParameter.value = ExceptionManager.EncodeXml(unescape(aPairs[i].substring(aPos + 1)));
        aParameterList[aParameterList.length] = aParameter;
    }

    return aParameterList;
}

// Returns a very brief description of the contents of this report.
ExceptionManager.prototype.GetErrorSummary = function(theMessage) {
    var aSummary = "";

    if (theMessage != null)
        aSummary += theMessage;

    if (aSummary.length < 10)
        aSummary += "Client Diagnostic Report";

    return ExceptionManager.EncodeXml(aSummary);
}


/*********************
* End Instance Methods
*********************/






