/*****************************************************\
*** Common functions used to validate text fields.	***
*** Created: 06/03/2004 (J1WMDU0)					***
*** Updated: 10/14/2004 (J1WMDU0)					***
*** Updated: 05/24/2006 (J1WMD01)					***
\*****************************************************/

// <input type="text" name="txtNumber" TextEdit="Number">
// <input type="text" name="txtDate" TextEdit="Date">

function appendObjectEvent(obj, elementEvent, eventHandler, allowOnlyOne) 
{
	if (obj[elementEvent]) 
		if(!allowOnlyOne) obj[elementEvent] = new Function(obj[elementEvent].toString().replace(/[\r\n]/g, '').replace(/\s+$|^\s+/g, '').replace(/^function\s*\w+\s*\(\w*\)\s*\{\s*(.*)\s*\}$/, eventHandler + '\n$1'));
		else alert('WARNING: TextEdits.js is trying to override \n an event(' + elementEvent + ') on obj(' + obj.name + ').');
	else obj[elementEvent] = new Function(eventHandler);
}

var obj = document.getElementsByTagName('INPUT');
for(var i = 0; i < obj.length; i++)
{
	if(obj[i].TextEdit)
	{
		switch(obj[i].TextEdit)
		{
		case 'Number':
			appendObjectEvent(obj[i], 'onkeypress', 'return AllowPressed(event, [48,49,50,51,52,53,54,55,56,57]);', true); // [0123456789]
			appendObjectEvent(obj[i], 'onpaste', 'return RemoveFromPaste(event, /[^\\d]/g);', true);
			appendObjectEvent(obj[i], 'onkeyup', 'FormatNumber(this);');
			appendObjectEvent(obj[i], 'onchange', 'this.onkeyup();');
			break;
		case 'Decimal': // ("Precision" attribute is optional.)
			appendObjectEvent(obj[i], 'onkeypress', 'return AllowPressed(event, [46,48,49,50,51,52,53,54,55,56,57]);', true); // [.0123456789]
			appendObjectEvent(obj[i], 'onpaste', 'return RemoveFromPaste(event, /[^\\d.]/g);', true);
			appendObjectEvent(obj[i], 'onkeyup', 'FormatDecimal(event, this);');
			appendObjectEvent(obj[i], 'onchange', 'this.onkeyup();');
			break;
		case 'Date':
			appendObjectEvent(obj[i], 'onkeypress', 'return AllowPressed(event, [47,48,49,50,51,52,53,54,55,56,57]);', true); // [/0123456789]
			appendObjectEvent(obj[i], 'onpaste', 'return RemoveFromPaste(event, /[^\\d\\/]/g);', true);
			appendObjectEvent(obj[i], 'onkeyup', 'FormatDate(event, this);');
			appendObjectEvent(obj[i], 'onchange', 'this.onkeyup();');
			obj[i].maxLength = '10';
			break;
		case 'Phone':
			appendObjectEvent(obj[i], 'onkeypress', 'return AllowPressed(event, [48,49,50,51,52,53,54,55,56,57]);', true); // [0123456789]
			appendObjectEvent(obj[i], 'onpaste', 'return RemoveFromPaste(event, /[^\\d]/g);', true);
			appendObjectEvent(obj[i], 'onkeyup', 'FormatPhone(event, this);');
			appendObjectEvent(obj[i], 'onchange', 'this.onkeyup();');
			break;
		default:
			continue;
		}
		
		if(!obj[i].disabled && obj[i].value) // If the object has a value to validate...
			obj[i].onkeyup(); // Trigger validation of data in the field.
	}
}

/***************************************************************\
*** KeyPress Events (Prevent certain Keys from being pressed. ***
\***************************************************************/

function AllowPressed(e, arr) // OnKeyPress="return AllowPressed(event, [48,49,50,51,52,53,54,55,56,57]);"
{
	var charCode = (e ? (e.keyCode ? e.keyCode : (e.charCode ? e.charCode : e.which)) : null); // Capture the key that was pressed.
	if(charCode <= 31) return true; // Allow Standard Editing characters.
	for(var i = 0; i < arr.length; i++)
		if(charCode == arr[i]) return true; // If the keyCode is listed in the array, allow it.
	return false; // Otherwise, key is not allowed.
}

/************************************************************************************\
*** BeforePaste Events (Prevent bad from being pasted into certain types of data.) ***
\************************************************************************************/

function RemoveFromPaste(e, regexp) // OnPaste="RemoveFromPaste(event, /[^\d]/g);"
{
	var txt = ((e && e.target) ? e.target : window.event.srcElement); // Get current object.
	var cursor = getCursorPosition(txt); // Get current cursor position.
	var paste = window.clipboardData.getData('Text'); // Get the text (to be pasted) from the clipboard.
	paste = paste.replace(regexp, ''); // Remove all specified characters.
	document.selection.createRange().text = paste; // Paste value from clipboard in place of current selection.
	setCursorPosition(txt, cursor); // Set the cursor position back to where it should be.
	if(txt.onchange) txt.onchange(); // If an OnChange event exists, trigger it.
	return false; // Cancel system paste.
}

/***************************************************************\
*** KeyUp Events (Format controls for certain types of data.) ***
\***************************************************************/

function FormatNumber(txt) // OnKeyUp="FormatNumber(this);" OnChange="this.onkeyup();"
{
	var cursor = getCursorPosition(txt); // Get current cursor position.
	txt.value = txt.value.replace(/[^\d]/g, ''); // Remove all non-numeric characters.
	setCursorPosition(txt, cursor); // Set the cursor position back to where it should be.
}

function FormatDecimal(e, txt) // OnKeyUp="DecimalNumber(event, this);" OnChange="this.onkeyup();"
{
	var charCode = (e ? (e.keyCode ? e.keyCode : (e.charCode ? e.charCode : e.which)) : null); // Get ascii character value of the key that was pressed.
	if (charCode >= 35 && charCode <= 40) return; // If a navigation key was pressed (left, right, home, end, etc.), then skip format.
	var cursor = getCursorPosition(txt); // Get current cursor position.
	var commas = txt.value.split(',').length - 1; // Count the number of original commas.
	var value = txt.value.replace(/[^\d.]/g, ''); // Remove all non-numeric characters (but not the decimal point).
	var arr = value.split('.'); // Split the value on the decimal points.
	if(arr.length > 2) // If there is more than one decimal point...
		for(var i = 2; i < arr.length; i++) // Loop through the groups of numbers.
			arr[1] += arr[i]; // Piece the numbers back together, only leaving the first decimal point.
	if(arr[0].search(/^0+/) != -1) // If there are leading zeroes...
	{
		var len = arr[0].length; // Remember the current length for later.
		arr[0] = arr[0].replace(/^0+/, ''); // Remove leading zeroes.
		if(arr[0].length == 0) arr[0] = '0'; // If all the numbers are gone now, leave atleast one zero.
		cursor += arr[0].length - len; // Move the cursor back a number of spaces equal to the number of digits removed.
	}
	if(arr[0].length > 3) // If the first group of numbers has more than 3 digits...
	{
		var mod = (arr[0].length % 3); // Divide the number of digits by 3 and store the remainder.
		if(mod == 0) mod = 3; // If the remainder is 0, set it to 3.
		value = arr[0].substr(0, mod); // Set value equal to the remainder digits.
		for(var i = 0; ((i * 3) + mod) < arr[0].length; i++) // Loop through numbers in groups of 3.
			value += ',' + arr[0].substr(mod + (i * 3), 3); // Place a comma before a group of 3 digits.
		cursor += i - commas; // Move the cursor to correspond to changes in the number of commas.
	}
	else // Else...
	{
		value = arr[0]; // Add no commas.
		cursor -= commas; // Move the cursor to correspond to changes in the number of commas.
	}
	var precision = txt.Precision; // Get the Precision attribute from the TextBox.
	if(arr.length > 1 && (!precision || precision > 0)) // If a decimal point is required...
	{
		if(value.length == 0) // If there are no number before the decimal point...
		{
			value = '0'; // If there are no number before the decimal point, place a zero there.
			cursor++; // Increment the cursor position to reflect this change.
		}
		if(precision) arr[1] = arr[1].substr(0, parseInt(precision)); // If a precision is given, limit the number to the precision.
		value += '.' + arr[1]; // Add the decimal point, followed by the remaining numbers.
	}
	txt.value = value; // Reassign the value back to the textbox.
	setCursorPosition(txt, cursor); // Set the cursor position back to where it should be.
}

function FormatDate(e, txt) // OnKeyUp="FormatDate(event, this);" OnChange="this.onkeyup();"
{
	var charCode = (e ? (e.keyCode ? e.keyCode : (e.charCode ? e.charCode : e.which)) : null); // Get ascii character value of the key that was pressed.
	if (charCode >= 35 && charCode <= 40) return; // If a navigation key was pressed (left, right, home, end, etc.), then skip format.
	var cursor = getCursorPosition(txt); // Get current cusor position.
	var slashes = txt.value.match(/\//g); slashes = (slashes ? slashes.length : 0); // Get count of the number of slashes.
	var value = txt.value.split('/'); // Get array of number groups.
	for(var i = 0; i < value.length; i++) value[i] = value[i].replace(/[^\d]/g, ''); // Remove all non-numeric characters.
	var text = ''; // Initialize return text.
	if(value.length > 0) // If there is a first group of numbers...
	{
		if(value[0].length > 2) // If the first group of numbers are longer than 2 digits...
		{
			if(value[1]) value[1] = value[0].substr(2, 8) + value[1]; // If there is a second group of numbers, append the extra digits to that group of numbers.
			else value[1] = value[0].substr(2, 8); // Else, create a second group of numbers from the extra digits.
			value[0] = value[0].substr(0, 2); // Remove extra digits from first group.
			slashes++; // Add a slash for between the groups of numbers.
			if(cursor > 2) cursor++; // If the cursor is past the added slash, move the cursor also.
		}
		text = value[0]; // Add first number group to the formated text.
		
		if(slashes >= 1) text = text + '/'; // If a slash is needed, add it to the formated text.
		if(value.length > 1) // If there is a second group of numbers...
		{
			if(value[1].length > 2) // If the second group of numbers are longer than 2 digits...
			{
				if(value[2]) value[2] = value[1].substr(2, 8) + value[2]; // If there is a third group of numbers, append the extra digits to that group of numbers.
				else value[2] = value[1].substr(2, 8); // Else, create a third group of numbers from the extra digits.
				value[1] = value[1].substr(0, 2); // Remove extra digits from second group.
				slashes++; // Add a slash for between the groups of numbers.
				if(cursor > 4) cursor++; // If the cursor is past the added slash, move the cursor also.
			}
			text = text + value[1]; // Add second number group to the formated text.
			
			if(slashes >= 2) text = text + '/'; // If a slash is needed, add it to the formated text.
			if(value.length > 2) // If there is a third group of numbers...
			{
				if(value.length > 3) for(var i = 3; i < value.length; i++) value[2] += value[i]; // Capture all remaining numbers.
				if(value[2].length > 4) value[2] = value[2].substr(0, 4); // If the third group of numbers are longer than 4 digits, remove the extra digits.
				text = text + value[2]; // Add third number group to the formated text.
			}
		}
	}
	txt.value = text; // Set the TextBox value equal to the formated text.
	setCursorPosition(txt, cursor); // Set the cursor position back to where it should be.
	
	// Validate Date...
	if(text.search(/^\d{1,2}\/\d{1,2}\/(\d{2}|\d{4})$/) == -1) // If date is not formated correctly...
	{
		txt.errorMessage = 'Date is formated incorrectly.';
		txt.valid = false; // Set the "valid" flag on the control to false.
	}
	else // If date is formated correctly...
	{
		var month = parseInt(value[0], 10); //RemoveLeadingZero(value[0]);
		var day = parseInt(value[1], 10); //RemoveLeadingZero(value[1]);
		var year = parseInt(value[2], 10); //RemoveLeadingZero(value[2]);
		if(month < 1 || month > 12) // If month is less than 1 or greater than 12...
		{
			txt.errorMessage = 'Invalid month specified for date.';
			txt.valid = false; // Set the "valid" flag on the control to false.
		}
		else
		{
			var maxDay; // Used to store the number of days in the month.
			switch(month) 
			{
			case 1: maxDay = 31; break;
			case 2: maxDay = ((year%4==0 && (year%100!=0 || year%400==0)) ? 29 : 28 ); break; // Leap Year Calculation.
			case 3: maxDay = 31; break;
			case 4: maxDay = 30; break;
			case 5: maxDay = 31; break;
			case 6: maxDay = 30; break;
			case 7: maxDay = 31; break;
			case 8: maxDay = 31; break;
			case 9: maxDay = 30; break;
			case 10: maxDay = 31; break;
			case 11: maxDay = 30; break;
			case 12: maxDay = 31; break;
			}
			txt.valid = (day >= 1 && day <= maxDay); // If day is less than 1 or greater then the number of days in the given month...
			txt.errorMessage = (txt.valid ? '' : 'Invalid day specified for date.');
		}
	}
	txt.style.color = (txt.valid ? '' : 'red'); // If the date is valid, set color to default; else, set color to red.
}

function FormatPhone(e, txt) // OnKeyUp="FormatPhone(event, this);" OnChange="this.onkeyup();"
{
	var charCode = (e ? (e.keyCode ? e.keyCode : (e.charCode ? e.charCode : e.which)) : null); // Get ascii character value of the key that was pressed.
	if (charCode >= 35 && charCode <= 40) return; // If a navigation key was pressed (left, right, home, end, etc.), then skip format.
	var cursor = getCursorPosition(txt); // Get current cusor position.
	var charRemoved = txt.value.substr(0, cursor).match(/[^\d]/g); // Get the characters that will be removed before the cursor.
	charRemoved = (charRemoved ? charRemoved.length : 0); // Count the number of characters that will be removed, if any.
	var value = txt.value.replace(/[^\d]/g, ''); // Remove all non-numeric characters.
	if(value.length > 10) value = '(' + value.substr(0, 3) + ') ' + value.substr(3, 3) + '-' + value.substr(6, 4) + ' x' + value.substr(10, 6); // (999) 999-9999 x999999
	else if(value.length > 7) value = '(' + value.substr(0, 3) + ') ' + value.substr(3, 3) + '-' + value.substr(6, 4); // (999) 999-9999
	else if(value.length > 3) value = value.substr(0, 3) + '-' + value.substr(3, 4); // 999-9999
	txt.value = value; // Set the TextBox value equal to the formated text.
	var charAdded = value.substr(0, cursor).match(/[^\d]/g); // Get the characters that were added before the cursor.
	charAdded = (charAdded ? charAdded.length : 0); // Count the number of characters that were added, if any.
	var newCursor = cursor + charAdded - charRemoved; // Adjust cursor: based on the number of characters added, minus the number removed.
	while(value.substr(cursor, newCursor - cursor).match(/[^\d]/g)) // While there are non-numeric characters between cursor and newCursor...
	{
		charAdded = value.substr(cursor, newCursor - cursor).match(/[^\d]/g); // Get the extra added characters.
		cursor = newCursor; // Set cursor equal to newCursor.
		newCursor += charAdded.length; // Adjust cursor again based on the number of characters added between cursor and the new position.
	}
	cursor = newCursor; // Set cursor equal to the new-verified cursor position.
	setCursorPosition(txt, cursor); // Set the cursor position back to where it should be.
	
	// Validate Phone...
	if(value.match(/^\(\d{3}\)\s\d{3}-\d{4}/)) txt.valid = true; // (999) 999-9999 {x999999}
	else if(value.match(/^\d{3}-\d{4}$/)) txt.valid = true; // 999-9999
	else txt.valid = false; // Else, not valid.
	txt.style.color = (txt.valid ? '' : 'red'); // If the date is valid, set color to default; else, set color to red.
}

/*************************************************\
*** Functions used to maintain cursor position. ***
\*************************************************/

function getCursorPosition(txt)
{
	// get current selection. Object must have a focus at this time
	var currentRange = document.selection.createRange();
	var workRange = currentRange.duplicate();
	// select the whole contents and get 'all' selection
	txt.select();
	var allRange = document.selection.createRange();
	var len = 0;
	// move current selection to the start of object
	// note: we do not use text.length property since it's not equal to the caret actual position
	try
	{
		while(workRange.compareEndPoints("StartToStart",allRange) > 0)
		{
			workRange.moveStart("character",-1);
			len++;
		}
	}
	catch(e) {return 0;}
	// restore original selection, it was lost when we did select() thing
	currentRange.select()
	// len contains the caret position if no selection or selection start point offset if any
	return len;
}

function setCursorPosition(txt, number)
{
	/*try // Error Handling added, because this was causing an error sometimes when a page first loaded.  Used only for debugging purposes.
	{*/
		var range = txt.createTextRange();
		range.moveStart("character", number);
		range.collapse();
		range.select();
	/*}
	catch(e){alert(txt.id);}*/
}

/*********************\
*** Misc. Functions ***
\*********************/

// Created because parseInt() was returning 0 when parsing '08' and '09'.
/*function RemoveLeadingZero(str)
{
	if(str.substr(0, 1) == '0' && str.length > 1) str = str.substr(1, str.length);
	return parseInt(str);
}*/