﻿var Functions = new FunctionsClass();

//======================================================
// Functions class
//======================================================
function FunctionsClass()
{
	var THIS = this;
	var winLockLayer = null;
	var winMessage = null;
	var winMessageText = null;
	var zIndex = 2000;
	
	THIS.Name = 'FunctionsClass';
	THIS.MoveObjectXPadding = 0;
	THIS.MoveObjectYPadding = 0;
	
	//==================================================
	// Increment the Z index.
	//==================================================
	this.ZIndex = function ZIndex()
	{
		return zIndex++;
	}
	
	//==================================================
	// Wait window.
	//==================================================
	this.WaitWindow = function WaitWindow(MessageText)
	{
		if (winLockLayer == null)
			winLockLayer = document.getElementById('winLockLayer');
		
		if (winMessage == null)	
			winMessage = document.getElementById('winMessage');
			
		if (winMessageText == null)
			winMessageText = document.getElementById('winMessageText');
		
		if ((winMessage == null) && (winMessageText == null))
			return;
			
		if (winLockLayer == null)
			return;
		
		if (MessageText == '')
		{
			winMessageText.innerHTML = 'Loading, please wait...';
			winLockLayer.className = 'Hide';
			winMessage.className = 'Hide';
		}
		else
		{
			winMessageText.innerHTML = MessageText;
			winLockLayer.className = 'Show';
			winMessage.className = 'Show';
			
			try
			{
				winMessageText.focus();
			}
			catch(e)
			{
				// Do nothing.
			}
		}
		return;
	}
	
	//==================================================
	// Lock layer.
	//==================================================
	this.LockLayer = function LockLayer(Visibility)
	{
		if (winLockLayer == null)
			winLockLayer = document.getElementById('winLockLayer');

		if (winLockLayer == null)
			return;

		if (Visibility)
		{
			winLockLayer.className = 'Show';
			winLockLayer.style.zIndex = Functions.ZIndex();
		}
		else
		{
			winLockLayer.className = 'Hide';
		}
		return;
	}
	
	//==================================================
	// Cancel bubble.
	//==================================================
	this.CancelBubble = function CancelBubble(evt)
	{
		if (document.body.addEventListener)
		{
			evt.stopPropagation();
		}
		else
		{
			if (window.event)
			{
				window.event.cancelBubble = true;
			}
			else
			{
				evt.cancelBubble = true;
			}
		}
		return false;
	}
	
	//==================================================
	// Set the move object.
	//==================================================
	this.SetMoveObject = function SetMoveObject(Element, evt)
	{
		if (Element == null)
			return;

		var evt = ((evt == null) ? window.event : evt);

		// Get the X and Y position of the cursor.
		SetCookie(Element.id + 'Top', evt.clientY, 1);
		SetCookie(Element.id + 'Left', evt.clientX, 1);
		
		// Get the offset.
		THIS.OffsetX = evt.clientX - Element.offsetLeft;
		THIS.OffsetY = evt.clientY - Element.offsetTop;

		// Set the move object.
		THIS.MoveObject = Element;
		return;
	}
	
	//==================================================
	// Reset the move object.
	//==================================================
	this.ResetMoveObject = function ResetMoveObject(evt)
	{
		if ((THIS.MoveObject == undefined) || (THIS.MoveObject == null))
			return;
			
		var evt = ((evt == null) ? window.event : evt);

		// Get the X and Y position of the cursor.
		SetCookie(THIS.MoveObject.id + 'Top', (evt.clientY - THIS.OffsetY), 1);
		SetCookie(THIS.MoveObject.id + 'Left', (evt.clientX - THIS.OffsetX), 1);
		
		THIS.MoveObject = undefined;
		return;
	}
	
	//==================================================
	// Mouse move event handler.
	//==================================================
	this.MouseMove = function MouseMove(evt)
	{
		if ((THIS.MoveObject == undefined) || (THIS.MoveObject == null))
			return;
			
		// Check if the move is allowed.
		if (!THIS.AllowMove)
			return;
			
		var evt = ((evt == null) ? window.event : evt);

		THIS.MoveObject.style.top = (evt.clientY - THIS.OffsetY) + (THIS.MoveObjectYPadding) + 'px';
		THIS.MoveObject.style.left = (evt.clientX - THIS.OffsetX) + (THIS.MoveObjectXPadding) + 'px';
		return;
	}
	
	//==================================================
	// Key press event handler.
	//==================================================
	this.KeyPress = function KeyPress(evt, CallBack)
	{
		var objSourceElement = evt.srcElement ? evt.srcElement : evt.target;
		var intKeyCode = evt.keyCode ? evt.keyCode : evt.which;

		// Check the keycode.
		if (intKeyCode == 13)
		{
			if (CallBack != undefined)
				CallBack(evt);
			
			if (evt.preventDefault)
				evt.returnValue = false;

			return false;
		}
		return;
	}
	
	//==================================================
	// Display an error to the user.
	//==================================================
	this.DisplayError = function DisplayError(Error, CallBack)
	{
		if (blnPageUnLoading)
			return;

		THIS.WaitWindow('');
		THIS.LockLayer(false);
		
		// Check if the callback handler has been defined.
		if ((CallBack == undefined) || (CallBack == null))
		    CallBack = THIS.btnDisplayMessagePromptOK_Click
		
		Error = Error.replace(/\n/gi, '<br/>');

		var strXML = '<Error><Message>' + Error + '</Message></Error>';
		var PopupWindow = new PopupWindowClass(strXML);
		PopupWindow.Padder = 5;
		PopupWindow.Open(null, THIS, 'ErrorMessage' + new Date().getTime(), null, CallBack, null, 'Application Error', 700, 400, '/Xslt/Error.xslt');
		return;
	}
	
	//==================================================
	// Display a message to the user.
	//==================================================
	this.DisplayMessage = function DisplayMessage(Message, Title, Icon, CallBack, Width, Height)
	{
		// Check the title.
		Title = (Title == undefined) ? 'Truckfile' : Title;
		Message = Message.replace(/\n/gi, '<br/>');

		var PopupWindow = new PopupWindowClass('<Data><Icon>' + Icon + '</Icon><ActionText>' + Message + '</ActionText></Data>');
		PopupWindow.Padder = 5;
		CallBack = (CallBack == undefined ? THIS.btnDisplayMessagePromptOK_Click : CallBack);
		Width = (Width == undefined ? 350 : Width);
		Height = (Height == undefined ? 130 : Height);
		PopupWindow.Open(null, THIS, Title.replace(' ', '') + 'Prompt', null, CallBack, null, Title, Width, Height, '/Xslt/Prompt.xslt');
		return PopupWindow;
	}
	
	//==================================================
	// Display a question prompt to the user.
	//==================================================
	this.DisplayPrompt = function DisplayPrompt(Message, Title, Icon, Buttons, CallBack, Width, Height)
	{
		// Check the title.
		Title = (Title == undefined) ? 'Truckfile' : Title;
		Message = Message.replace(/\n/gi, '<br/>');
		
		// Check the button array for a 'CLOSE' function.
		for (var strButtonName in Buttons)
		{
			// Check the button name.
			if (strButtonName == undefined)
				continue;

			// Check if the button name is 'CLOSE'.
			if (Buttons[strButtonName] == 'CLOSE')
				Buttons[strButtonName] = THIS.btnDisplayPromptClose_Click;
		}
		
		THIS.Popup = new PopupWindowClass('<Data><Icon>' + Icon + '</Icon><ActionText>' + Message + '</ActionText></Data>');
		THIS.Popup.Padder = 5;
		Width = (Width == undefined ? 350 : Width);
		Height = (Height == undefined ? 130 : Height);
		THIS.Popup.Open(null, THIS, Title.replace(' ', '') + 'Prompt', null, null, null, Title, Width, Height, '/Xslt/Prompt.xslt', undefined, undefined, ((Buttons == undefined) ? undefined : Buttons));
		return THIS.Popup;
	}
	
	//==================================================
	// Display prompt close button event handler.
	//==================================================
	this.btnDisplayPromptClose_Click = function btnDisplayPromptClose_Click()
	{
		THIS.LockLayer(false);
		THIS.Popup.Close();
		return true;
	}

	//==================================================
	// Display message prompt OK button event handler.
	//==================================================
	this.btnDisplayMessagePromptOK_Click = function btnDisplayMessagePromptOK_Click()
	{
		THIS.LockLayer(false);
		return true;
	}
	
	//==================================================
	// Set keyoboard focus element.
	//==================================================
	this.KeyboardFocusElement = function KeyboardFocusElement(evt)
	{
		THIS.SourceElement = evt.srcElement ? evt.srcElement : evt.target;
		Keyboard.KeyboardElement = THIS.SourceElement;
		return;
	}
	
	//==================================================
	// Dispose.
	//==================================================
	this.Dispose = function Dispose(Page)
	{
		for(Element in Page)
		{
			if (typeof(Page[Element]) != 'function')
			{
				Page[Element] = null;
				delete Page[Element];
			}
		}
		
		delete Page;
		return;
	}
	
	//=====================================================================
	// Left pad a value.
	//=====================================================================
	this.PadLeft = function PadLeft(Value, Length, Character)
	{
		var objRegExp = new RegExp(".{" + Length + "}$");
		var pad = "";
		
		if (!Character) Character = " ";
		do  {
			pad += Character;
		}while(pad.length < Length);
		
		return objRegExp.exec(pad + Value)[0];
	}
	
	//=====================================================================
	// Right pad a value.
	//=====================================================================
	this.PadRight = function PadRight(Value, Length, Character)
	{
		var objRegExp = new RegExp("^.{" + Length + "}");
		var pad = "";

		if (!Character) Character = " ";
		do {
			pad += Character;
		} while (pad.length < Length);

		return objRegExp.exec(Value + pad)[0];
	}
	
	//=====================================================================
	// Replace ampersand.
	//=====================================================================
	this.Ampersand = function Ampersand(Text)
	{
		// Check if the browser is Internet Explorer.
		if (BrowserDetect.browser == 'Explorer')
			Text = Text.replace(/&#38;/gi, '&');
		
		return Text;
	}

	//=====================================================================
	// Format the XML for ampersand.
	//=====================================================================
	this.FormatXMLAmpersand = function FormatXMLAmpersand(XML)
	{
		XML = XML.replace(/&amp;/gi, '&#38;');
		XML = XML.replace(/  /gi, '');
		XML = XML.replace(/amp;/gi, '');
		return XML;
	}

	//=====================================================================
	// Lookup search initialisation.
	//=====================================================================
	this.LookupSearchInitialise = function LookupSearchInitialise(SearchTimeout, DisplayCount, Container)
	{
		try
		{
			// Quick search variables.
			THIS.SearchTimeout = (SearchTimeout == 0) ? 700 : SearchTimeout;
			THIS.DisplayCount = (DisplayCount == 0) ? 20 : DisplayCount;
			THIS.intHideQuickSearchTimer = 0;
			THIS.QuickSearchHide = 2000;
			THIS.DataNotFoundMessage = false;
			THIS.QuickSearchResultsRS = null;
			THIS.Container = Container;
			
			// Check if the quick search layer has already been added.
			if ((document.getElementById('QuickSearchLayer') == undefined) || (document.getElementById('QuickSearchLayer') == null))
			{
				THIS.QuickSearchLayer = document.createElement('DIV');
				THIS.QuickSearchLayer.id = 'QuickSearchLayer';
				THIS.QuickSearchLayerShadow = document.createElement('DIV');
				THIS.QuickSearchLayerShadow.id = 'QuickSearchLayerShadow';
				THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
				THIS.QuickSearchLayerShadow.innerHTML = '&nbsp;';
				THIS.QuickSearchLayerShadow.className = 'QuickSearchShadow';
				THIS.QuickSearchLayerShadow.style.display = 'none';
				THIS.Container.appendChild(THIS.QuickSearchLayer);
				THIS.Container.appendChild(THIS.QuickSearchLayerShadow);
			}
		}
		catch (e)
		{
			HtmlPopup.Error('LookupSearch():\n\n' + e.message);
		}
		return;
	}

	//==================================================
	// Lookup search textbox (e.g make etc...) key up event handler.
	//==================================================
	this.LookupSearch = function LookupSearch(evt, Recordset, OnChange, Callback, StringLength)
	{
		try
		{
			// Check the browser.	
			if ((BrowserDetect.browser == 'Explorer') && ((BrowserDetect.version == 6) || (BrowserDetect.version == 7)))
			{
				THIS.ElementTop = (evt.clientY - evt.offsetY);
				THIS.ElementLeft = (evt.clientX - evt.offsetX);
			}
			
			window.clearTimeout(THIS.intSearchTimeOut);
			THIS.DisplaySearchResults = false;

			var objSourceElement = evt.srcElement ? evt.srcElement : evt.target;
			var intKeyCode = evt.keyCode ? evt.keyCode : evt.which;
			
			if ((intKeyCode == 16) || (intKeyCode == 35) || (intKeyCode == 36) || (intKeyCode == 37) || (intKeyCode == 39))
				return;

			var blnValid = ((intKeyCode > 47 && intKeyCode < 58) || (intKeyCode > 64 && intKeyCode < 91) || (intKeyCode > 95 && intKeyCode < 123) || (intKeyCode == 8) || (intKeyCode == 8) || (intKeyCode == 13));

			THIS.Data = new Object();
			THIS.Data['SourceElement'] = objSourceElement;
			THIS.Data['StringLength'] = StringLength;
			THIS.Data['Callback'] = Callback;
			THIS.Data['Recordset'] = Recordset;

			// Check the keycode.
			if (!blnValid)
			{
				if (Callback)
					Callback(undefined, THIS.Data);

				if (evt.preventDefault)
					evt.returnValue = false;

				return false;
			}
			
			// Raise the onchange event handler.
			if (OnChange)
				OnChange();

			// Check the length of the textbox.
			if (objSourceElement.value.length >= StringLength)
			{
				THIS.SourceElement = objSourceElement;
				THIS.DisplaySearchResults = true;
				THIS.intSearchTimeOut = window.setTimeout(THIS.InvokeLookupSearch, THIS.SearchTimeout);
			}
		}
		catch (e)
		{
			HtmlPopup.Error('LookupSearch():\n\n' + e.message);
		}
		return;
	}
	
	//==================================================
	// Invoke the lookup search.
	//==================================================
	this.InvokeLookupSearch = function InvokeLookupSearch()
	{
		try
		{
			window.clearTimeout(THIS.intSearchTimeOut);
			
			if (!THIS.DisplaySearchResults)
				return;

			THIS.SourceElement.className += ' Search';
			THIS.TableName = 'Data';

			var soapClient = new SoapClient();
			
			// Check which item is being searched for.
			switch (THIS.SourceElement.id)
			{
				case 'txtMake':
					THIS.SearchType = 'Make';
					THIS.Data['Recordset'].Rows[THIS.Data['Recordset'].RecordPointer]['MakeId'] = 0;
					
					THIS.Data['ValueMember'] = 'MakeID';
					THIS.Data['DisplayMember'] = 'Make';
					soapClient.AddParameter('Name', escape(THIS.SourceElement.value));
					soapClient.SendRequest('/WebServices/Part.asmx', 'http://www.truckfile.co.uk/', 'Make_Select', THIS.LookupSearchCallback, THIS.Data);
					break;
					
				case 'txtSupplier':
					THIS.SearchType = 'Supplier';
					THIS.Data['Recordset'].Rows[THIS.Data['Recordset'].RecordPointer]['SupplierId'] = 0;
					
					THIS.Data['ValueMember'] = 'SupplierId';
					THIS.Data['DisplayMember'] = 'Supplier';
					soapClient.AddParameter('Name', escape(THIS.SourceElement.value));
					soapClient.SendRequest('/WebServices/Part.asmx', 'http://www.truckfile.co.uk/', 'Supplier_Select', THIS.LookupSearchCallback, THIS.Data);
					break;
					
				case 'txtPartType':
					THIS.SearchType = 'Part Type';
					THIS.Data['Recordset'].Rows[THIS.Data['Recordset'].RecordPointer]['PartTypeId'] = 0;
					
					THIS.Data['ValueMember'] = 'PartTypeId';
					THIS.Data['DisplayMember'] = 'PartType';
					soapClient.AddParameter('Name', escape(THIS.SourceElement.value));
					soapClient.SendRequest('/WebServices/Part.asmx', 'http://www.truckfile.co.uk/', 'PartType_Select2', THIS.LookupSearchCallback, THIS.Data);
					break;

				case 'txtOperator':
				case 'txtVehicle_Operator':
					THIS.SearchType = 'Operator';
					THIS.Data['ValueMember'] = 'Company_ID';
					THIS.Data['DisplayMember'] = 'Company_Name';
					soapClient.AddParameter('Search', escape(THIS.SourceElement.value));
					soapClient.AddParameter('CompanyType', 'OPT');
					soapClient.SendRequest('/WebServices/Common.asmx', 'http://www.truckfile.co.uk/', 'CompanySearch', THIS.LookupSearchCallback, THIS.Data);
					break;

				case 'txtOrderLinkTo':
				case 'OrderEditRegistrationNumber':
					THIS.SearchType = 'Vehicle/Asset';
					THIS.Data['ValueMember'] = 'Company_ID';
					THIS.Data['DisplayMember'] = 'Company_Name';
					soapClient.AddParameter('Search', escape(THIS.SourceElement.value));
					soapClient.AddParameter('CompanyType', 'OPT');
					soapClient.SendRequest('/WebServices/Orders.asmx', 'http://orders.magicinternet.co.uk/', 'LinkOrderToSearch', THIS.LookupSearchCallback, THIS.Data);
					break;

				case 'txtLookUp':
					THIS.SearchType = 'Company';
					THIS.Data['ValueMember'] = 'Company_ID';
					THIS.Data['DisplayMember'] = 'Company_Name';
					soapClient.AddParameter('Search', escape(THIS.SourceElement.value));
					soapClient.AddParameter('CompanyType', 'OPT');
					soapClient.SendRequest('/WebServices/Orders.asmx', 'http://orders.magicinternet.co.uk/', 'LinkRecipientToSearch', THIS.LookupSearchCallback, THIS.Data);
					break;
					
				case 'txtQuestionSearch':
					THIS.SearchType = 'Question';
					THIS.Data['ValueMember'] = 'QuestionID';
					THIS.Data['DisplayMember'] = 'QuestionText';
					
					THIS.QuestionRS = new RecordSet();
					THIS.QuestionRS.LoadXML(THIS.Data['Recordset'], 'Question');
					
					// Filter the data.
					THIS.QuestionRS.MoveFirst();
					while (!THIS.QuestionRS.EOF())
					{
						if (THIS.QuestionRS.Rows[THIS.QuestionRS.RecordPointer]['QuestionText'].toLowerCase().indexOf(THIS.SourceElement.value.toLowerCase()) < 0)
							THIS.QuestionRS.DeleteRow();

						THIS.QuestionRS.MoveNext();
					}
					
					var strXML = THIS.QuestionRS.ToString();
					strXML = strXML.replace('<Data>', '<NewDataSet>');
					strXML = strXML.replace('</Data>', '</NewDataSet>');
					
					strXML = strXML.replace(/<Question>/gi, '<Data>');
					strXML = strXML.replace(/<\/Question>/gi, '</Data>');
					
					// Check the number of records.
					if (THIS.QuestionRS.RecordCount == 0)
					{
						THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
						THIS.QuickSearchLayerShadow.style.display = 'none';
						THIS.SourceElement.className = THIS.SourceElement.className.replace(' Search', '');
						THIS.QuickSearchSourceElement = THIS.SourceElement;
						Functions.DisplayMessage('Unfortunately \'' + THIS.SourceElement.value + '\' was not found.', THIS.SearchType +  ' Not Found', 'Information', THIS.CloseDataNotFoundMessage);
					}
					else
					{
						THIS.LookupSearchCallback('OK|' + strXML, THIS.Data);
					}
					
					delete THIS.QuestionRS;
					break;
					
				default:
					THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
					THIS.QuickSearchLayerShadow.style.display = 'none';
					THIS.SourceElement.className = THIS.SourceElement.className.replace(' Search', '');
					THIS.DisplayMessage('Unable to invoke the search as the source element \'' + THIS.SourceElement.id + '\' hasn\'t been defined', 'Undefined Source Element', 'Error');
					break;

				}
		}
		catch (e)
		{
			HtmlPopup.Error('InvokeLookupSearch():\n\n' + e.message);
		}
		return;
	}
	
	//==================================================
	// Lookup search callback event handler.
	//==================================================
	this.LookupSearchCallback = function LookupSearchCallback(Response, Data)
	{
		try
		{
			if (!THIS.DisplaySearchResults)
				return;

			// Cancel the quick search timer.
			THIS.CancelHideQuickSearchTimer();
			
			var SourceElement = Data['SourceElement'];
			var Callback = Data['Callback'];
			var strValueMember = Data['ValueMember'];
			THIS.StringLength = Data['StringLength'];
			
			// Check the response.
			if (Response == undefined)
			{
				THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
				THIS.QuickSearchLayerShadow.style.display = 'none';
				SourceElement.className = SourceElement.className.replace(' Search', '');
				return;
			}
			
			var aResponse = Response.split('|');
			
			// Check if an error occured.
			if (aResponse[0] == 'ERROR')
			{
				Functions.DisplayError(aResponse[1]);
				return;
			}
			
			// Check if the result set already exist.
			if (THIS.QuickSearchResultsRS != null)
				delete THIS.QuickSearchResultsRS;
			
			THIS.QuickSearchSourceElement = SourceElement;
			THIS.QuickSearchResultsRS = new RecordSet();
			THIS.QuickSearchResultsRS.LoadXML(aResponse[1], THIS.TableName);
			
			// View the data.
			if (window.location.hostname == DevelopmentHostName)
			{
				var soapClient = new SoapClient();
				soapClient.AddParameter('Name', 'QuickSearchData.xml');
				soapClient.AddParameter('Data', escape(aResponse[1]));
				soapClient.SendRequest('/WebServices/Common.asmx', 'http://www.truckfile.co.uk/', 'ViewXMLData');
			}
			
			// Check if there are any results.
			if (THIS.QuickSearchResultsRS.RecordCount > 0)
			{
				if (THIS.QuickSearchSourceElement.value.length < THIS.StringLength)
				{
					THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
					THIS.QuickSearchLayerShadow.style.display = 'none';
					THIS.QuickSearchSourceElement.className = THIS.QuickSearchSourceElement.className.replace(' Search', '');
					return;
				}
				
				// Check if only one result was found.
				if (THIS.QuickSearchResultsRS.RecordCount == 1)
				{
					THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
					THIS.QuickSearchLayerShadow.style.display = 'none';
					THIS.QuickSearchSourceElement.className = THIS.QuickSearchSourceElement.className.replace(' Search', '');
					Callback(THIS.QuickSearchSourceElement, THIS.QuickSearchResultsRS, THIS.QuickSearchResultsRS[strValueMember]);
				}
				else
				{
					// Check the browser.	
					if ((BrowserDetect.browser == 'Explorer') && ((BrowserDetect.version == 6) || (BrowserDetect.version == 7)) && ((THIS.QuickSearchResultsRS.RecordCount > THIS.DisplayCount)))
					{
						THIS.QuickSearchSourceElement.className = THIS.QuickSearchSourceElement.className.replace(' Search', '');
						Functions.DisplayMessage('Your browser is not capable of displaying all the results, please consider using Internet Explorer 8, Firefox of Safari. Please contact your system adinmistrator for more information.', 'Quick Search Results', 'Information');
						return;
					}

					// Load the content.
					var objXSLTransform = new XSLTransform();
					objXSLTransform.Transform(THIS.QuickSearchLayer, '/Xslt/LookupSearchResults.xslt?DisplayMember=' + Data['DisplayMember'] + '&DisplayCount=' + THIS.DisplayCount, aResponse[1], THIS.QuickSearchLayerLoaded);
					delete objXSLTransform;
				}
			}
			else
			{
				
				THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
				THIS.QuickSearchLayerShadow.style.display = 'none';
				THIS.QuickSearchSourceElement.className = THIS.QuickSearchSourceElement.className.replace(' Search', '');
				
				//if no message then do not show
				if(THIS.SearchType != 'NOMESSAGE')
				{	
					Functions.DisplayMessage('Unfortunately \'' + THIS.QuickSearchSourceElement.value + '\' was not found.', THIS.SearchType +  ' Not Found', 'Information', THIS.CloseDataNotFoundMessage);
				}
			}
		}
		catch (e)
		{
			THIS.QuickSearchSourceElement.className = THIS.QuickSearchSourceElement.className.replace(' Search', '');
			HtmlPopup.Error('LookupSearchCallback():\n\n' + e.message);
		}
		return;
	}
	
	//====================================================
	// Quick search layer content loaded handler.
	//====================================================
	this.QuickSearchLayerLoaded = function QuickSearchLayerLoaded()
	{
		try
		{
			if (THIS.QuickSearchSourceElement.value.length < THIS.QuickSearchLength)
			{
				THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
				THIS.QuickSearchLayerShadow.style.display = 'none';
				THIS.QuickSearchSourceElement.className = THIS.QuickSearchSourceElement.className.replace(' Search', '');
				return;
			}

			var intOffset = (BrowserDetect.browser == 'Explorer') ? 1 : 0;
			
			// Set the width and height of the quick search layer.
			THIS.QuickSearchLayer.style.width = (THIS.QuickSearchSourceElement.offsetWidth - 2) + 'px';
			THIS.QuickSearchLayer.scrollTop = 0;
			
			// Check if the element top and left variables exist.
			if (THIS.ElementTop)
			{
				THIS.QuickSearchLayer.style.top = ((THIS.ElementTop + THIS.QuickSearchSourceElement.offsetHeight) - 4) + 'px';
				THIS.QuickSearchLayer.style.left = (THIS.ElementLeft - 3) + 'px';
			}
			else
			{
				if (THIS.QuickSearchSourceElement.offsetParent.offsetParent == 'DIV')
				{
					THIS.QuickSearchLayer.style.top = (THIS.QuickSearchSourceElement.offsetParent.offsetParent.offsetTop + THIS.QuickSearchSourceElement.offsetParent.offsetTop + THIS.QuickSearchSourceElement.offsetTop) + (THIS.QuickSearchSourceElement.offsetHeight - 27) + 'px';
					THIS.QuickSearchLayer.style.left = ((THIS.QuickSearchSourceElement.offsetParent.offsetParent.offsetLeft + THIS.QuickSearchSourceElement.offsetParent.offsetLeft + THIS.QuickSearchSourceElement.offsetLeft) - intOffset)+ 'px';
				}
				else
				{
					THIS.QuickSearchLayer.style.top = ((THIS.QuickSearchSourceElement.offsetTop + THIS.QuickSearchSourceElement.offsetHeight) - 1)+ 'px';
					THIS.QuickSearchLayer.style.left = (THIS.QuickSearchSourceElement.offsetLeft) + 'px';
				}
			}
			
			THIS.QuickSearchLayer.className = 'QuickSearchLayerShow';
			THIS.QuickSearchLayer.onmouseout = THIS.StartHideQuickSearchTimer;
			THIS.QuickSearchLayer.onmouseover = THIS.CancelHideQuickSearchTimer;
			
			if (THIS.QuickSearchResultsRS.RecordCount > THIS.DisplayCount)
			{
				var QuickSearchContainer = document.getElementById('QuickSearchContainer');
				
				if (THIS.QuickSearchSourceElement.offsetParent.offsetParent == 'DIV')
				{
					QuickSearchContainer.style.height = (THIS.Container.offsetHeight - 50) + 'px';
				}
				else
				{
					QuickSearchContainer.style.height = ((THIS.QuickSearchSourceElement.offsetParent.offsetHeight - THIS.QuickSearchSourceElement.offsetTop) - 50) + 'px';
				}

				QuickSearchContainer.style.overflowY = 'scroll';
				QuickSearchContainer.style.borderTop = 'solid 1px #000';
				QuickSearchContainer.style.borderBottom = 'solid 1px #000';
			}
			
			THIS.QuickSearchLayerShadow.style.top = THIS.QuickSearchLayer.offsetTop + 5 + 'px';
			THIS.QuickSearchLayerShadow.style.left = THIS.QuickSearchLayer.offsetLeft + 5 + 'px';
			THIS.QuickSearchLayerShadow.style.width = THIS.QuickSearchLayer.offsetWidth + 'px';
			THIS.QuickSearchLayerShadow.style.height = THIS.QuickSearchLayer.offsetHeight + 'px';
			THIS.QuickSearchLayerShadow.style.display = 'block';

			THIS.QuickSearchSourceElement.className = THIS.QuickSearchSourceElement.className.replace(' Search', '');
			THIS.StartHideQuickSearchTimer();
		}
		catch(e)
		{
			THIS.QuickSearchSourceElement.className = THIS.QuickSearchSourceElement.className.replace(' Search', '');
			HtmlPopup.Error('QuickSearchLayerLoaded():\n\n' + e.message);
		}
		return;
	}

	//====================================================
	// Lookup search item click event handler.
	//====================================================
	this.LookupSearchItem_Click = function LookupSearchItem_Click(ValueMember)
	{
		try
		{
			// Invoke the call back handler.
			THIS.Data['Callback'](THIS.QuickSearchSourceElement, THIS.QuickSearchResultsRS, ValueMember);
			THIS.HideQuickSearch();
		}
		catch (e)
		{
			HtmlPopup.Error('StartHideQuickSearchTimer():\n\n' + e.message);
		}
		return;
	}

	//====================================================
	// Start the timer to hide quick search layer.
	//====================================================
	this.StartHideQuickSearchTimer = function StartHideQuickSearchTimer()
	{
		try
		{
			THIS.intHideQuickSearchTimer = window.setTimeout(THIS.HideQuickSearch, THIS.QuickSearchHide);
		}
		catch (e)
		{
			HtmlPopup.Error('StartHideQuickSearchTimer():\n\n' + e.message);
		}
		return;
	}
	
	//====================================================
	// Cancel the hide quick search layer timer.
	//====================================================
	this.CancelHideQuickSearchTimer = function CancelHideQuickSearchTimer()
	{
		try
		{
			window.clearTimeout(THIS.intHideQuickSearchTimer);
		}
		catch (e)
		{
			HtmlPopup.Error('CancelHideQuickSearchTimer():\n\n' + e.message);
		}
		return;
	}

	//====================================================
	// Hide quick search layer.
	//====================================================
	this.HideQuickSearch = function HideQuickSearch()
	{
		try
		{
			window.clearTimeout(THIS.intHideQuickSearchTimer);
			
			if (THIS.QuickSearchLayer)
			{
				THIS.QuickSearchLayer.className = 'QuickSearchLayerHide';
				THIS.QuickSearchLayerShadow.style.display = 'none';
			}
		}
		catch (e)
		{
			HtmlPopup.Error('HideQuickSearch():\n\n' + e.message);
		}
		return;
	}

	//====================================================
	// Close data not found message event handler.
	//====================================================
	this.CloseDataNotFoundMessage = function CloseDataNotFoundMessage()
	{
		try
		{
			THIS.QuickSearchSourceElement.focus();
		}
		catch (e)
		{
			HtmlPopup.Error('HideQuickSearch():\n\n' + e.message);
		}
		return true;
	}

	//====================================================
	// Allow only alpha/numeric values.
	//====================================================
	this.AlphaNumericOnly = function AlphaNumericOnly(evt, Callback)
	{
		try
		{
			var intKeyCode = evt.keyCode ? evt.keyCode : evt.which;

			// Check the keycode.
			if (intKeyCode == 13)
			{
				if (Callback != 'undefined')
					Callback(evt);
				
				if (evt.preventDefault)
					evt.returnValue = false;

				return false;
			}
			
			var blnValid = false;
			blnValid = (blnValid) ? blnValid : (intKeyCode == 32); // Space
			blnValid = (blnValid) ? blnValid : (intKeyCode == 46); // Full stop
			blnValid = (blnValid) ? blnValid : ((intKeyCode > 47) && (intKeyCode < 58)); // 0 - 9
			blnValid = (blnValid) ? blnValid : ((intKeyCode > 64) && (intKeyCode < 91)); // A - Z
			blnValid = (blnValid) ? blnValid : ((intKeyCode > 96) && (intKeyCode < 123)); // a - z
			
			if (!blnValid)
			{
				if (evt.preventDefault)
					evt.returnValue = false;

				return false;
			}
		}
		catch(exc)
		{
			WaitWindow.Hide();
			HtmlPopup.Error('AlphaNumericOnly():\n\n' + exc);
		}
		return;
	}

	//====================================================
	// Update a CSS style sheet reference.
	//====================================================
	this.UpdateCSS = function UpdateCSS(StyleSheetURL, ClassName, Styles)
	{
		try
		{
			// Change the width of the detail class.
			for(StyleSheet in document.styleSheets)
			{
				if (document.styleSheets[StyleSheet].href == undefined)
					continue;

				if (document.styleSheets[StyleSheet].href.toLowerCase().indexOf(StyleSheetURL) > 0)
				{
					var cssRules = (document.styleSheets[StyleSheet].rules == undefined) ? document.styleSheets[StyleSheet].cssRules : document.styleSheets[StyleSheet].rules;
					for(Rule in cssRules)
					{
						if (cssRules[Rule].selectorText == undefined)
							continue;

						if (cssRules[Rule].selectorText.toLowerCase() == ClassName.toLowerCase())
						{
							if ((BrowserDetect.browser == 'Explorer'))
							{
								document.styleSheets[StyleSheet].removeRule(Rule);
								document.styleSheets[StyleSheet].addRule(ClassName, Styles);
							}
							else
							{
								document.styleSheets[StyleSheet].deleteRule(Rule);
								document.styleSheets[StyleSheet].insertRule(ClassName + ' {' + Styles + '}', 0);
							}
							break;
						}
					}
					break;
				}
			}
		}
		catch(exc)
		{
			WaitWindow.Hide();
			HtmlPopup.Error('UpdateCSS():\n\n' + exc);
		}
		return;
	}
	
	//================================================
	// View the user's QR code
	//================================================
	this.btnViewQRCode_Click = function btnViewQRCode_Click(Value, Name)
	{
		try
		{
			Value = Value.replace(/,/gi, '|');

			THIS.ViewQRCodePopupWindow = new PopupWindowClass('<Data><Value>' + Value + '</Value><Name>' + Name + '</Name></Data>');
			THIS.ViewQRCodePopupWindow.Padder = 5;
			THIS.ViewQRCodePopupWindow.Open(null, THIS, 'ViewQRCode', THIS.ViewQRCode_Page_Load, THIS.ViewQRCode_btnOK_Click, undefined, 'QR Code', 358, 400, '/XSLT/QRCode.xslt');
		}
		catch(e)
		{
			WaitWindow.Hide();
			HtmlPopup.Error('btnViewQRCode_Click():\n\n' + e.message);
		}
		return;
	}
	
	//====================================================
	// View QR code page load handler.
	//====================================================
	this.ViewQRCode_Page_Load = function ViewQRCode_Page_Load(Sender, Parent, Callback)
	{
		try
		{
		}
		catch(e)
		{
			WaitWindow.Hide();
			HtmlPopup.Error('ViewQRCode_Page_Load():\n\n' + e.message);
		}
		return;
	}
	
	//====================================================
	// View QR code page load handler.
	//====================================================
	this.ViewQRCode_btnOK_Click = function ViewQRCode_btnOK_Click(Sender, Parent, Callback)
	{
		try
		{
			delete THIS.ViewQRCodePopupWindow;
		}
		catch(e)
		{
			WaitWindow.Hide();
			HtmlPopup.Error('ViewQRCode_btnOK_Click():\n\n' + e.message);
		}
		return true;
	}
	
	//====================================================
	// Process the response error from an AJAX call.
	//====================================================
	this.ResponseError = function ResponseError(ResponseError)
	{
		try
		{
			WaitWindow.Hide();

			// Check the response error.
			if (ResponseError.indexOf('There was a problem processing the request (12152)') > 0)
			{
				NavigateToHome();
				return;
			}
			
			if (ResponseError.indexOf('ERR002:You must be logged in to access this webservice') > 0)
			{
				NavigateToHome();
				return;
			}
			
			if (ResponseError == 'SessionEnd')
			{
				NavigateToHome();
				return;
			}
			
			// Display the error to the user.
			Functions.DisplayError(ResponseError);
		}
		catch(e)
		{
			WaitWindow.Hide();
			HtmlPopup.Error('ResponseError():\n\n' + e.message);
		}
		return true;
	}
	
	//==================================================
	// Proper case event handler.
	//==================================================
	this.ProperCase = function ProperCase(evt)
	{
		try
		{
			var objSourceElement = evt.srcElement ? evt.srcElement : evt.target;
			
			if (objSourceElement.value == '')
				return objSourceElement.value;

			objSourceElement.value = objSourceElement.value.toLowerCase();
			var strStrings = objSourceElement.value.split(' ');

			objSourceElement.value = "";

			for(var intCounter = 0; intCounter < strStrings.length; intCounter++)
			{
				if (strStrings[intCounter] == '')
					continue;

				if (objSourceElement.value != '')
					objSourceElement.value += ' ';

				objSourceElement.value += strStrings[intCounter].substring(0, 1).toUpperCase() + strStrings[intCounter].substring(1);
			}
			
			return;
		}
		catch (exc)
		{
			WaitWindow.Hide();
			HtmlPopup.Error(exc);
		}
		return true;
	}
	
	//==================================================
	// Transform a JSON object to XML.
	//==================================================
	this.JSONToXML = function JSONToXML(JSONObject)
	{
		var strXML = '<Data>';

		try
		{
			// Loop through the JSON object.
			for(Property in JSONObject)
			{
				// Check the property.
				if (Property != '')
					strXML += this.RecurseJSON(JSONObject, Property);
			}
		}
		catch (exc)
		{
			WaitWindow.Hide();
			HtmlPopup.Error(exc);
		}

		strXML += '</Data>';
		return strXML;
	}
	
	//==================================================
	// Recurse JSON objects.
	//==================================================
	this.RecurseJSON = function RecurseJSON(JSONObject, Property)
	{
		var strXML = '';

		try
		{
			// Check the property type.
			if (typeof(JSONObject[Property]) == 'object')
			{
				strXML += '<' + Property + '>';

				for(var intCounter = 0; intCounter < JSONObject[Property].length; intCounter++)
				{
					for(SubProperty in JSONObject[Property][intCounter])
					{
						strXML += '<' + SubProperty + '>';

						if (typeof(JSONObject[Property][intCounter][SubProperty]) == 'object')
						{
							strXML += this.RecurseJSON(JSONObject[Property][intCounter], SubProperty);
						}
						else
						{
							strXML += JSONObject[Property][intCounter][SubProperty];
						}
						strXML += '</' + SubProperty + '>';
					}
				}

				strXML += '</' + Property + '>'
			}
			else
			{
				strXML += '<' + Property + '>' + JSONObject[Property] + '</' + Property + '>'
			}
		}
		catch (exc)
		{
			WaitWindow.Hide();
			HtmlPopup.Error(exc);
		}

		return strXML;
	}

	return;
}
