
// ***************************************************************************
// * Date parsing functions
// * Jul 29, 2002
// ***************************************************************************
// ========== Current date=============
var now = new Date();
var year = now.getYear();
// ========== Associate month numbers with abbreviated month names =================
var months = new Array();
months["JAN"] = "1";
months["FEB"] = "2";
months["MAR"] = "3";
months["APR"] = "4";
months["MAY"] = "5";
months["JUN"] = "6";
months["JUL"] = "7";
months["AUG"] = "8";
months["SEP"] = "9";
months["OCT"] = "10";
months["NOV"] = "11";
months["DEC"] = "12";
// =========================
// Number of days in a month
// where array elements: 0 = dummy*, 1 = Jan, 2 = Feb, ..., 12 = Dec
// * A dummy value is used because arrays start at 0.
// =========================
var ndm = new Array(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var ndm_leap = new Array(0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
// ============= Date patterns ================
var MMM = "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)";
var dd = "([1-9]|([0]{0,1}[1-9])|([1-2][0-9])|([3][0-1]))";
var mm = "([1-9]|([0]{0,1}[1-9])|([1][0-2]))";
var yy = "[0-9]{2}";
var yyyy = "[0-9]{4}";
var mmddyyyy_slash = new RegExp("^" + mm + "\/" + dd + "\/" + yyyy + "$");
var mmddyy_slash = new RegExp("^" + mm + "\/" + dd + "\/" + yy + "$");
var mmddyyyy_dash = new RegExp("^" + mm + "-" + dd + "-" + yyyy + "$");
var mmddyy_dash = new RegExp("^" + mm + "-" + dd + "-" + yy + "$");
var MMMddyyyy = new RegExp("^" + MMM + " " + dd + " " + yyyy + "$", "i");
var MMMddyyyy_comma = new RegExp("^" + MMM + " " + dd + ", " + yyyy + "$", "i");
var MMMddyy_comma = new RegExp("^" + MMM + " " + dd + ", " + yy + "$", "i");
var mmdd_slash = new RegExp("^" + mm + "\/" + dd + "$");
var mmdd_dash = new RegExp("^" + mm + "-" + dd + "$");
var MMMdd = new RegExp("^" + MMM + " " + dd + "$", "i");
// ================ Date range patterns =====================
var range_yyyy = new RegExp("^" + yyyy + "$");
var range_mmyyyy = new RegExp("^" + mm + " " + yyyy + "$");
var range_MMMyyyy = new RegExp("^" + MMM + " " + yyyy + "$", "i");

//----- New wrapper function for cleaner code base ----- Alex, Mar 30, 2005
function parseDate(date) { return validateParsedDate(getSingleDate(date,"",false)); }

// validateParsedDate(date)
// additional check against invalid date such as Feb 29, 2005 or Jun 31, 2005
// return the pass in parameter if date is valid; return nothing if date is incorrect
function validateParsedDate(date) {
	var elements = new Array(), d = "", m = "", y = "";
	if (date=="")
		return "";

	elements = date.split (/\//);
	m = elements[0];
	d = elements[1];
	y = elements[2];
		
	switch (parseInt(m,10)) {
	case 1:
	case 3:
	case 5:
	case 7:
	case 8:
	case 10:
	case 12:
		if(parseInt(d,10) < 1 || parseInt(d,10) > 31) {
			alert("The Date is not a valid date format.");
			return "";
		}
		break;
	case 4:
	case 6:
	case 9:
	case 11:
		if(parseInt(d,10) < 1 || parseInt(d,10) > 30) {
			alert("The Date is not a valid date format.");
			return "";
		}
		break;
	case 2:
		if(leapYear(parseInt(y))) {
			if(parseInt(d,10) < 1 || parseInt(d,10) > 29) {
				alert("The Date is not a valid date format.");
				return "";
			}
		} else {
			if(parseInt(d,10) < 1 || parseInt(d,10) > 28) {
				alert("The Date is not a valid date format.");
				return "";
			}
		} 
	}//switch
	return date;
}//validateParsedDate

// leapYear(year)
// return true if the year is leap year; false otherwise
function leapYear(year) {
	var result = false;
	if(year % 4 == 0) {
		if(year % 100 != 0) {
			result = true;
		} else if(year % 400 == 0) {
			result = true;
		}
	}
	return result;
}

// ==================================
// getSingleDate(date, func=[""|"check"], {debug=[1]})
// Description: Accepts a date in various formats and converts it to a
//	default format (mm-dd-yyyy) used in SQL queries.
// Limitations: The European date format (dd/mm/yyyy) is not supported
//	because of ambiguities with the North American format
//	(mm/dd/yy). For example: 1/4/2002 -- is this Jan 4 or Apr 1?
//	Also, the yy/mm/dd format is not supported.
// Accepted input formats:
// +--------------+--------------+--------------+--------------+---------------------+
// |    Format    |  Example 1   |  Example 2   |  Example 3   |       Returns       |
// +--------------+--------------+--------------+--------------+---------------------+
// | mm/dd/yyyy   | 01/13/2000   | 1/13/2000    |              | 1/13/2000           |
// | mm/dd/yy     | 01/13/00     | 1/13/99      |              | 1/13/2000           |
// | mm-dd-yyyy   | 01-13-2000   | 1-13-2000    |              | 1/13/2000           |
// | mm-dd-yy     | 01-13-00     | 1-13-99      |              | 1/13/2000           |
// | MMM dd yyyy  | JAN 13 2000  | Jan 13 2000  | jan 13, 2000 | 1/13/2000           |
// | MMM dd, yyyy | JAN 13, 2000 | Jan 13, 2000 | jan 13, 2000 | 1/13/2000           |
// | MMM dd, yy   | JAN 13, 00   | Jan 13, 00   | jan 13, 00   | 1/13/2000           |
// | mm/dd        | 01/13        | 1/13         |              | 1/13/[current year] |
// | mm-dd        | 01-13        | 1-13         |              | 1/13/[current year] |
// | MMM dd       | JAN 13       | Jan 13       | jan 13       | 1/13/[current year] |
// +--------------+--------------+--------------+--------------+---------------------+
// Note: 2-digit years are converted as follows:
//	00 - 50 = 2000 - 2050
//	51 - 99 = 1951 - 1999
// ----- This function is modified to return date in mm/dd/yyyy format, or nothing if can't be parse -----Alex, Mar 30, 2005
// ====================================
function getSingleDate (date, func, debug) {
	var format = "";
	var elements = new Array();
	var d = "";
	var m = "";
	var y = "";
	var chkdate = false;
	var sqldate = "";
	if (date) {
		// Debugging code
		if (debug) {
			document.writeln("<b>Debug mode</b>:<br>\n");
			document.writeln("<b>Input date</b>: " + date + "<br>\n");
		}
		if (mmddyyyy_slash.test(date)) {
			format = "mm/dd/yyyy";
			chkdate = true;
			elements = date.split (/\//);
			m = elements[0];
			d = elements[1];
			y = elements[2];
			sqldate = m + "/" + d + "/" + y;
		} else if (mmddyy_slash.test(date)) {
			format = "mm/dd/yy";
			chkdate = true;
			elements = date.split (/\//);
			m = elements[0];
			d = elements[1];
			y = elements[2];
			y = formatYear(y);
			sqldate = m + "/" + d + "/" + y;
		} else if (mmddyyyy_dash.test(date)) {
			format = "mm-dd-yyyy"; // default format -- no modification required
			chkdate = true;
			elements = date.split (/\-/);
			m = elements[0];
			d = elements[1];
			y = elements[2];
			sqldate = m + "/" + d + "/" + y;
		} else if (mmddyy_dash.test(date)) {
			format = "mm-dd-yy";
			chkdate = true;
			elements = date.split (/\-/);
			m = elements[0];
			d = elements[1];
			y = elements[2];
			y = formatYear(y);
			sqldate = m + "/" + d + "/" + y;
		} else if (MMMddyyyy.test(date)) {
			format = "MMM dd yyyy";
			chkdate = true;
			elements = date.split (/[ ]+/);
			m = elements[0];
			m = m.toUpperCase();
			m = months[m];
			d = elements[1];
			y = elements[2];
			sqldate = m + "/" + d + "/" + y;
		} else if (MMMddyyyy_comma.test(date)) {
			format = "MMM dd, yyyy";
			chkdate = true;
			date = date.replace(/\,/g, "");
			elements = date.split (/[ ]+/);
			m = elements[0];
			m = m.toUpperCase();
			m = months[m];
			d = elements[1];
			y = elements[2];
			sqldate = m + "/" + d + "/" + y;
		} else if (MMMddyy_comma.test(date)) {
			format = "MMM dd, yy";
			chkdate = true;
			date = date.replace(/\,/g, "");
			elements = date.split (/[ ]+/);
			m = elements[0];
			m = m.toUpperCase();
			m = months[m];
			d = elements[1];
			y = elements[2];
			y = formatYear(y);
			sqldate = m + "/" + d + "/" + y;
		} else if (mmdd_slash.test(date)) {
			format = "mm/dd";
			chkdate = true;
			elements = date.split (/\//);
			m = elements[0];
			d = elements[1];
			y = now.getYear();
			sqldate = m + "/" + d + "/" + y;
		} else if (mmdd_dash.test(date)) {
			format = "mm-dd";
			chkdate = true;
			elements = date.split (/\-/);
			m = elements[0];
			d = elements[1];
			y = now.getYear();
			sqldate = m + "/" + d + "/" + y;
		} else if (MMMdd.test(date)) {
			format = "MMM dd";
			chkdate = true;
			elements = date.split (/[ ]+/);
			m = elements[0];
			m = m.toUpperCase();
			m = months[m];
			d = elements[1];
			y = now.getYear();
			sqldate = m + "/" + d + "/" + y;
		} else {
			format = "Error: <font color='red'>" + date + "</font> is not a valid date format.";
			chkdate = false;
			sqldate = "";
			alert("The Date is not a valid date format.");
		}
		if (debug) {		// Debugging code
			document.writeln("<b>Format detected</b>: " + format + "<br>\n");
			document.writeln("<b>SQL date format</b>: " + sqldate + "<br>\n");
		}
	} else {
//		sqldate = "<b>Syntax</b>: getSingleDate(date, func, {debug})";
		sqldate = "";
	}
	if (func == "check") {
		return (chkdate);
	} else {
		return (sqldate);
	}
}
// =============
// getDateRange(date, {debug=[1]})
// Description: Accepts a partial date and returns a date range.
// Accepted input formats:
// +--------------+----------+-----------------------+
// |    Format    | Example  |        Returns        |
// +--------------+----------+-----------------------+
// | yyyy         | 2000     | 1/1/2000 - 12/31/2000 |
// | mm yyyy      | 1 2000   | 1/1/2000 - 1/31/2000  |
// | MMM yyyy     | Jan 1999 | 1/1/2000 - 1/31/2000  |
// +--------------+----------+-----------------------+
// ========================
function getDateRange (date, func, debug) {
	var format = "";
	var elements = new Array();
	var d = "";
	var m = "";
	var y = "";
	var chkdate = false;
	var range = new Array();
	var m_start = "1";
	var d_start = "1";
	var m_end = "12";
	var date_start = "";
	var date_end = "";
	if (date) {
		// Debugging code
		if (debug) {
			document.writeln("<b>Debug mode</b>:<br>\n");
			document.writeln("<b>Input date</b>: " + date + "<br>\n");
		}
		if (range_yyyy.test(date)) {
			chkdate = true;
			format = "yyyy";
			date_start = m_start + "-" + d_start + "-" + date;
			if (checkLeapYear(date)) {
				date_end = m_end + "-" + ndm_leap[m_end] + "-" + date;
			}else{
				date_end = m_end + "-" + ndm[m_end] + "-" + date;
			}
			range.push(date_start);
			range.push(date_end);
		}else if (range_mmyyyy.test(date)){
			chkdate = true;
			format = "mm yyyy";
			elements = date.split (/[ ]+/);
			m = elements[0];
			m = m.replace(/^0/, ""); // strip leading zero from single-digit days
			y = elements[1];
			date_start = m + "-" + d_start + "-" + y;
			if (checkLeapYear(y)){
				date_end = m + "-" + ndm_leap[m] + "-" + y;
			}else{
				date_end = m + "-" + ndm[m] + "-" + y;
			}
			range.push(date_start);
			range.push(date_end);
		}else if (range_MMMyyyy.test(date)){
			chkdate = true;
			format = "MMM yyyy";
			elements = date.split (/[ ]+/);
			m = elements[0];
			m = m.toUpperCase();
			y = elements[1];
			date_start = months[m] + "-" + d_start + "-" + y;
			if (checkLeapYear(y)){
				date_end = months[m] + "-" + ndm_leap[months[m]] + "-" + y;
			}else{
				date_end = months[m] + "-" + ndm[months[m]] + "-" + y;
			}
			range.push(date_start);
			range.push(date_end);
		}else{
			format = "Error: <font color='red'>" + date + "</font> is not a valid date format.";
			range.push("N/A");
		}
		if (debug){		// Debugging code
			document.writeln("<b>Format detected</b>: " + format + "<br>\n");
			if (date_start && date_end) {
				document.writeln("<b>Date range</b>: " + date_start + " to " + date_end + "<br>\n");
			}else{
				document.writeln("<b>Date range</b>: " + range + "<br>\n");
			}
		}
	}else{
		range.push("<b>Syntax</b>: getDateRange(date, {debug})");
	}
	if(func == "check"){
		return (chkdate);
	}else{
		return (range);
	}
}
// ========================
// getMultiDates(dates, func=[""|"check"], {debug=[1]})
// Description: Accepts a string of dates and returns them as an array of
//	formatted dates.
// Example Format: Jul 1, 4, 7 2002; Aug 1 - 5 2002
// ========================
function getMultiDates (dates, func, debug) {
	var valid = true;
	var datelist = new Array();
	var tmp_m_days_y = new Array();
	var tmp_mdy = new Array();
	var tmp_days = new Array();
	var comma = new RegExp("\,");
	var dash = new RegExp("\-");
	if (dates){
		// Debugging code
		if (debug){
			document.writeln("<b>Debug mode</b>:<br>\n");
			document.writeln("<b>Input dates</b>: " + dates + "<br>\n");
		}
		// split dates into month sections
		tmp_m_days_y = dates.split (/\;/);
		for (i = 0; i < tmp_m_days_y.length; i++){
			// parse comma-delimited day ranges
			if (comma.test(tmp_m_days_y[i])){
				// trim spaces after commas
				tmp_m_days_y[i] = tmp_m_days_y[i].replace(/\,[ ]+/g, "\,");
				// separate out month, days, and year
				tmp_mdy = tmp_m_days_y[i].split(/[ ]+/);
				// format month
				tmp_m = tmp_mdy[0];
				tmp_m = tmp_m.toUpperCase();
				// separate days
				tmp_days = tmp_mdy[1].split (/\,/);
				// format year
				tmp_y = tmp_mdy[2];
				// create array of dates
				for (j=0; j<tmp_days.length; j++){
					testdate = getSingleDate (months[tmp_m] + "-" + tmp_days[j] + "-" + tmp_y, "check");
					if (testdate == true){
						datelist.push(months[tmp_m] + "-" + tmp_days[j] + "-" + tmp_y);
					}else{
						valid = false;
						datelist.push("Error: invalid date (<font color='red'>" + months[tmp_m] + "-" + tmp_days[j] + "-" + tmp_y + "</font>) in range.");
					}
				}
			}
			// parse dash-delimited day ranges
			else if (dash.test(tmp_m_days_y[i])){
				// trim spaces around dashes
				tmp_m_days_y[i] = tmp_m_days_y[i].replace(/[ ]+\-[ ]+/, "\-");
				tmp_m_days_y[i] = tmp_m_days_y[i].replace(/\-[ ]+/, "\-");
				tmp_m_days_y[i] = tmp_m_days_y[i].replace(/[ ]+\-/, "\-");
				// separate out month, days, and year
				tmp_mdy = tmp_m_days_y[i].split(/[ ]+/);
				// format month
				tmp_m = tmp_mdy[0];
				tmp_m = tmp_m.toUpperCase();
				// separate days
				tmp_days = tmp_mdy[1].split (/\-/);
				// format year
				tmp_y = tmp_mdy[2];
				// create array of dates
				if (parseInt(tmp_days[0],10) < parseInt(tmp_days[1],10))	{
					for (j = parseInt(tmp_days[0],10); j <= parseInt(tmp_days[1],10); j++){
						testdate = getSingleDate (months[tmp_m] + "-" + j + "-" + tmp_y, "check");
						if (testdate == true){
							datelist.push(months[tmp_m] + "-" + j + "-" + tmp_y);
						}else{
							valid = false;
							datelist.push("Error: invalid date (<font color='red'>" + months[tmp_m] + "-" + j + "-" + tmp_y + "</font>) in range.");
						}
					}
				}else{
					valid = false;
					datelist.push("Error: invalid date range (start date <font color='red'>" + tmp_days[0] + "</font> is greater than end date <font color='red'>" + tmp_days[1] + "</font>).");
				}
			}
			// parse single dates
			else{
				tmp_mdy = tmp_m_days_y[i].split(/[ ]+/);
				tmp_m = tmp_mdy[0];
				tmp_m = tmp_m.toUpperCase();
				tmp_d = tmp_mdy[1];
				tmp_y = tmp_mdy[2];
				testdate = getSingleDate (months[tmp_m] + "-" + tmp_d + "-" + tmp_y, "check");
				if (testdate == true){
					datelist.push(months[tmp_m] + "-" + tmp_d + "-" + tmp_y);
				}else{
					valid = false;
					datelist.push("Error: invalid date (<font color='red'>" + months[tmp_m] + "-" + tmp_d + "-" + tmp_y + "</font>) in range.");
				}
			}
		}
		// Debugging code
		if (debug){
			document.writeln("<b>Date list</b>:<br>\n");
			for (x = 0; x < datelist.length; x++){
				document.writeln(datelist[x] + "<br>\n");
			}
		}
	}else{
		datelist.push("<b>Syntax</b>: getMultiDates (dates, func, {debug})");
	}
	if (func == "check"){
		return (valid);
	}else{
		return (datelist);
	}
}
// ===========================
// formatYear(year)
// Description: Accepts a 2-digit year and returns a 4-digit year.
// ===========================
function formatYear (year){
	y = parseInt(year,10);
	if (y > 50 && y <= 99){
		y = 1900 + y;
	}else{
		y = 2000 + y;
	}
	return (y);
}
// ===========================
// checkLeapYear(year)
// Description: Returns true (1) if date is a leap year.
// Leap years are evenly divisible by 4 with the exception of centurial years
// that are not evenly divisible by 400. Therefore, the years 1700, 1800,
// 1900 and 2100 are not leap years, but 1600, 2000, and 2400 are leap years.
// ===========================
function checkLeapYear (year){
	if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)){
		return (1);
	}else{
		return (0);
	}
}
//Adds the specified number of intervals to the passed date.
function dateAdd( start, interval, number ) {
	// Create 3 error messages, 1 for each argument. 
	var startMsg = "Sorry the start parameter of the dateAdd function\n"
		startMsg += "must be a valid date format.\n\n"
		startMsg += "Please try again." ;
	var intervalMsg = "Sorry the dateAdd function only accepts\n"
		intervalMsg += "d, h, m OR s intervals.\n\n"
		intervalMsg += "Please try again." ;
	var numberMsg = "Sorry the number parameter of the dateAdd function\n"
		numberMsg += "must be numeric.\n\n"
		numberMsg += "Please try again." ;
	//Get the milliseconds for this Date object. 
	var buffer = Date.parse( start ) ;
	//Check that the start parameter is a valid Date. 
	if ( isNaN (buffer) ) {
		alert(startMsg);
		return null;
	}
	//Check that an interval parameter was not numeric. 
	if ( interval.charAt == 'undefined' ) {
		// the user specified an incorrect interval, handle the error. 
		alert( intervalMsg ) ;
		return null ;
	}
	// check that the number parameter is numeric. 
	if ( isNaN ( number ) )	{
		alert( numberMsg ) ;
		return null ;
	}
	//Check the add type
	switch (interval.charAt(0)) {
		case 'd': case 'D': 
			number *= 24 ; //days to hours
		case 'h': case 'H':
			number *= 60 ; //hours to minutes
		case 'm': case 'M':
			number *= 60 ; //minutes to seconds
		case 's': case 'S':
			number *= 1000 ; //seconds to milliseconds
			break;
		default:
			alert(intervalMsg); //handle the error, no valid add type
			return null;
	}
	return new Date( buffer + number );
}

//Date format
var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
function LZ(x) {return(x<0||x>9?"":"0")+x}

function formatDate(date,format) {
	format=format+"";
	var result="";
	var i_format=0;
	var c="";
	var token="";
	var y=date.getYear()+"";
	var M=date.getMonth()+1;
	var d=date.getDate();
	var E=date.getDay();
	var H=date.getHours();
	var m=date.getMinutes();
	var s=date.getSeconds();
	var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
	// Convert real date parts into formatted versions
	var value=new Object();
	if (y.length < 4) {y=""+(y-0+1900);}
	value["y"]=""+y;
	value["yyyy"]=y;
	value["yy"]=y.substring(2,4);
	value["M"]=M;
	value["MM"]=LZ(M);
	value["MMM"]=MONTH_NAMES[M-1];
	value["NNN"]=MONTH_NAMES[M+11];
	value["d"]=d;
	value["dd"]=LZ(d);
	value["E"]=DAY_NAMES[E+7];
	value["EE"]=DAY_NAMES[E];
	value["H"]=H;
	value["HH"]=LZ(H);
	if (H==0){value["h"]=12;}
	else if (H>12){value["h"]=H-12;}
	else {value["h"]=H;}
	value["hh"]=LZ(value["h"]);
	if (H>11){value["K"]=H-12;} else {value["K"]=H;}
	value["k"]=H+1;
	value["KK"]=LZ(value["K"]);
	value["kk"]=LZ(value["k"]);
	if (H > 11) { value["a"]="PM"; }
	else { value["a"]="AM"; }
	value["m"]=m;
	value["mm"]=LZ(m);
	value["s"]=s;
	value["ss"]=LZ(s);
	while (i_format < format.length) {
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
			}
		if (value[token] != null) { result=result + value[token]; }
		else { result=result + token; }
		}
	return result;
	}


