
/***************************************************************************
@func	DTE_updateDateSelection(fieldname, form)
@author	Graham Pearson
@desc	Performs validation on date fields and updates Day field if it is outside the valid range
@desc	Only ever used in conjunction with OutputDateSelect (incUtility.asp)
@param	fieldname	name of date field created by OutputDateSelect
@param	form		form object in which the date field was created
***************************************************************************/
function DTE_updateDateSelection(fieldname, form) {
	//set the day to the day selected in the form
	var intDay = eval('form.'+fieldname+'day.options[form.'+fieldname+'day.selectedIndex].value;');
	
	//do the same with the month selection
	var intMonth = eval('form.'+fieldname+'month.options[form.'+fieldname+'month.selectedIndex].value;');
	
	//if the year is a select list
	if (eval('form.'+fieldname+'year.type == \'select-one\'')) { 
		//set the year to the selected value
		var intYear = eval('form.'+fieldname+'year.options[form.'+fieldname+'year.selectedIndex].value;'); 
	} else { 
		// otherwise the year is a text field - set the value to the value entered
		var intYear = eval('form.'+fieldname+'year.value;');
		if (VAL_validateNumber(intYear,1,'0','50','0','0')) {
			intYear = 2000+intYear*1;
			eval('form.'+fieldname+'year.value = '+intYear.toString());
		} else if (VAL_validateNumber(intYear,1,'51','99','0','0')) {
			intYear = 1900+intYear*1;
			eval('form.'+fieldname+'year.value = '+intYear.toString());
		}
	}
	
	//if the first day selection is blank (because the date is optional, we have to set an 'adjustment' value
	//to true, otherwise, it's set to false. this is used to correctly select the day field if it is out of range
	var blnAdj = eval('form.'+fieldname+'day.options[0].value == \'\';');
	
	//if all three date parts are entered, we perform some validation on the date
	if (intMonth != '' && intYear != '' && intDay != '') {
	
		// if the month is a 30-day month, but the day selected is > 30
		if ((intMonth == 4 || intMonth == 6 || intMonth == 9 || intMonth == 11) && intDay > 30) {
			//set the day selection to the 30th (note the use of adj incase the first option is a blank row
			//we will want to set option 30 rather than 29 (remember this is base 0 so option 29 with no
			//initial blank row has the value '30', and option 29 with an initial blank row has the value '29'
			eval('form.'+fieldname+'day.selectedIndex = 29 + 1*(blnAdj)'); 
			//also reset the day value to 30
			intDay=30;
		}
		
		//if the month is feb and year is a leap year (strictly speaking this should be adjusted to ensure that
		//2100 is not counted as a leap year
		if (intMonth == 2 && intYear%4 == 0  && intDay > 29) { 
			//reset the day selection and day value as above
			eval('form.'+fieldname+'day.selectedIndex = 28 + 1*(blnAdj)'); 
			intDay=29;
		}
		//if the month is feb and year is NOT a leap year (strictly speaking this should be adjusted to ensure that
		//2100 is not counted as a leap year
		if (intMonth == 2 && intYear%4 != 0  && intDay > 28) {
			//reset the day selection and day value as above
			eval('form.'+fieldname+'day.selectedIndex = 27 + 1*(blnAdj)'); 
			intDay=28;
		}
		//finally set the hidden form field with the name given by fieldname to the value of the date entered
		//note that this value may still be invalid in the case that the year field is a text entry field
		//and the user has entered an invalid value - e.g. 'ABCD'
		eval('form.'+fieldname+'.value = \''+intDay+'/'+DTE_monthName(intMonth,0)+'/'+intYear+'\'');
	} else {
		//if not all date parts have been entered / selected set the hidden form field to an enpty string
		eval('form.'+fieldname+'.value = \'\'');
	}
}


/***************************************************************************
@func	DTE_monthName(intMonth, blnLongFormat)
@author	Graham Pearson
@desc	Returns either the full name of the month or the three letter version of the month 
	indicated by the integer passed in
@param	intMonth	the month between 1 and 12
@param	blnLongFormat	if = 1 then return the full name of the month, other wise return the short form
***************************************************************************/
function DTE_monthName(intMonth, blnLongFormat) {
	var strMonthName = '';
	
	// set the month name depending on the integer passed in
	switch (intMonth) {
		case '1':	strMonthName = 'January'; break;
		case '2':	strMonthName = 'February'; break;
		case '3':	strMonthName = 'March'; break;
		case '4':	strMonthName = 'April'; break;
		case '5':	strMonthName = 'May'; break;
		case '6':	strMonthName = 'June'; break;
		case '7':	strMonthName = 'July'; break;
		case '8':	strMonthName = 'August'; break;
		case '9':	strMonthName = 'September'; break;
		case '10':	strMonthName = 'October'; break;
		case '11':	strMonthName = 'November'; break;
		case '12':	strMonthName = 'December'; break;
		default:	strMonthName = 'NOTAMONTH'; break;	/*this will cause an error if we manipulate
									the date later on, but if the month is
									not in the range 1-12 we've got something
									wrong anyway and this may help us to debug*/
	}
	
	// if the Long format is not required the set the month name to just the first three letters
	if (!blnLongFormat) strMonthName = strMonthName.substring(0,3);
	
	// return the string
	return strMonthName;
}

/***************************************************************************
@func	DTE_monthNum(strMonth)
@author	Graham Pearson
@desc	Returns the integer (base zero) of the month name passed in (the reverse of the function above)
@param	strMonth	the month name
***************************************************************************/
function DTE_monthNum(strMonth) {
	var intMonth;
	
	// set the month name depending on the integer passed in
	switch (strMonth.substring(0,3)) {
		case 'Jan':	intMonth = 0; break;
		case 'Feb':	intMonth = 1; break;
		case 'Mar':	intMonth = 2; break;
		case 'Apr':	intMonth = 3; break;
		case 'May':	intMonth = 4; break;
		case 'Jun':	intMonth = 5; break;
		case 'Jul':	intMonth = 6; break;
		case 'Aug':	intMonth = 7; break;
		case 'Sep':	intMonth = 8; break;
		case 'Oct':	intMonth = 9; break;
		case 'Nov':	intMonth = 10; break;
		case 'Dec':	intMonth = 11; break;
		default:	intMonth = 'NOTAMONTH'; break;		/*this will cause an error if we manipulate
									the date later on, but if the month is
									not in the range 0-11 we've got something
									wrong anyway and this may help us to debug*/
	}
	
	// return the month number
	return intMonth;
}


/***************************************************************************
@func	DTE_validateDate(strValue,blnFuture,blnPast,blnIncludeToday)
@author	Graham Pearson
@desc	Validates that a string is a valid date
	just needs to validate that it's in the form d(d)/Mmm/yyyy
@param	strValue	String reporesting the date
***************************************************************************/
function DTE_validateDate(strValue,blnFuture,blnPast) {			
	var strDay, strMonth, strYear	// variables to hold the date parts
	var blnReturn = true;		// return value - assume date is valid to begin with
	var dteNow = new Date();	//used to compare the date passed in with the current date

	// if the date is in the format d/mmm/yyyy (single digit day) then split the date into parts using the first method
	if (strValue.substring(1,2) == '/') {
		strDay = strValue.substring(0,1);
		strMonth = strValue.substring(2,5);
		strYear = strValue.substring(6,10);

	// otherwise the date must be in format dd/mmm/yyyy (two-digit day)
	} else {
		strDay = strValue.substring(0,2);
		strMonth = strValue.substring(3,6);
		strYear = strValue.substring(7,11);
	}
	
	//check that the month is one of the valid 3letter month strings
	if (!VAL_validateWithPattern(strMonth,'Jan\|Feb\|Mar\|Apr\|May\|Jun\|Jul\|Aug\|Sep\|Nov\|Dec')) blnReturn = false;
	
	//check the the day is between 1 and 99 (note that we don't use VAL_validateNumber as whole numbers include 1.0
	//which we don't want to allow here
	if (!VAL_validateWithPattern(strDay,'^[1-9][0-9]?$')) blnReturn = false;
	
	//similarly chech the year value
	if (!VAL_validateWithPattern(strYear,'^[0-9][0-9][0-9]?[0-9]?$')) blnReturn = false;

	// also check that the year is either 2 or 4 digits and between 1753 and 3000 (if four digits)
	if (blnReturn) {
		if (!(VAL_validateNumber(strYear,1,'0','99','0','0') ||
			VAL_validateNumber(strYear,1,'1753','3000','0','0'))) blnReturn = false;
	}
	
	//if the blnFuture or blnPast flags have been set also compare the date with the current date
	//note the user of DTE_monthNum(strMonth) which accepts the month name in 3 letter format and returns the month
	//number in base 0 - e.g. DTE_monthNum('Dec') returns 11
	if (blnReturn) {
		var dteDate = new Date(strYear, DTE_monthNum(strMonth), strDay);
		if (blnFuture && dteDate < dteNow) { blnReturn = false; }
		if (blnPast && dteDate > dteNow) { blnReturn = false; }
	}

	return blnReturn;
}


/***************************************************************************
@func	DTE_compareDate(objDate1,objDate2,blnAllowEqual,strError,arrError)
@author	Graham Pearson
@desc	Validates that a objDate1 is earlier (or equal to if blnAllowEqual=1) than objDate2
	and adds strError to the arrError array if not (as per VAL_validate() function
@param	objDate1	name of 1st Date field
@param	objDate2	name of 2nd Date field
@param	blnAllowEqual	flag indicating whether or not to allow the dates to be equal
@param	strError	error string to add to the error array if validation fails
@param	arrError	error array
***************************************************************************/
function DTE_compareDate(objDate1, objDate2, blnAllowEqual, strError, arrError) {			
	var strDay1, strMonth1, strYear1	// variables to hold the date parts
	var strDay2, strMonth2, strYear2	// variables to hold the date parts
	var blnValid = true;


	//first check that the two dates are valid
	if (DTE_validateDate(objDate1.value,0,0) && DTE_validateDate(objDate2.value,0,0)) {
	
		// if the date is in the format d/mmm/yyyy (single digit day) then split the date into parts using the first method
		if (objDate1.value.substring(1,2) == '/') {
			strDay1 = objDate1.value.substring(0,1);
			strMonth1 = objDate1.value.substring(2,5);
			strYear1 = objDate1.value.substring(6,10);

		// otherwise the date must be in format dd/mmm/yyyy (two-digit day)
		} else {
			strDay1 = objDate1.value.substring(0,2);
			strMonth1 = objDate1.value.substring(3,6);
			strYear1 = objDate1.value.substring(7,11);
		}

		//repeat for the second date
		// if the date is in the format d/mmm/yyyy (single digit day) then split the date into parts using the first method
		if (objDate2.value.substring(1,2) == '/') {
			strDay2 = objDate2.value.substring(0,1);
			strMonth2 = objDate2.value.substring(2,5);
			strYear2 = objDate2.value.substring(6,10);

		// otherwise the date must be in format dd/mmm/yyyy (two-digit day)
		} else {
			strDay2 = objDate2.value.substring(0,2);
			strMonth2 = objDate2.value.substring(3,6);
			strYear2 = objDate2.value.substring(7,11);
		}

		//compare the two dates
		var dteDate1 = new Date(strYear1, DTE_monthNum(strMonth1), strDay1);
		var dteDate2 = new Date(strYear2, DTE_monthNum(strMonth2), strDay2);
		if 	(dteDate1 > dteDate2 || 
			(dteDate1 - dteDate2 == 0 && blnAllowEqual == 0)) { blnValid = false; }
	}
	if (!blnValid) {
		VAL_addError(objDate2, strError, arrError);
	}
}

/***************************************************************************
@func	DTE_DateDiff(strInterval,dt1, dt2)
@author	Graham Pearson
@desc	returns the difference between dt1 and dt2 in terms of strInterval
	strInterval can be 'd'ay, 'w'onth, 'h'our, 'm'nute
@param	strInterval
@param	dt1		DateFrom
@param	dt2		DateTo
***************************************************************************/
function DTE_DateDiff(strInterval, dt1, dt2) {

	var iSec = Math.round((dt2 - dt1 + 1000)/1000);
	var iReturn = 0;

	switch (strInterval) {
		case 'd': iReturn = Math.round(iSec / (60*60*24)); break;
		case 'w': iReturn = Math.round(iSec / (60*60*24*7)); break;
		case 'h': iReturn = Math.round(iSec / (60*60)); break;
		case 'm': iReturn = Math.round(iSec / (60)); break;
		default: iReturn = 'NOT A VALID INTERVAL'; break;
	}
	return iReturn;
}
