////////////////////////////////////////////////////////////////////////////////////////////
// date_functions_<version>.js
//
// Contains handy GENERIC date manipulation functions we come up with. Available to all screens.
// Each modification needs to be commented in the history below.
// Each modification requires this file be saved as a new version (incremental filename), and should be referenced in the 
// includes/html/javascripts.asp include file.
////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////
// Modification History:
// Version	Date		Initials	Comments
// v1.00	dd/mm/yyyy	???			Initial release.
// v1.01	dd/mm/yyyy	???			???
// v1.02	12/06/2008	SBH			Aborted attempt to add hours support to dateAdd routine. Leaving in place as the mods
//									at least pave the way for the technical solution - there's a case branch for it now!
// v1.03	24/07/2008	SBH			Added fn*ConvertToDate function.
// v1.04	17/09/2008	MET			Added fnCompareSequentialDates function.
// v1.05	30/10/2008	SBH			Added fnDateDiff and fnLastDayInMonth functions.
////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
--------------------------------------------------------------------------------------------------------
User defined function: 	Emulates core functionality of vbscript DateDiff() function. SBH:28/10/2008
Parameters:	
	datepart:		interval type - "d"=days, "m"=months
	date 1:			first date in range - date or "dd/mm/yyyy" formatted string
	date 2:			second date in range - date or "dd/mm/yyyy" formatted string
--------------------------------------------------------------------------------------------------------
*/
function fnDateDiff(paramDatePart, paramDate1, paramDate2) {
	var dDate1 = paramDate1;
	var dDate2 = paramDate2;
	var iDateDiffRaw, iDateDiffFinal;
	var strMarker = "";
	var iDD, iMM, iYYYY;
	
	if (typeof(dDate1) == "string") {
		dDate1 = fnConvertToDate(dDate1);
	}
	if (typeof(dDate2) == "string") {
		dDate2 = fnConvertToDate(dDate2);
	}

	iDateDiffRaw = dDate2 - dDate1;
	iDateDiffFinal = iDateDiffRaw;	//initialise as milliseconds

	//now convert to required uom:
	switch(paramDatePart) {
	case "d":
		iDateDiffFinal = iDateDiffFinal/1000;
		iDateDiffFinal = iDateDiffFinal/60;
		iDateDiffFinal = iDateDiffFinal/60;
		iDateDiffFinal = iDateDiffFinal/24;
		break;
	case "m":
		//set a working date variable, initialise as start date
		var dWorkingDate = dDate1;

		//iterate a loop, setting the working date to working date + 1 month
		var iIncrementCount = 0;
		var iInitialMonthIndex = dDate1.getMonth();
		var iIncrementMonthTo;
		var iNewDayOfMonth, iOriginalDayOfMonth;
		var iNewMonth, iOriginalMonth, iPrevMonth;
		var iLastAvailableDay;

		iIncrementMonthTo = iInitialMonthIndex;
		iOriginalDayOfMonth = dDate1.getDate();
		iOriginalMonth = dDate1.getMonth();
		iPrevMonth = iOriginalMonth;
		//alert ("iOriginalDayOfMonth=" + iOriginalDayOfMonth + ", iOriginalMonth=" + iOriginalMonth);
		
		while (dWorkingDate <= dDate2) {
			//adjust for year rollover
			if (iIncrementMonthTo > 11) {
				iIncrementMonthTo = iIncrementMonthTo - 12;
				dWorkingDate.setYear(dWorkingDate.getYear() + 1);
			}
			//alert("pre: loop " + iIncrementCount + ": working date=" + dWorkingDate + " vs date2=" + dDate2);
			
			//standard action:
			iPrevMonth = dWorkingDate.getMonth();
			dWorkingDate.setMonth(iIncrementMonthTo);

			//month rollover adjustment:
			//if new month > prev month+1 then
			//	set date to last day in the prev month
			//end if
			iNewMonth = dWorkingDate.getMonth();
			iNewDayOfMonth = dWorkingDate.getDate();
			//alert("iNewMonth=" + iNewMonth + ", iPrevMonth=" + iPrevMonth);
			if (iNewMonth > (iPrevMonth+1)) {
				//alert("triggered");
				dWorkingDate.setMonth(iNewMonth-1);
				dWorkingDate.setDate(fnLastDayInMonth(dWorkingDate.getMonth(), dWorkingDate.getYear()));
			}
			
			//adjust for possible lost days on the prev loop:
			//if new day < original day then
			//	see if the original day is available to the current month
			//	if so, set it as such
			//	otherwise, set it as last available day
			//end if
			iNewDayOfMonth = dWorkingDate.getDate();
			if (iNewDayOfMonth - iOriginalDayOfMonth != 0) {
				iLastAvailableDay = fnLastDayInMonth(dWorkingDate.getMonth(), dWorkingDate.getYear());
				if (iLastAvailableDay >= iOriginalDayOfMonth) {
					dWorkingDate.setDate(iOriginalDayOfMonth);
				}
				else {
					dWorkingDate.setDate(iLastAvailableDay);
				}
			}
						
			//alert("post: loop " + iIncrementCount + ": working date=" + dWorkingDate + " vs date2=" + dDate2);
			if (dWorkingDate - dDate2 == 0) {
				//alert("date 2 reached");
				break;
			}
			if (dWorkingDate > dDate2) {
				//alert("date 2 exceeded");
				iIncrementCount--;
				strMarker = "+";
				break;
			}
			iIncrementCount ++;
			iIncrementMonthTo++;
						
			//escape clause:
			if (iIncrementCount > 100) {
				alert("error encountered, exiting loop");
				return false;
			}
		}
		iDateDiffFinal = iIncrementCount;
		break;
	}
	return iDateDiffFinal + strMarker;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
--------------------------------------------------------------------------------------------------------
User defined function: 	Returns the last day in specified month, for specified year. SBH:30/10/2008
Parameters:	
	monthindex:		zero-based month (0=jan, 1=dec)
	year:			four digit year specifier expressed as a NUMERIC datetype.
--------------------------------------------------------------------------------------------------------
*/
function fnLastDayInMonth(paramMonthIndex, paramYear) {
	var iStartDay = 28;
	var iWorkDay = iStartDay;
	var iLastDayInMonth;
	var dWorkDate = new Date(paramYear, paramMonthIndex, iStartDay);
	while (dWorkDate.getMonth() - paramMonthIndex == 0) {
		iLastDayInMonth = iWorkDay;
		iWorkDay = iWorkDay + 1;
		dWorkDate.setDate(iWorkDay);
	}
	return iLastDayInMonth;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


//##########################################################################################################		
/*
--------------------------------------------------------------------------------------------------------
User defined function: 	Emulates vbscript DateAdd() function. JETS:30/11/2005
Parameters:	
	start:			mm/dd/yyyy date format as string
	interval:		"d"=days, "h"=hours, "n"=months, "m"=minutes, "s"=seconds
	number:			integer value of number of units to add, eg, ("02/26/1975","d",1) will result 02/27/1975
--------------------------------------------------------------------------------------------------------
*/
function dateAdd( start, interval, number ) {
   // get the milliseconds for this Date object. 
    var buffer = Date.parse( start ) ;
	
	//What part are we adding
    switch (interval.charAt(0))
    {
        case 'd': case 'D': 
            number *= 24 ; // days to hours
            // fall through! 
        case 'h': case 'H':
            number *= 60 ; // hours to minutes
            // fall through! 
        case 'm': case 'M':
            number *= 60 ; // minutes to seconds
            // fall through! 
        case 'n': case 'n':
			//still to do - also, need to switch n and m I think.
			//month additions will need to be handled differently - will need to evaluate the date and then add the months.
        case 's': case 'S':
            number *= 1000 ; // seconds to milliseconds
            break ;
        default:
        // If we get to here then the interval parameter
        // didn't meet the d,h,m,s criteria.  Handle
        // the error. 		
        alert(intervalMsg) ;
        return null ;
    }
    return new Date( buffer + number ) ;
}
//##########################################################################################################	


//##########################################################################################################	
/*
--------------------------------------------------------------------------------------------------------
User defined function: 	Reads in a date string and returns that value as a JS Date object.  SBH:24/07/2008
Parameters:	
	paramDateString:	dd/mm/yyyy date format as string
--------------------------------------------------------------------------------------------------------
*/
function fnConvertToDate(paramDateString) {
	var arrDateParts = paramDateString.split("/");
	//alert(arrDateParts[2] + "," + arrDateParts[1] + "," + arrDateParts[0]);
	var dReturnDate = new Date(arrDateParts[2], arrDateParts[1]-1, arrDateParts[0]);

	return dReturnDate; 
}
//##########################################################################################################	
/*
--------------------------------------------------------------------------------------------------------
User defined function: This function compares two dates and returns true if paramDateFirst is in sequence 
with paramDateSecond. MET: 17/09/2008
Parameters:
	paramDateFirst: String of field ID of first date
	ParamDateSecond: String of field ID of second date

Example:
	paramDateFirst = 23/07/2007 and ParamDateSecond = 28/07/2007 : result returns true
	paramDateFirst = 02/08/2007 and ParamDateSecond = 28/07/2007 : result returns false
--------------------------------------------------------------------------------------------------------
*/

function fnCompareSequentialDates(paramDateFirst, paramDateSecond) {

	// get dates from form
	var strDate1 = document.getElementById(paramDateFirst).value;
    var strDate2  = document.getElementById(paramDateSecond).value;
	
	// convert to component date parts
    var dDay1   = parseInt(strDate1.substring(0,2),10); 
    var dMonth1  = parseInt(strDate1.substring(3,5),10);
    var dYear1   = parseInt(strDate1.substring(6,10),10); 
    var dDay2   = parseInt(strDate2.substring(0,2),10); 
    var dMonth2  = parseInt(strDate2.substring(3,5),10); 
    var dYear2   = parseInt(strDate2.substring(6,10),10);
	
	// rebuild new dates
    var dDate1 = new Date(dYear1, dMonth1, dDay1); 
    var dDate2 = new Date(dYear2, dMonth2, dDay2); 

	// compare dates
   	if (dDate2 < dDate1) {
		//alert("FALSE - the first date is out of sequence with the second date");
		return false;
	} 
   	else { 
		//alert("TRUE - the first date is the same or in sequence with the second date ");
		return true;
   	}
} 

