
// %a - abbreviated weekday name 
// %A - full weekday name 
// %b - abbreviated month name 
// %B - full month name 
// %c - preferred date and time representation for the current locale
// %C - century number 
// %d - the day of the month ( 00 .. 31 ) 
// %D - american date style: %m/%d/%y
// %e - the day of the month ( 0 .. 31 ) 
// %E - (man strftime)
// %f - 
// %F - (man strftime)
// %g - (man strftime)
// %G - (man strftime)
// %h - (man strftime)
// %H - hour ( 00 .. 23 ) 
// %i - 
// %I - hour ( 01 .. 12 ) 
// %j - day of the year ( 000 .. 366 ) 
// %J - 
// %k - hour ( 0 .. 23 ) 
// %K - 
// %l - hour ( 1 .. 12 ) 
// %L - 
// %m - month ( 01 .. 12 ) 
// %M - minute ( 00 .. 59 ) 
// %n - a newline character 
// %N - 
// %o - 
// %O - 
// %p - ``PM'' or ``AM'' 
// %P - ``pm'' or ``am'' 
// %q - 
// %Q - 
// %r - the time in am/pm notation %I:%M:%S %p
// %R - the time in 24-hour notation %H:%M
// %s - number of seconds since Epoch (since Jan 01 1970 00:00:00 UTC)
// %S - second ( 00 .. 59 ) 
// %t - a tab character 
// %T - the time in 24-hour notation (%H:%M:%S)
// %u - the day of the week ( 1 .. 7, 1 = MON )
// %U - the week number
// %v - 
// %V - the week number
// %w - the day of the week ( 0 .. 6, 0 = SUN )
// %W - the week number
// %x - preferred date representation for the current locale without the time
// %X - preferred time representation for the current locale without the date
// %y - year without the century ( 00 .. 99 )
// %Y - year including the century ( ex. 1979 )
// %z - 
// %Z - 
// %% - a literal % character 

// this validation will only work if there are delimeters of some sort between each date part
// %m%d%Y will not validate properly

Calendar.validateDateFormat = function(strDate, fmt) { //as Boolean

	if (typeof Calendar._SDN_len == "undefined")
		Calendar._SDN_len = 3;

	//the length of a short Weekday name
	var SDN_len = Calendar._SDN_len;
	
	if (typeof Calendar._SMN_len == "undefined")
		Calendar._SMN_len = 3;
		
	//the length of a short month name
	var SMN_len = Calendar._SMN_len;

	//create the regular expression test
	//www.regular-expressions.info/javascript.html
	//msdn.microsoft.com/library/default.asp?url=/library/en-us/jscript7/html/jsreconRegularExpressions.asp
	var strRegExp = '';

	//save which character we are looking at
	var chr = '';
	
	//the character plus 1
	var chrPlus1 = '';
	
	//for each character in fmt
	for(var i = 0; i < fmt.length; i++)
	{
		//get a character
		chr = fmt.charAt(i);
		
		//get the pair if characters, if possible
		if(i < fmt.length)
		{
			chrPlus1 = chr + fmt.charAt(i + 1);
		}
		
		//if chr = "%", this is a calendar code
		if(chr == "%" && chrPlus1.length == 2)
		{
			switch (chrPlus1)
			{
				case "%a": // abbreviated weekday name [FIXME: I18N]
					strRegExp += "("
					for (var j = 0; j < Calendar._DN.length; j++) {
						strRegExp += Calendar._DN[j].substr(0, SDN_len);
						if(j < Calendar._DN.length -1) strRegExp += "|";
					}
					strRegExp += ")";
					break;
				case "%A": // full weekday name
					strRegExp += "("
					for (var j = 0; j < Calendar._DN.length; j++) {
						strRegExp += Calendar._DN[j];
						if(j < Calendar._DN.length -1) strRegExp += "|";
					}
					strRegExp += ")";
					break;
				case "%b": // abbreviated month name [FIXME: I18N]
					strRegExp += "("
					for (var j = 0; j < 12; j++) {
						strRegExp += Calendar._MN[j].substr(0, SMN_len);
						if(j < Calendar._MN.length -1) strRegExp += "|";
					}
					strRegExp += ")";
					break;
				case "%B": // full month name
					strRegExp += "("
					for (var j = 0; j < 12; j++) {
						strRegExp += Calendar._MN[j];
						if(j < Calendar._MN.length -1) strRegExp += "|";
					}
					strRegExp += ")";
					break;
				// FIXME: %c : preferred date and time representation for the current locale
				case "%C": // the century number
					strRegExp += "(19|20)"
					break;
				case "%d": // the day of the month (range 01 to 31)
					//must be 01-09 or 10-29 or 30-31
					strRegExp += "(0[1-9]{1}|[1-2][0-9]|3[0-1])"
					break;
				case "%e": // the day of the month (range 1 to 31)
					//must be 1-9 or 10-29 or 30-31
					strRegExp += "(0?[1-9]{1}|[1-2][0-9]|3[0-1])"
					break;
				// FIXME: %D : american date style: %m/%d/%y
				// FIXME: %E, %F, %G, %g, %h (man strftime)
				case "%H": // hour, range 00 to 23 (24h format)
					//must be from 00-09 or 10-19 or 20-23
					strRegExp += "(0[0-9]{1}|1[0-9]|2[0-3])"
					break;
				case "%I": // hour, range 01 to 12 (12h format)
					//must be from 01-09 or 10-12
					strRegExp += "(0[1-9]{1}|1[0-2]{1})"
					break;
				case "%j": // day of the year (range 001 to 366)
					//must be from ...
					strRegExp += "([0-3]{1}[0-9]{1}[0-9]{1})"
					//this is not perfect, range is currently set as 000 - 399
					//I am jsut being lazy right now, and this prolly will not be used much
					break;
				case "%k":	// hour, range 0 to 23 (24h format)
					//must be from 0-9 or 10-19 or 20-23
					strRegExp += "(0?[0-9]{1}|1[0-9]|2[0-3])"
					break;
				case "%l": // hour, range 1 to 12 (12h format)
					//must be from 1-9 or 10-12
					strRegExp += "(0?[1-9]{1}|1[0-2]{1})"
					break;
				case "%m": // month, range 01 to 12
					//must be 01-09 | 10-12
					strRegExp += "(0[1-9]{1}|1[0-2]{1})"
					break;
				case "%M": // minute, range 00 to 59
					//must be 00-09 | 10-59
					strRegExp += "(0[0-9]{1}|[1-5]{1}[0-9]{1})"
					break;
				case "%n": // a newline character
					strRegExp += "\n"
					break;
				case "%p": // AM | PM
					strRegExp += "(AM|PM)"
					break;
				case "%P": // am | pm
					strRegExp += "(am|pm)"
					break;
				case "%q": // abreviated OR full Weekday name (for format testing only)
					strRegExp += "("
					for (var j = 0; j < Calendar._DN.length; j++) {
						strRegExp += Calendar._DN[j].substr(0, SDN_len) + "(" + Calendar._DN[j].substr(SDN_len, Calendar._DN[j].length) + ")?";
						if(j < Calendar._DN.length -1) strRegExp += "|";
					}
					strRegExp += ")";
					break;
				case "%Q": // abreviated OR full Month name (for format testing only)
					strRegExp += "("
					for (var j = 0; j < 12; j++) {
						strRegExp += Calendar._MN[j].substr(0, SMN_len) + "(" + Calendar._MN[j].substr(SMN_len, Calendar._MN[j].length) + ")?";
						if(j < Calendar._MN.length -1) strRegExp += "|";
					}
					strRegExp += ")";
					break;
				// FIXME: %r : the time in am/pm notation %I:%M:%S %p
				// FIXME: %R : the time in 24-hour notation %H:%M
				case "%s": // number of seconds since Epoch (since Jan 01 1970 00:00:00 UTC)
					//do not know the length of the number so as long as it is a bunch of numbers
					strRegExp += "[0-9]+"
					break;
				case "%S": // seconds, range 00 to 59
					//must be 00-09 | 10-59
					strRegExp += "(0[0-9]{1}|[1-5]{1}[0-9]{1})"
					break;
				case "%t": // a tab character
					break;
				// FIXME: %T : the time in 24-hour notation (%H:%M:%S)
				case "%U": //run to V
				case "%W": //run to V
				case "%V": // the week number (range 01 to 52)
					//must be from 00-09 or 10-49 or 50-52
					strRegExp += "(0[1-9]{1}|[1-4]{1}[0-9]{1}|5[0-2]{1})"
					break;
				case "%u":	// the day of the week (range 1 to 7, 1 = MON)
					strRegExp += "[1-7]{1}"
					break;
				case "%w":	// the day of the week (range 0 to 6, 0 = SUN)
					strRegExp += "[0-6]{1}"
					break;
				// FIXME: %x : preferred date representation for the current locale without the time
				// FIXME: %X : preferred time representation for the current locale without the date
				case "%y": // year without the century (range 00 to 99)
					//must be from 00-09 or 10-99
					strRegExp += "(0[0-9]{1}|[1-9]{1}[0-9]{1})"
					break;
				case "%Y":	// year with the century
					//must be 19 | 20 | 21 + 1 digit from 0-9 + 1 digit from 0-9
					strRegExp += "(19|20|21)[0-9]{1}[0-9]{1}"
					break;
				case "%%": // a literal '%' character
					strRegExp += "%"
					break;
				default:
					break;
			}
			
			//increment i to skip the 2 code characters
			i++;
		}
		else
		//not a calendar code, just a regular character
		//add it to the strRegExp
		{
			//check for special characters
			//www.regular-expressions.info/characters.html
			switch (chr)
			{
				case "[":
				case "\\": // \ (backslash)
				case "^":
				case "$":
				case ".":
				case "|":
				case "?":
				case "*":
				case "+":
				case "(":
				case ")":
					//Calendar._jsChr(92) = \ (backslash)
					strRegExp += "\\" + chr;
					break;
				case " ": //space
					strRegExp += " ";
					break;
				default:
					strRegExp += chr;
					break;
			}

		} //end if(chr == "%")

	} //end for
	
	//add beginning and end position markers
	strRegExp = "^" + strRegExp + "$"
	
	//create the RegExp object, case-InSeNsItIvE
	var objRegExp = new RegExp(strRegExp, "i");
	
	//you may remove these lines without problems, they are for testing and development purposes only
	//*******************************************************************************
	if(top.location.href.indexOf("dynarch_test.html") > 0 && document.Form1.RegExp)
	{
		document.Form1.RegExp.value = strRegExp;
		//document.Form1.Status.value = objRegExp.test(strDate)
	}
	//*******************************************************************************
	
	//if the date format is valid, make sure the value itself is a valid date
	if(objRegExp.test(strDate))
	{
		return Calendar.validateDateValue(strDate, fmt)
	}
	else
	{
		return false;
	}

}

//try to create a date using the values passed
//should be used AFTER the format has been validated
Calendar.validateDateValue = function(strDate, fmt) { //as Boolean

	//at the end if the syntax test, test for a valid date value
	//i.e. make sure the user is not trying to enter February 31, 2006 or 13/13/2006
	//save each part of a valid date
	var theMonth = 0;
	var theMonthName = '';
	var theDay = 0;
	var theYear = 0;
	var theHour12 = 0;
	var theHour24 = 0;
	var theMinute = 0;
	var theSecond = 0;

	//save which character we are looking at
	var chr = '';
	
	//the character plus 1
	var chrPlus1 = '';
	
	//save the delimiter after the fmt code
	var chrLookingFor = '';
	
	var startPos = -1;
	var endPos = -1;
	
	//for each character in fmt
	for(var i = 0; i < fmt.length; i++)
	{
		//get a character
		chr = fmt.charAt(i);
		
		//get the pair if characters, if possible
		if(i < fmt.length)
		{
			chrPlus1 = chr + fmt.charAt(i + 1);
		}
		
		//if chrPlus1.length <= 1 then we must be at the end of the string
		if(chr == "%" && chrPlus1.length == 2)
		{
			//start extrtacting from
			//if the startPos has not been defined, get the position from the current fmt position
			//else it is 1 character after the last extraction
			startPos = (startPos < 0) ? i : endPos + chrLookingFor.length;

			//the delimiter after this fmt code will be the pos of % + 2
			//chrLookingFor = fmt.charAt(i + 2);
			var tmp = fmt.indexOf("%", i + 2)
			chrLookingFor = fmt.substring(i + 2, (tmp < 0) ? strDate.length : tmp)
			
			//end position is where the deleimter is or the end of the string
			endPos = ((i + 2) >= fmt.length) ? strDate.length : strDate.indexOf(chrLookingFor, startPos + 1);
			endPos = (endPos == strDate.length - 1) ? strDate.length : endPos;
			
			//alert("startPos: " + startPos + "\nendPos: " + endPos)
			
			switch (chrPlus1)
			{
				case "%a": // abbreviated weekday name [FIXME: I18N]
					break;
				case "%A": // full weekday name
					break;
				case "%b": // abbreviated month name [FIXME: I18N]
				case "%B": // full month name
				case "%Q": // abbreviated OR full month name
					theMonthName = strDate.substring(startPos, endPos);
					for (var j = 0; j < 12; j++) {
						if(Calendar._MN[j].toLowerCase().indexOf(theMonthName.toLowerCase()) == 0){
							theMonth = j - (-1);
							break;
						}
					}
					break;
				// FIXME: %c : preferred date and time representation for the current locale
				case "%C": // the century number
					break;
				case "%d": // the day of the month (range 01 to 31)
					//must be 01-09 or 10-29 or 30-31
					theDay = strDate.substring(startPos, endPos);
					break;
				case "%e": // the day of the month (range 1 to 31)
					//must be 1-9 or 10-29 or 30-31
					theDay = strDate.substring(startPos, endPos);
					break;
				// FIXME: %D : american date style: %m/%d/%y
				// FIXME: %E, %F, %G, %g, %h (man strftime)
				case "%H": // hour, range 00 to 23 (24h format)
					//must be from 00-09 or 10-19 or 20-23
					theHour24 = strDate.substring(startPos, endPos);
					break;
				case "%I": // hour, range 01 to 12 (12h format)
					//must be from 01-09 or 10-12
					theHour12 = strDate.substring(startPos, endPos);
					theHour24 = theHour12;
					if (/pm/i.test(strDate) && theHour24 < 12)
						theHour24 -= -12;
					else if (/am/i.test(strDate) && theHour24 >= 12)
						theHour24 -= 12;
					break;
				case "%j": // day of the year (range 001 to 366)
					break;
				case "%k":	// hour, range 0 to 23 (24h format)
					//must be from 0-9 or 10-19 or 20-23
					theHour24 = strDate.substring(startPos, endPos);
					break;
				case "%l": // hour, range 1 to 12 (12h format)
					//must be from 1-9 or 10-12
					theHour12 = strDate.substring(startPos, endPos);
					theHour24 = theHour12;
					if (/pm/i.test(strDate) && theHour24 < 12)
						theHour24 -= -12;
					else if (/am/i.test(strDate) && theHour24 >= 12)
						theHour24 -= 12;
					break;
				case "%m": // month, range 01 to 12
					//must be 01-09 | 10-12
					theMonth = strDate.substring(startPos, endPos);
					break;
				case "%M": // minute, range 00 to 59
					//must be 00-09 | 10-59
					theMinute = strDate.substring(startPos, endPos);
					break;
				case "%n": // a newline character
					break;
				case "%p": // AM | PM
					break;
				case "%P": // am | pm
					break;
				// FIXME: %r : the time in am/pm notation %I:%M:%S %p
				// FIXME: %R : the time in 24-hour notation %H:%M
				case "%s": // number of seconds since Epoch (since Jan 01 1970 00:00:00 UTC)
					break;
				case "%S": // seconds, range 00 to 59
					//must be 00-09 | 10-59
					theSecond = strDate.substring(startPos, endPos);
					break;
				case "%t": // a tab character
					break;
				// FIXME: %T : the time in 24-hour notation (%H:%M:%S)
				case "%U": //run to V
				case "%W": //run to V
				case "%V": // the week number (range 01 to 52)
					//must be from 00-09 or 10-49 or 50-52
					break;
				case "%u":	// the day of the week (range 1 to 7, 1 = MON)
					break;
				case "%w":	// the day of the week (range 0 to 6, 0 = SUN)
					break;
				// FIXME: %x : preferred date representation for the current locale without the time
				// FIXME: %X : preferred time representation for the current locale without the date
				case "%y": // year without the century (range 00 to 99)
					//must be from 00-09 or 10-99
					theYear = strDate.substring(startPos, endPos);
					theYear -= (theYear > 29) ? -1900 : -2000;
					break;
				case "%Y":	// year with the century
					//must be 19 | 20 | 21 + 1 digit from 0-9 + 1 digit from 0-9
					theYear = strDate.substring(startPos, endPos);
					break;
				case "%%": // a literal '%' character
					break;
				default:
					break;
			}
			
			//increment i to skip the 2 code characters
			i++;
			
		}//end if(chr == "%")
			
	} //end for
	
	//create a date object using the parts submitted
	//Javascript New Date syntax
	//1. dateObjectName = new Date()
	//2. dateObjectName = new Date("month day, year hours:minutes:seconds")
	//3. dateObjectName = new Date(year, month, day)
	//4. dateObjectName = new Date(year, month, day, hours, minutes, seconds)
	//this will convert April 31 into May 1 and February 29 into March 1 (if not a leap year)
	var submittedDate = new Date(parseInt(theYear, 10), parseInt(theMonth, 10) - 1, parseInt(theDay, 10), parseInt(theHour24, 10), parseInt(theMinute, 10), parseInt(theSecond, 10))
	
	//alert("MonthName: " + theMonthName + "(" + theMonth + ")\nDay: " + theDay + "\nYear: " + theYear + "\nHour: " + theHour24 + "\nMinute: " + theMinute + "\nSecond: " + theSecond);
	//alert(submittedDate);

	var tmp = "";
	tmp += "submittedDate.getMonth() - (-1): " + (submittedDate.getMonth() - (-1)) + " == theMonth: " + parseInt(theMonth, 10) + "\n";
	tmp += "submittedDate.getDate(): " + submittedDate.getDate() + " == theDay: " + parseInt(theDay, 10) + "\n";
	tmp += "submittedDate.getYear(): " + submittedDate.getYear() + " == theYear: " + parseInt(theYear, 10) + "\n";
	tmp += "submittedDate.getHours(): " + submittedDate.getHours() + " == theHour24: " + parseInt(theHour24, 10) + "\n";
	tmp += "submittedDate.getMinutes(): " + submittedDate.getMinutes() + " == theMinute: " + parseInt(theMinute, 10) + "\n";
	tmp += "submittedDate.getSeconds(): " + submittedDate.getSeconds() + " == theSecond: " + parseInt(theSecond, 10);
	//alert(tmp);

	//now if the values extracted from the date object still match the submitted values, the date is valid
	if(
		parseInt(submittedDate.getMonth() - (-1), 10) == parseInt(theMonth, 10) && 
		parseInt(submittedDate.getDate(), 10) == parseInt(theDay, 10) && 
		parseInt(submittedDate.getYear(), 10) == parseInt(theYear, 10) && 
		parseInt(submittedDate.getHours(), 10) == parseInt(theHour24, 10) && 
		parseInt(submittedDate.getMinutes(), 10) == parseInt(theMinute, 10) && 
		parseInt(submittedDate.getSeconds(), 10) == parseInt(theSecond, 10)
		)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//similar to the ASP version of Chr()
Calendar._jsChar = function (charCode) {
	return unescape('%' + charCode.toString(16));
}

// add the following to in calendar.js

// in Date.prototype.print = function (str) 
// s["%q"] = Calendar._DN[w]; // full weekday name
// s["%Q"] = Calendar._MN[m]; // full month name

// in Date.parseDate = function(str, fmt)
// case "%Q": (after case "%B":)
