﻿// JavaScript for DateTimePicker and DateTimePickerValidator controls.

// <summary>
/// Sets the text of a HTML label to the Day of the Week string for a Date object.
/// </summary>
function DateTimePicker_SetDayOfWeekLabel( dateTimePickerId, dayMode )
{
	var lblDayOfWeek = document.getElementById( dateTimePickerId + '_lblDayOfWeek' );
	var dow = '';
	var selectedDate = DateTimePicker_ParseDateTime( dateTimePickerId, dayMode );
	if (selectedDate != null)
		dow = DateTimePicker_GetDaysOfWeek()[selectedDate.getDay()]; // DateTimePicker_GetDaysOfWeek function will have been rendered by DateTimePicker.OnPreRender. 
	
	lblDayOfWeek.firstChild.data = dow;
}


// <summary>
/// Tries to parse a Date object from the specified DateTimePicker control, taking into account its DayMode property.
/// </summary>
function DateTimePicker_ParseDateTime( dateTimePickerId, dayMode )
{
	var ddlMillisecond = document.getElementById( dateTimePickerId + '_ddlMillisecond' );
	var ddlSecond = document.getElementById( dateTimePickerId + '_ddlSecond' );
	var ddlMinute = document.getElementById( dateTimePickerId + '_ddlMinute' );
	var ddlHour = document.getElementById( dateTimePickerId + '_ddlHour' );
	var ddlDay = document.getElementById( dateTimePickerId + '_ddlDay' );
	var ddlMonth = document.getElementById( dateTimePickerId + '_ddlMonth' );
	var ddlYear = document.getElementById( dateTimePickerId + '_ddlYear' );
	
	var iMillisecond = 0;
	var iSecond = 0;
	var iMinute = 0;
	var iHour = 0;
	var iDay = 1;
	var iMonth = 1;
	var iYear = 1;
	
	if (ddlMillisecond != null)
		iMillisecond = parseInt( ddlMillisecond.options[ddlMillisecond.selectedIndex].value, 10 );
		
	if (ddlSecond != null)
		iSecond = parseInt( ddlSecond.options[ddlSecond.selectedIndex].value, 10 );
		
	if (ddlMinute != null)
		iMinute = parseInt( ddlMinute.options[ddlMinute.selectedIndex].value, 10 );
		
	if (ddlHour != null)
		iHour = parseInt( ddlHour.options[ddlHour.selectedIndex].value, 10 );
	
	if (ddlDay != null)
		iDay = parseInt( ddlDay.options[ddlDay.selectedIndex].value, 10 );

	if (ddlMonth != null)
		iMonth = parseInt( ddlMonth.options[ddlMonth.selectedIndex].value, 10 );

	if (ddlYear != null)
		iYear = parseInt( ddlYear.options[ddlYear.selectedIndex].value, 10 );
		
	if( iMillisecond == -1 || iSecond == -1 || iMinute == -1 || iHour == -1 || iDay == -1 || iMonth == -1 || iYear == -1 )
		return null;
		
	switch( dayMode )
	{
		case 'firstofmonth':
			iDay = 1;
			break;
			
		case 'lastofmonth':
			// Build a Date object set to 1st day of next month. Note: month param is zero-based, so using ddl's 1 based-value is equivilent of next month.
			var dtLastOfMonth = new Date( iYear, iMonth, 1 );
			// Get date before 1st day of next month, i.e. last day of selected month.
			dtLastOfMonth.setDate( dtLastOfMonth.getDate() -1 );
			// Get day of month.
			iDay = dtLastOfMonth.getDate();
			break;
			
		//default:
		// Stays as 1.
	}
	
	var dateStr = iDay + '/' + iMonth + '/' + iYear + ' ' + iHour + ':' + iMinute + ':' + iSecond + '.' + iMillisecond;
	
	if( DateTimePickerValidator_IsDate( dateStr ) )
		return new Date( iYear, iMonth - 1, iDay, iHour, iMinute, iSecond, iMillisecond );
	else
		return null;
}


/// <summary>
/// Validates a DateTimePicker control.
/// </summary>
function DateTimePickerValidator_EvaluateIsValid( val )
{
	var ddlMillisecond = document.getElementById( val.controltovalidate + '_ddlMillisecond' );
	var ddlSecond = document.getElementById( val.controltovalidate + '_ddlSecond' );
	var ddlMinute = document.getElementById( val.controltovalidate + '_ddlMinute' );
	var ddlHour = document.getElementById( val.controltovalidate + '_ddlHour' );
	var ddlDay = document.getElementById( val.controltovalidate + '_ddlDay' );
	var ddlMonth = document.getElementById( val.controltovalidate + '_ddlMonth' );
	var ddlYear = document.getElementById( val.controltovalidate + '_ddlYear' );
	
	var iMillisecond = 0;
	var iSecond = 0;
	var iMinute = 0;
	var iHour = 0;
	var iDay = 1;
	var iMonth = 1;
	var iYear = 1;
	
	if (ddlMillisecond != null)
		iMillisecond = parseInt( ddlMillisecond.options[ddlMillisecond.selectedIndex].value, 10 );
		
	if (ddlSecond != null)
		iSecond = parseInt( ddlSecond.options[ddlSecond.selectedIndex].value, 10 );
		
	if (ddlMinute != null)
		iMinute = parseInt( ddlMinute.options[ddlMinute.selectedIndex].value, 10 );
		
	if (ddlHour != null)
		iHour = parseInt( ddlHour.options[ddlHour.selectedIndex].value, 10 );
	
	if (ddlDay != null)
		iDay = parseInt( ddlDay.options[ddlDay.selectedIndex].value, 10 );

	if (ddlMonth != null)
		iMonth = parseInt( ddlMonth.options[ddlMonth.selectedIndex].value, 10 );

	if (ddlYear != null)
		iYear = parseInt( ddlYear.options[ddlYear.selectedIndex].value, 10 );
		
	if( iMillisecond == -1 || iSecond == -1 || iMinute == -1 || iHour == -1 || iDay == -1 || iMonth == -1 || iYear == -1 )
		return false;
	
	switch( val.dayMode )
	{
		case 'firstofmonth':
			iDay = 1;
			break;
			
		case 'lastofmonth':
			// Build a Date object set to 1st day of next month. Note: month param is zero-based, so using ddl's 1 based-value is equivilent of next month.
			var dtLastOfMonth = new Date( iYear, iMonth, 1 );
			// Get date before 1st day of next month, i.e. last day of selected month.
			dtLastOfMonth.setDate( dtLastOfMonth.getDate() -1 );
			// Get day of month.
			iDay = dtLastOfMonth.getDate();
			break;
			
		//default:
		// Stays as 1.
	}
	
	// Now we have all the date and time parts, can they make a valid Date object?
	if( DateTimePickerValidator_IsDate( iDay + '/' + iMonth + '/' + iYear + ' ' + iHour + ':' + iMinute + ':' + iSecond + '.' + iMillisecond ) )
	{
		var dtSelected = new Date( iYear, iMonth - 1, iDay, iHour, iMinute, iSecond, iMillisecond );
		
		// If necessary, check if selected time isn't too low.
		if( val.minTime != null && dtSelected < DateTimePickerValidator_TimeFromString( val.minTime ) )
		{
			return false;
		}
			
		// If necessary, check if selected time isn't too high.
		if( val.maxTime != null && dtSelected > DateTimePickerValidator_TimeFromString( val.maxTime ) )
		{
			return false;
		}

		// If necessary, check if selected date isn't too low.
		if( val.minDate != null && dtSelected < DateTimePickerValidator_DateTimeFromString( val.minDate ) )
		{
			return false;
		}
		
		// If necessary, check if selected date isn't too high.
		if( val.maxDate != null && dtSelected > DateTimePickerValidator_DateTimeFromString( val.maxDate ) )
		{
			return false;
		}
		
		// Check minAge.
		if( val.minAge != null )
		{
			if( DateTimePickerValidator_AgeAt( dtSelected, DateTimePickerValidator_DateTimeFromString( val.minAgeAt ) ) < val.minAge ) 
				return false;
		}
		
		// Check maxAge.
		if( val.maxAge != null )
		{
			if( DateTimePickerValidator_AgeAt( dtSelected, DateTimePickerValidator_DateTimeFromString( val.maxAgeAt ) ) > val.maxAge )
				return false;
		}
		
		// Other possible checks can go here...
		
		// Success if we get this far.
		return true;
	}
	else
	{
		// Not a valid date.
		return false;
	}
}


/// <summary>
/// Calculates the age in whole years on the current date.
/// </summary>
function DateTimePickerValidator_Age( dob )
{
	var Now = new Date();
	
	return DateTimePickerValidator_AgeAt( Now, dob );
}


/// <summary>
/// Calculates the age in whole years on the specified date.
/// </summary>
function DateTimePickerValidator_AgeAt( dob, onDate )
{
	// Get the difference in years.
	var iAge = onDate.getFullYear() - dob.getFullYear(); 
	
	if( onDate.getMonth() < dob.getMonth() || ( onDate.getMonth() == dob.getMonth() && onDate.getDate() < dob.getDate() ) )
		iAge--;
	
	return iAge;
}


/// <summary>
/// Parses a time from a HHmmssfff string representation.
/// </summary>
function DateTimePickerValidator_TimeFromString( timeStr )
{
	var iHour = parseInt( timeStr.substr( 0, 2 ), 10 );
	var iMinute = parseInt( timeStr.substr( 2, 2 ), 10 );
	var iSecond = parseInt( timeStr.substr( 4, 2 ), 10 );
	var iMilliecond = parseInt( timeStr.substr( 6, 3 ), 10 );
	
	var t = new Date( 1, 0, 1, iHour, iMinute, iSecond, iMilliecond );
	
	return t;
}


/// <summary>
/// Parses a date from a ddMMyyyyHHmmssfff string representation.
/// </summary>
function DateTimePickerValidator_DateTimeFromString( dateStr )
{
	// dateStr is in the format ddMMyyyyHHmmssfff
	
//	var iDay = parseInt( DateTimePickerValidator_TrimLeadingZeroes( dateStr.substr( 0, 2 ) ) );
//	var iMonth = parseInt( DateTimePickerValidator_TrimLeadingZeroes( dateStr.substr( 2, 2 ) ) );
//	var iYear = parseInt( DateTimePickerValidator_TrimLeadingZeroes( dateStr.substr( 4, 4 ) ) );

	var iDay = parseInt( dateStr.substr( 0, 2 ), 10 );
	var iMonth = parseInt( dateStr.substr( 2, 2 ), 10 );
	var iYear = parseInt( dateStr.substr( 4, 4 ), 10 );
	var iHour = parseInt( dateStr.substr( 8, 2 ), 10 );
	var iMinute = parseInt( dateStr.substr( 10, 2 ), 10 );
	var iSecond = parseInt( dateStr.substr( 12, 2 ), 10 );
	var iMilliecond = parseInt( dateStr.substr( 14, 3 ), 10 );
	
	var dt = new Date( iYear, iMonth -1, iDay, iHour, iMinute, iSecond, iMilliecond );

	return dt;
}


/// <summary>
/// Trims all leading zero characters from the specified string.
/// </summary>
function DateTimePickerValidator_TrimLeadingZeroes( str )
{
//	while( str.substr(0, 1) == '0' )
//		str = str.substr(1);
//	return str;

	if (str != null)
		str  = str.replace(/^[0]+/g, '');

	return str;
}


/// <summary>
/// Validates a string as a date.
/// </summary>
function DateTimePickerValidator_IsDate(dateStr)
{ 
	// Checks for the following valid date formats: 
	// DD/MM/YYYY HH:mm:ss:fff DD-MM-YYYY
	// 2 Digit Year pattern.
	// var datePat = /^(\d{1,2})(\/|-)(\d{1,2})\2(\d{2}|\d{4})$/; 
	// 4 Digit Year pattern.
	// var datePat = /^(\d{1,2})(\/|-)(\d{1,2})\2(\d{4})$/; 
	var datePat =    /^(\d{1,2})(\/|-)(\d{1,2})\2(\d{1,4})(\s)(\d{1,2})(:)(\d{1,2})(:)(\d{1,2})(\.)(\d{1,3})$/; 

	var matchArray = dateStr.match(datePat); // Is the format OK? 
	if (matchArray == null)
	{
		return false; 
	} 
	//month = matchArray[1]; // parse date into variables 
	//day = matchArray[3]; 
	day = matchArray[1];
	month = matchArray[3];
	year = matchArray[4]; 
	hour = matchArray[6];
	minute = matchArray[8];
	second = matchArray[10];
	millisecond = matchArray[12];
	
	if (hour < 0 || hour > 23)
		return false; //
	
	if (minute < 0 || minute > 59)
		return false; //
		
	if (second < 0 || second > 59)
		return false; //
		
	if (millisecond < 0 || millisecond > 999)
		return false; // 
	
	if (month < 1 || month > 12)
	{
		// Check month is be between 1 and 12.
		return false; 
	} 
	
	if (day < 1 || day > 31)
	{
		// Check day is between 1 and 31.
		return false; 
	} 
	
	if ((month==4 || month==6 || month==9 || month==11) && day==31)
	{
		// Check month doesn't have 31 days if April, June, September or November.
		return false;
	} 
	
	if (month == 2)
	{
		// check for february 29th when year is cleanly divisible by 4 but not 100 or 400.
		var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); 
		if (day>29 || (day==29 && !isleap))
		{
			return false; 
		} 
	} 
	
	if (year < -1)
		return false;
	
	return true; // date is valid if we get this far.
}
