// Namespacing 
var IRTH = window.IRTH || {};

IRTH.ErrorHandler = 
{
	'handleError' : function(msg, url, lineNum)
	{
		// Create a hash of the line number, message and URL
		var hashCode = hex_md4(msg + url + lineNum);
		
		// Retrieve an array of errors already reported
		var cookieValue = IRTH.ErrorHandler.getReportedErrorsCookie();
		var reportedErrors = IRTH.ErrorHandler.deserializeReportedErrors(cookieValue);
		
		// If this error already exists then update its count, otherwise add a new entry to the array
		var errorCount = 1;
		var wasFound = false;
		for (var i=0; i < reportedErrors.length; i++)
		{
			var thisError = reportedErrors[i];
			if (thisError.hashCode == hashCode)
			{
				wasFound = true;
				errorCount = ++thisError.count;
			}
		}
		
		if (!wasFound)
		{
			reportedErrors[reportedErrors.length] = 
			{
				"hashCode" : hashCode,
				"count" : 1,
				"msg" : msg,
				"lineNumber" : lineNum
			};
		}
		
		// Update the cookie
		cookieValue = IRTH.ErrorHandler.serializeReportedErrors(reportedErrors);
		IRTH.ErrorHandler.setReportedErrorsCookie(cookieValue);
		
		// If this was the first occurrence, or every 10th occurrence thereafter, log it
		if ((errorCount == 1) || (errorCount % 10 == 0))
		{
			IRTH.ApplicationLog.logError("Line " + lineNum + ": " + msg + " [count: " + errorCount + "]");
		}
		
		// Notify the user and let the error bubble up
		alert("An error has occurred: " + msg);
		return false;
	},
	
	'serializeReportedErrors' : function(errorData)
	{
        /// <summary>
        /// Serializes an array of error data to a string for storage. The error
		/// array is serialized as a pipe-delimited list of errors, where each
		/// error is in the format "hashCode~count~message~lineNumber".
        /// </summary	

		var serialized = "";
		for(var i=0; i < errorData.length; i++)
		{
			var thisError = errorData[i];
			
			// Replace any tildes, pipes or semicolons with spaces... don't know if escaping them is worth the trouble
			serialized += 
				"|" 
				+ thisError.hashCode + "~" 
				+ thisError.count + "~" 
				+ thisError.msg.replace(/[\|~;]/g, ' ') + "~" 
				+ thisError.lineNumber;
		}

		// trim the leading "|"
		if (serialized.length > 0)
			serialized = serialized.substring(1);
			
		return serialized;
	},
	
	'deserializeReportedErrors' : function(serialized)
	{
        /// <summary>
        /// Deserializes the error data into an array of objects. Each object has these members:
		/// 	.hashCode 	= unique hashcode for the error
		///		.count		= number of times this error has occurred
		///		.msg 		= message that was logged
		///		.lineNumber	= line number the error occurred on
        /// </summary	

		// string is pipe-delimited list of ~-delimited values
		var reportedErrors = new Array();
		
		if (serialized.length > 0)
		{
			var errorData = serialized.split('|');
			for (var i=0; i < errorData.length; i++)
			{
				var thisErrorData = errorData[i].split('~');

				reportedErrors[i] = 
				{
					"hashCode" : thisErrorData[0],
					"count" : thisErrorData[1],
					"msg" : thisErrorData[2],
					"lineNumber" : thisErrorData[3]
				};
			}
		}
		
		return reportedErrors;
	},

	'getReportedErrorsCookie' : function()
	{
        /// <summary>
        /// Returns the value stored in the cookie used to track reported errors.
        /// </summary	
		
		var cookies = document.cookie.split(';');
		for (var i=0; i < cookies.length; i++)
		{
			var cookieData = cookies[i].split('=');
			var cookieName = cookieData[0].replace(/^\s+|\s+$/g, '');
			
			if (cookieName == "IRTH_ReportedErrors")
				return cookieData[1].replace(/^\s+|\s+$/g, '');
		}
		return "";
	},
	
	'setReportedErrorsCookie' : function(stringData)
	{
        /// <summary>
        /// Stores a serialized error array to a browser cookie that expires tomorrow.
        /// </summary	
		
		// expire at 12:00am tomorrow, so that we get at least one report per day
		var expires;
		with (expires = new Date())
		{
			setDate(getDate()+1);
			setHours(0);
			setMinutes(0);
			setSeconds(0);
			setMilliseconds(0);
		}
		document.cookie = "IRTH_ReportedErrors=" + stringData + "; expires=" + expires.toGMTString() + "; path=/";
	},
	
	'clearReportedErrorsCookie' : function()
	{
		var date = new Date();
		date.setTime(date.getTime()+(-1*24*60*60*1000));	// -1 day causes to expire
		document.cookie = "IRTH_ReportedErrors=; expires=" + date.toGMTString() + "; path=/";
	}
}

// Global error handler: logs data to server
window.onerror = IRTH.ErrorHandler.handleError;
