/*	Copyright (c) 1996,2001 Picdar Technology Limited       All Rights Reserved
 *
 * 	This is UNPUBLISHED PROPRIETARY work of Picdar Technology Limited;
 * 	the contents of this file may not be disclosed to third parties, copied or
 * 	duplicated in any form, in whole or in part, without the prior written
 * 	permission of Picdar Technology Limited
 *
 *	Module   :	DateTime001.js
 *
 *	Synopsis :	JavaScript Common Code Date and Time Utils
 *
 *	Author   :	Many
 *
 */

/*
REQUIRES:
String001.js	
Forms001.js
*/

/* This function returns "intYear" in YYYY format.
*/

function FixUpYear(intYear)
	{
	if (intYear < 100)
		{
		var intCurrYear = GetCurrentYear();
		while (Math.abs(intYear - intCurrYear) > 50)
			intYear += 100;
		}	
	return intYear;
	}
	
/* This function gets the current year and fixes the javascript year anomoly, 
where years < 2000 are as two digits e.g. 1998 --> 98 and on some browsers, years >= 2000
are 3 digits. e.g. 2001 --> 101.
*/
		
function GetCurrentYear()
	{
	dateCurrent = new Date();
	
	intCurrYear = dateCurrent.getYear();
	if (intCurrYear < 1000)
		intCurrYear += 1900;
	
	return intCurrYear
	}

/* 	This function return the separator used in a date string. 
	The valid seperators are...
		-
		/
		\
		<space>
		.
	If "strDate" is found not to be a valid date, "NOTVALID" is returned.

	This function accommodates ambiguous dates (e.g. 02/2002), and so thus applies 3
	different regexps in turn:
	
	myRegExpDMY		- checking for full dd/mm/yyyy dates
	myRegExpMY		- checking for partial mm/yyyy dates
	myRegExpY		- checking for partial yyyy dates	(default to '/' as a separator)
*/

function GetSeparator(strDate,boolAmbigDate)
	{
	var myRegExpDMY = /^\s*\d{1,2}([\.\-\/\\ ])\d{1,2}\1\d{1,4}\s*$/;
	var myRegExpMY = /^\s*\d{1,2}([\.\-\/\\ ])\d{1,4}\s*$/;
	var myRegExpY = /^\s*\d{1,4}\s*$/;
	
	var result = "NOTVALID";
	if (myRegExpDMY.test(strDate))
		{	/* full date */
		var results = strDate.match(myRegExpDMY);
		result = results[1];
		}
	else if (boolAmbigDate)
		{
		if (myRegExpMY.test(strDate))
		{	/* ambig date - month and year only */
		var results = strDate.match(myRegExpMY);
		result = results[1];
		}
	else if (myRegExpY.test(strDate))
		{	/* ambig date - year only */
		result = "/";
		}		
		}	
	return result;
	}


/* This function determines whether "strTime" is in 24-hour clock format or 12-hour clock format.
	It returns:
		"NOTVALID"	if it is not a valid time.
		"a"			if it is in 12-hour format am.
		"p"			if it is in 12-hour format pm.
		"24HOUR"	if it is in 24-hour format.		
*/

function GetTimeFormat(strTime)
	{
	var result = "NOTVALID";
	var results = "";
	var hour12RegExp = /^\s*\d{1,2}:\d{1,2}(:\d{1,2})?\s*(a|p)\.?m?\.?\s*$/i
	var hour24RegExp = /^\s*\d{1,2}:\d{1,2}(:\d{1,2})?\s*$/
	
	if (hour12RegExp.test(strTime))
		{
		results = strTime.match(hour12RegExp);
		result = results[2].toLowerCase();
		}
	else if (hour24RegExp.test(strTime))
		result = "24HOUR";
	return result
	}

/* This function returns true if "intDay" is a valid day of "intMonth" in "intYear".
	This function is aware of Leap years.
*/	

function IsValidDay(intDay,intMonth,intYear)
	{
	var result = false;
	var monthLengths = new Array(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	
	if (((intYear % 4 == 0) && (intYear % 100 != 0)) || (intYear % 400 == 0))
		{
		monthLengths[2] = 29;
		}
		
	if (intDay >= 1 && intDay <= monthLengths[intMonth])
		result = true
		
	return result;
	}

/* This function returns true if "intMonth" is a valid month. 
*/

function IsValidMonth(intMonth)
	{
	var result = false;
	if (intMonth >= 1 && intMonth <=12)
		result = true;
	return result;
	}

/* 	These functions returns true if "objDateField" is a valid AMBIGUOUS date.
	If "boolAlert" is true, an alert will be displayed if the date is invalid.
	"strDescription" is used to describe the input field to the user if it is invalid when the form is submitted.
	If it is a valid date, then it is converted to the format: DD/MM/YYYY
	
	An ambigupus date is one which is not fully specified.
		e.g. 02/2002 = Feb 2002
	
	These types of date are expanded so that an appropriate full date is generated.
	The expansion can be either backwards or forwards, depending on whether the date specified is a 'start' date
	or and 'end' date.  e.g.
		start date = 06/03	= 01/06/2003
		start date = 03		= 01/01/2003
		start date = AAA	= invalid date
		end date = 06/03	= 30/06/2003
		end date = 03		= 31/12/2003
		end date = 02/00	= 29/02/2000
	
	ValidateAmbigStartDate and ValidateAmbigEndDate are provided for validating start and end dates.
	Both functions bottleneck through ValidateAmbigDate, passing an appropriate flag value.
*/


/* validate an ambiguous start-date
 */
function ValidateAmbigStartDate(objDateField,boolAlert,strDescription)
	{
	return ValidateAmbigDate(objDateField,boolAlert,strDescription,true);
	}

/* validate an ambiguous end-date
 */
function ValidateAmbigEndDate(objDateField,boolAlert,strDescription)
	{
	return ValidateAmbigDate(objDateField,boolAlert,strDescription,false);
	}

/* validate and expand an ambiguous date - one which is not fully specified.
	e.g. 02/2002 = Feb 2002
 */	
function ValidateAmbigDate(objDateField,boolAlert,strDescription,boolStartDate)
	{
	var arrMonthNames = new  Array('','January','February','March','April','May','June','July','August','September','October','November','December');
	var arrMonthDays = new  Array('','31','28','31','30','31','30','31','31','30','31','30','31');
	var strReason = "";
	var strDate = objDateField.value;
	var IsValid = true;
	var strSeparator = GetSeparator(strDate,true);
	var arrDate = new Array();

	if (IsEmpty(strDate))
		IsValid = true;
	else if (strSeparator == "NOTVALID")
		{
		IsValid = false;
		strReason = "The date is not in the correct format.";
		}
	else
		{
		arrDate = strDate.split(strSeparator);
		intDay = 0;
		intMonth = 0;
		intYear = 0;
	
		if (arrDate.length == 3)
			{
			/* a full date, so use the old validation procedure */
			IsValid = ValidateDate(objDateField,boolAlert,strDescription);
			}
		else
			{
			if (arrDate.length == 2)
				{
				/* month and year only */
				intMonth = TrimArrayDateValue(arrDate,0);
				intYear = ExpandYear(arrDate,1);
				}
			else if (arrDate.length == 1)
				{
				/* year only */
				intYear = ExpandYear(arrDate,0);
				}
			
			if (intMonth == 0)
				{
				/* if no month specified then make one up */
				if (boolStartDate)
					intMonth = 1;
				else
					intMonth = 12;
				}
			
			if (!IsValidMonth(intMonth))
				{
				IsValid = false;
				strReason = intMonth + " is not a valid month.";
				}
			else if (intDay == 0)
				{
				/* if no day specified then add one in */
				if (boolStartDate)
					intDay = 1;
				else if (intMonth != 2)					/* February and leap years */
					intDay = arrMonthDays[intMonth];	/* are the usual P.I.T.A.! */
				else if (((intYear % 4 == 0) && (intYear % 100 != 0)) || (intYear % 400 == 0))
					intDay = 29;
				else
					intDay = 28;
				}
			}
		}
	if (!IsValid)
		{
		if (boolAlert && strReason != "")
			alert("The date \"" + strDate + "\" is invalid because:\n" + strReason +"\nPlease enter the date as either dd/mm/yyyy, mm/yyyy or yyyy.");
		objDateField.focus();
		}
	else if (!IsEmpty(strDate))
		{
		/* fill the input with the new date */
		var strDay = new String(intDay);
		var strMonth = new String(intMonth);
		var strYear = new String(intYear);
		strDay = StringPadLeft(strDay,"0",2);
		strMonth = StringPadLeft(strMonth,"0",2);
		strYear = StringPadLeft(strYear,"0",4);
		var strNewDate = strDay + "/" + strMonth + "/" + strYear;
		objDateField.value = strNewDate;
		}
	return IsValid;
	}

/* ***** end of ambiguous date functions ***** */

/* 	This function returns true if "objDateField" is a valid date. 
	If "boolAlert" is true, an alert will be displayed if the date is invalid.
	"strDescription" is used to describe the input field to the user if it is invalid when the form is submitted.
	If it is a valid date, then it is converted to the format: DD/MM/YYYY
*/
function ValidateDate(objDateField,boolAlert,strDescription)
	{
	var arrMonthNames = new  Array('','January','February','March','April','May','June','July','August','September','October','November','December');
	var strReason = "";
	var strDate = objDateField.value;
	var IsValid = true;
	var strSeparator = GetSeparator(strDate,false);
	var arrDate = new Array();
	
	if (IsEmpty(strDate))
		IsValid = true;
	else if (strSeparator == "NOTVALID")
		{
		IsValid = false;
		strReason = "The date is not in the correct format.";
		}
	else
		{
		arrDate = strDate.split(strSeparator);
		
		intDay = TrimArrayDateValue(arrDate,0);
		intMonth = TrimArrayDateValue(arrDate,1);
		intYear = ExpandYear(arrDate,2);		

		if (!IsValidMonth(intMonth))
			{
			IsValid = false;
			strReason = intMonth + " is not a valid month.";
			}
		else if (!IsValidDay(intDay,intMonth,intYear))
			{
			IsValid = false;
			var strYear = new String(intYear);
			strYear = StringPadLeft(strYear,"0",4);
			strReason = intDay + " is not a valid day of " + arrMonthNames[intMonth];
			strReason += " " + strYear + ".";
			}
		}
	if (!IsValid)
		{
		if (boolAlert) alert("The date \"" + strDate + "\" is invalid because:\n" + strReason +"\nPlease enter the date in the form dd/mm/yyyy.");
		}
	else if (!IsEmpty(strDate))
		{
		var strDay = new String(intDay);
		var strMonth = new String(intMonth);
		var strYear = new String(intYear);
		strDay = StringPadLeft(strDay,"0",2);
		strMonth = StringPadLeft(strMonth,"0",2);
		strYear = StringPadLeft(strYear,"0",4);
		var strNewDate = strDay + "/" + strMonth + "/" + strYear;
		objDateField.value = strNewDate;
		}
	return IsValid;
	}
	
/* 	This function returns true if "objTimeField" is a valid time. 
	If "boolAlert" is true, an alert will be displayed if the time is invalid.
	"strDescription" is used to describe the input field to the user if it is invalid when the form is submitted.
	If it is a valid time, then it is converted to the format:-  HH:MM (24-hour).
*/

function ValidateTime(objTimeField,boolAlert,strDescription)
	{
	var strReason = "";
	var IsValid = true;
	var strTime = objTimeField.value;
	var strFormat = "";
	var intHours = 0;
	var intMinutes = 0;
	var intSeconds = 0;
	if (IsEmpty(strTime))
		;  //Blank values are valid.
	else 
		{
		strFormat = GetTimeFormat(strTime);
		if (strFormat == "NOTVALID")
			{
			IsValid = false;
			strReason = "The time is not in the correct format.";
			}
		else
			{
			arrTime = strTime.split(":");
			
			arrTime[0] = StringTrimLeft(arrTime[0],"0");
			if (arrTime[0] == "") arrTime[0] = "0";
			intHours = parseInt(arrTime[0]);
			
			arrTime[1] = StringTrimLeft(arrTime[1]);
			if (arrTime[1] == "") arrTime[1] = "0";
			intMinutes = parseInt(arrTime[1]);
			
			if (arrTime[2])
				{
				arrTime[2] = StringTrimLeft(arrTime[2],"0");
				if (arrTime[2] == "") arrTime[2] = 0;
				intSeconds = parseInt(arrTime[2]);
				}
			if (!(intMinutes >= 0 && intMinutes <= 59))
				{
 				IsValid = false;
 				strReason = "The value \"" + intMinutes + "\" is not a valid minute."
 				}
 			else if (!(intSeconds >= 0 && intSeconds <= 59))
				{
 				IsValid = false;
 				strReason = "The value \"" + intSeconds + "\" is not a valid second."
 				}			
 			else if (!(intHours >= 0 && intHours <= 23))
				{
 				IsValid = false;
 				strReason = "The value \"" + intHours + "\" is not a valid hour."
 				}			
			else if (intHours > 12 && strFormat == "a")
				{
				IsValid = false;
				strReason = "You have entered an hour greater than 12, but specified a.m."
				}
			else
				{
				if (strFormat == "a" && intHours == 12)
					intHours = 0;
				if (strFormat == "p" && intHours < 12)
					intHours += 12;
				}
			}
		}
	if (!IsValid)
		{
		if (boolAlert)
			alert("The time \"" + strTime + "\" is invalid because:\n" + strReason +"\nPlease enter the time in the form HH:MM:SS.");
		else
			;
		}
	else if (!IsEmpty(strTime))
		{
		var strHours = new String(intHours);
		var strMinutes = new String(intMinutes);
		var strSeconds = new String(intSeconds);
			
		strHours = StringPadLeft(strHours,"0",2);
		strMinutes = StringPadLeft(strMinutes,"0",2);
		strSeconds = StringPadLeft(strSeconds,"0",2);
		
		var strNewDate = strHours + ":" + strMinutes + ":" + strSeconds;
		objTimeField.value = strNewDate;
		}
	return IsValid;
	}	

/* trims a date-array value, removing leading zeroes, and returns the integer value
	(factored out code into this procedure)
 */
function TrimArrayDateValue(arrDate,index)
	{
	arrDate[index] = StringTrimLeft(arrDate[index],"0");
	if (arrDate[index] == "") arrDate[index] = "0";
	return parseInt(arrDate[index]);
	}

/* Expand a year within a date-value array removing leading zeroes, and returns the integer value
	(factored out code into this procedure)
 */
function ExpandYear(arrDate,index)
	{
	var intYear;
	if (arrDate[index].length <= 2) 
		{
		arrDate[index] = StringTrimLeft(arrDate[index],"0"); // otherwise it thinks its octal!!
		if (arrDate[index] == "") arrDate[index] = "0";
		intYear = FixUpYear(parseInt(arrDate[index]));
		}
	else 
		{
		arrDate[2] = StringTrimLeft(arrDate[index],"0"); // otherwise it thinks its octal!!
		if (arrDate[2] == "") arrDate[index] = "0";
		intYear = parseInt(arrDate[index]);
		}
	return intYear;
	}
