/**
Use an "iFrame shim" to deal with problems where the datepicker shows up behind
selection list elements, if they're below the datepicker. The problem and solution are
described at:
http://dotnetjunkies.com/WebLog/jking/archive/2003/07/21/488.aspx
http://dotnetjunkies.com/WebLog/jking/archive/2003/10/30/2975.aspx
*/
function adjustiFrame(popupDiv)
{
	var iFrameDiv = document.getElementById("popupIframe");
	if(!iFrameDiv) 
	{
		iFrameDiv = document.createElement("iFrame");
		iFrameDiv.setAttribute("id", "popupIframe");
		iFrameDiv.setAttribute("src", "javascript:false;");
		iFrameDiv.setAttribute("scrolling", "no");
		iFrameDiv.setAttribute("frameborder", "0");
		document.body.appendChild(iFrameDiv);
	}
	try 
	{
		iFrameDiv.style.position = "absolute";
		iFrameDiv.style.width = popupDiv.offsetWidth+"px";
		iFrameDiv.style.height = popupDiv.offsetHeight+"px";
		iFrameDiv.style.top = popupDiv.style.top;
		iFrameDiv.style.left = popupDiv.style.left;
		iFrameDiv.style.zIndex = popupDiv.style.zIndex-1;
		iFrameDiv.style.visibility = popupDiv.style.visibility;
	} 
	catch(e){}
}	
/**
 * @param date Date object
 * @param format Date format
 * @return a date in the output format specified as dateFormat
 * The format string uses the same abbreviations as in getDateFromFormat()
 */
function formatDate(date,format) 
{
	var result="";
	var i_format=0;
	var c="";
	var token="";
	var y = date.getFullYear();
	var M = date.getMonth();
	var d=date.getDate();
	var E=date.getDay();
	var H=date.getHours();
	var m=date.getMinutes();
	var s=date.getSeconds();
	// Convert real date parts into formatted versions
	var value=new Object();
	//if ((""+y).length < 4) {y=""+(y-0+1900);}
	value["y"]=y+"";
	value["yyyy"]=value["y"];
	value["yy"]=value["y"].substring(2,4);
	value["M"]=""+M+1;
	value["MM"]=LZ(M+1);
	value["MMM"]=monthsShort[date.getMonth()];
	value["MMMM"]=monthsLong[date.getMonth()];
	value["E"]=daysShort[date.getDay()];
	value["EEEE"]=daysLong[date.getDay()];
	value["d"]=d;
	value["dd"]=LZ(d);
	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;
}
/**
 * @param value
 * @param format
 *            Date format
 * @return a date object This function takes a date string and a format string.
 *         It matches If the date string matches the format string, it returns
 *         the getTime() of the date. If it does not match, it returns 0.
 */
function parseDate(val, format) {
	val = val + "";
	format = format + "";
	var i_val = 0;
	var i_format = 0;
	var c = "";
	var token = "";
	var token2 = "";
	var x, y;
	var now = new Date();
	var year = now.getYear();
	var month = now.getMonth() + 1;
	var date = 1;
	var hh = now.getHours();
	var mm = now.getMinutes();
	var ss = now.getSeconds();
	var ampm = "";

	while (i_format < format.length) {
		// Get next token from format string
		c = format.charAt(i_format);
		token = "";
		while ((format.charAt(i_format) == c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
		}

		// Year Tokens
		if (token == "yyyy" || token == "yy" || token == "y") {
			if (token == "yyyy") {
				x = 4;
				y = 4;
			}
			if (token == "yy") {
				x = 2;
				y = 2;
			}
			if (token == "y") {
				x = 2;
				y = 4;
			}
			year = getInt(val, i_val, x, y);
			if (year == null) {
				return new Date();
			}
			i_val += year.length;
			if (year.length == 2) {
				if (year > 70) {
					year = 1900 + (year - 0);
				} else {
					year = 2000 + (year - 0);
				}
			}
		}
		// Month name Tokens
		else if (token == "MMMM") {
			month = 0;
			for ( var i = 0; i < monthsLong.length; i++) {
				var month_name = monthsLong[i];
				if (val.substring(i_val, i_val + month_name.length)
						.toLowerCase() == month_name.toLowerCase()) {
					month = i + 1;
					i_val += month_name.length;
					break;
				}
			}
			if ((month < 1) || (month > 12)) {
				return new Date();
			}
		} else if (token == "MMM") {
			month = 0;
			for ( var i = 0; i < monthsShort.length; i++) {
				var month_name = monthsShort[i];
				if (val.substring(i_val, i_val + month_name.length)
						.toLowerCase() == month_name.toLowerCase()) {
					month = i + 1;
					i_val += month_name.length;
					break;
				}
			}
			if ((month < 1) || (month > 12)) {
				return new Date();
			}
		}
		// Month number tokens
		else if (token == "MM" || token == "M") {
			month = getInt(val, i_val, token.length, 2);
			if (month == null || (month < 1) || (month > 12)) {
				return new Date();
			}
			i_val += month.length;
		}
		// Weekday long name token
		else if (token == "EEEE") {
			for ( var i = 0; i < daysLong.length; i++) {
				var day_name = daysLong[i];
				if (val.substring(i_val, i_val + day_name.length).toLowerCase() == day_name
						.toLowerCase()) {
					i_val += day_name.length;
					break;
				}
			}
		}
		// Weekday short name token
		else if (token == "E") {
			for ( var i = 0; i < daysShort.length; i++) {
				var day_name = daysShort[i];
				if (val.substring(i_val, i_val + day_name.length).toLowerCase() == day_name
						.toLowerCase()) {
					i_val += day_name.length;
					break;
				}
			}
		}
		// Monthday number tokens
		else if (token == "dd" || token == "d") {
			date = getInt(val, i_val, token.length, 2);
			if (date == null || (date < 1) || (date > 31)) {
				return new Date();
			}
			i_val += date.length;
		}
		// 12h hour tokens
		else if (token == "hh" || token == "h") {
			hh = getInt(val, i_val, token.length, 2);
			if (hh == null || (hh < 1) || (hh > 12)) {
				return new Date();
			}
			i_val += hh.length;
		}
		// 24h hour tokens
		else if (token == "HH" || token == "H") {
			hh = getInt(val, i_val, token.length, 2);
			if (hh == null || (hh < 0) || (hh > 23)) {
				return new Date();
			}
			i_val += hh.length;
		} else if (token == "KK" || token == "K") {
			hh = getInt(val, i_val, token.length, 2);
			if (hh == null || (hh < 0) || (hh > 11)) {
				return new Date();
			}
			i_val += hh.length;
		} else if (token == "kk" || token == "k") {
			hh = getInt(val, i_val, token.length, 2);
			if (hh == null || (hh < 1) || (hh > 24)) {
				return new Date();
			}
			i_val += hh.length;
			hh--;
		} else if (token == "mm" || token == "m") {
			mm = getInt(val, i_val, token.length, 2);
			if (mm == null || (mm < 0) || (mm > 59)) {
				return new Date();
			}
			i_val += mm.length;
		} else if (token == "ss" || token == "s") {
			ss = getInt(val, i_val, token.length, 2);
			if (ss == null || (ss < 0) || (ss > 59)) {
				return new Date();
			}
			i_val += ss.length;
		} else if (token == "a") {
			if (val.substring(i_val, i_val + 2).toLowerCase() == "am") {
				ampm = "AM";
			} else if (val.substring(i_val, i_val + 2).toLowerCase() == "pm") {
				ampm = "PM";
			} else {
				return new Date();
			}
			i_val += 2;
		} else {
			if (val.substring(i_val, i_val + token.length) != token) {
				return new Date();
			} else {
				i_val += token.length;
			}
		}
	}
	// If there are any trailing characters left in the value, it doesn't match
	if (i_val != val.length) {
		return new Date();
	}
	// Is date valid for month?
	if (month == 2) {
		// Check for leap year
		if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) { // leap year
			if (date > 29) {
				return new Date();
			}
		} else {
			if (date > 28) {
				return new Date();
			}
		}
	}
	if ((month == 4) || (month == 6) || (month == 9) || (month == 11)) {
		if (date > 30) {
			return new Date();
		}
	}
	// Correct hours value
	if (hh < 12 && ampm == "PM") {
		hh = hh - 0 + 12;
	} else if (hh > 11 && ampm == "AM") {
		hh -= 12;
	}
	return new Date(year, month - 1, date, hh, mm, ss);
}

/**
 * Utility functions for parsing in getDateFromFormat()
 */	
function isInt(val) 
{
	var digits="1234567890";
	for (var i=0; i < val.length; i++) 
	{
		if (digits.indexOf(val.charAt(i))==-1){return false;}
	}
	return true;
}

function isDate(val,format) 
{
	var date=getDateFromFormat(val,format);
	if (date==0) { return false; }
	return true;
}
function LZ(x) {return(x<0||x>9?"":"0")+x}	


/**
TODO: Implement week numbers

This is a JavaScript library that will allow you to easily add some basic DHTML
drop-down datepicker functionality to your forms and pages. This script is not as
full-featured as others you may find on the Internet, but it's free, it's easy to
understand, and it's easy to change.

You'll also want to include a stylesheet that makes the datepicker elements
look nice. Example styles have been included directly in this HTML page for ease
of reference.

I've tested this lightly with Internet Explorer 6 and Mozilla Firefox. I have no idea
how compatible it is with other browsers. You are free to use this in any way you'd
like, with no charge or obligation.

version 1.4
December 20, 2004
Julian Robichaux -- http://www.nsftools.com

HISTORY
--  version 1.0 (Sept. 4, 2004):
Initial release.

--  version 1.1 (Sept. 5, 2004):
Added capability to define the date format to be used, either globally (using the
defaultDateSeparator and defaultDateFormat variables) or when the displayDatePicker
function is called.

--  version 1.2 (Sept. 7, 2004):
Fixed problem where datepicker x-y coordinates weren't right inside of a table.
Fixed problem where datepicker wouldn't display over selection lists on a page.
Added a call to the datePickerClosed function (if one exists) after the datepicker 
is closed, to allow the developer to add their own custom validation after a date
has been chosen. For this to work, you must have a function called datePickerClosed
somewhere on the page, that accepts a field object as a parameter. See the
example in the comments of the updateDateField function for more details.

--  version 1.3 (Sept. 9, 2004)
Fixed problem where adding the <div> and <iFrame> used for displaying the datepicker
was causing problems on IE 6 with global variables that had handles to objects on
the page (I fixed the problem by adding the elements using document.createElement()
and document.body.appendChild() instead of document.body.innerHTML += ...).

--  version 1.4 (Dec. 20, 2004)
Added "targetDateField.focus();" to the updateDateField function (as suggested 
by Alan Lepofsky) to avoid a situation where the cursor focus is at the top of the 
form after a date has been picked. Added "padding: 0px;" to the dpButton CSS 
style, to keep the table from being so wide when displayed in Firefox.
*/

var datePickerDivID = "datePicker";
var crlf = "\r\n";
var TABLE = "<table cols=7 class='DatePicker' cellpadding='2' cellspacing='0'>" + crlf;
var TR = "<tr class='DatePicker'>";
var TR_title = "<tr class='DatePickerTitle'>";
var TD = "<td class='DatePicker'";//leave this tag open, we'll be adding events
var TD_selected = "<td class='DatePickerSelected'";//leave this tag open, we'll be adding events
var TD_button = "<td class='DatePickerButton'>";
var TD_day = "<td class='DatePickerDay'>";
var TD_title = "<td colspan=5 class='DatePickerTitle'>";
var TD_days = "<td class='DatePickerTD'>";
var xTABLE = "</table>" + crlf;
var xTR = "</tr>" + crlf;
var xTD = "</td>" + crlf;
var xDIV = "</div>" + crlf;

/**
This is the main function you'll call from the onClick event of a button.
Normally, you'll have something like this on your HTML page:

Start Date: <input name="StartDate"> 
<input type=button value="select" onclick="displayDatePicker('StartDate');">

That will cause the datepicker to be displayed beneath the StartDate field and
any date that is chosen will update the value of that field. If you'd rather have the
datepicker display beneath the button that was clicked, you can code the button
like this:

<input type=button value="select" onclick="displayDatePicker('StartDate', this);">

So, pretty much, the first argument (dateFieldName) is a string representing the
name of the field that will be modified if the user picks a date, and the second
argument (displayBelowThisObject) is optional and represents an actual node
on the HTML document that the datepicker should be displayed below.

In version 1.1 of this code, the dtFormat and dtSep variables were added, allowing
you to use a specific date format or date separator for a given call to this function.
Normally, you'll just want to set these defaults globally with the defaultDateSeparator
and defaultDateFormat variables, but it doesn't hurt anything to add them as optional
parameters here. An example of use is:

<input type=button value="select" onclick="displayDatePicker('StartDate', false, 'dmy', '.');">

This would display the datepicker beneath the StartDate field (because the 
displayBelowThisObject parameter was false), and update the StartDate field with
the chosen value of the datepicker using a date format of dd.mm.yyyy
*/
function displayDatePicker(event, searchFrom, dateFormat)
{
	var row = getEnclosingElem(searchFrom, "tr");
	var targetField;

	var exit = false;
	map(row.getElementsByTagName("*"), function(o) {
		if (exit) return;
		if (/input/i.test(o.tagName) && o.type != "hidden" && o.style.display != "none")
			targetField = o;
		if (searchFrom == o) exit = true;
	});
	if(targetField!=null)
	{
		if(!document.getElementById(datePickerDivID)){drawDatePicker(dateFormat);} 
		showDatePicker(event, targetField,dateFormat);
	}
}
/**
 *	Draw the Div for the DatePicker
 */
function drawDatePicker(dateFormat)
{
	//the datepicker table will be drawn inside of a <div> with an ID defined by the
	//global datePickerDivID variable. If such a div doesn't yet exist on the HTML
	//document we're working with, add one.
	var newNode = document.createElement("div");
	newNode.setAttribute("id", datePickerDivID);
	newNode.setAttribute("class", "DatePicker");
	newNode.setAttribute("style", "visibility:hidden;");
	document.body.appendChild(newNode);
}
/**
 *	Show the DatePicker Div at the correct locatie with the Value of the Target Field
 */
function showDatePicker(event, targetField,dateFormat)
{
	var dt = parseDate(targetField.value,dateFormat);
	//move the datepicker div to the proper x,y coordinate and toggle the visiblity
	var pickerDiv = document.getElementById(datePickerDivID);
	pickerDiv.style.position = "absolute";
	pickerDiv.style.visibility = (pickerDiv.style.visibility=="visible"?"hidden":"visible");
	pickerDiv.style.zIndex = 10001;
	
	//draw the datepicker table
	refreshDatePicker(targetField.id,dateFormat, dt.getFullYear(), dt.getMonth(), dt.getDate());

	var yPos = event.clientY;
	if (event.clientY + 100 >= document.body.clientHeight)
		yPos = document.body.clientHeight - 100;
	
	//offsetWidth and offsetHeight are known after refresh
	pickerDiv.style.left = (event.clientX-pickerDiv.offsetWidth - 10)+"px";
	pickerDiv.style.top = yPos + "px";
	adjustiFrame(pickerDiv);
}
/**
 *	This is the function that actually draws the datepicker calendar.
 */
function refreshDatePicker(dateFieldId, dateFormat, year, month, day)
{
  //if no arguments are passed, use today's date; otherwise, month and year
  //are required (if a day is passed, it will be highlighted later)
  var thisDay = new Date();  
  if ((month >= 0) && (year > 0)) 
  {
    thisDay = new Date(year, month, 1);
  } 
  else 
  {
    day = thisDay.getDate();
    thisDay.setDate(1);
  }
  thisDay.setHours(14,00);
  //start generating the code for the calendar table
  var html = TABLE;  
  //this is the title bar, which displays the month and the buttons to
  //go back to a previous month or forward to the next month
  html += TR_title;
  html += TD_button + getButtonCode(dateFieldId, dateFormat, thisDay, -1, "prev.gif") + xTD;
  html += TD_title + monthsLong[thisDay.getMonth()] + " " + thisDay.getFullYear() + xTD;
  html += TD_button + getButtonCode(dateFieldId, dateFormat, thisDay, 1, "next.gif") + xTD;
  html += xTR;
  
  // this is the row that indicates which day of the week we're on
  html += TR;
  for(i=0; i<daysShort.length; i++){html += TD_day + daysShort[i] + xTD;}
  html += xTR;

  // now we'll start populating the table with days of the month
  html += TR;
  
  //first, the leading blanks
  for (i = 0; i < thisDay.getDay(); i++){html+=TD_days+"&nbsp;"+xTD;}
  
  // now, the days of the month
  do
  {
    dayNum = thisDay.getDate();
    TD_onclick = " onclick=\"updateDateField('" + dateFieldId + "', '" + formatDate(thisDay,dateFormat) + "');\">";
    
    
    
    if (dayNum == day)
    {
    	html += TD_selected + TD_onclick + dayNum + xTD;
   	}
    else
    {
    	TD_onmouseover = " onmouseover=\"dateHover(this)\"";
    	TD_onmouseout = " onmouseout=\"dateOut(this)\"";
    	TD_events = TD_onmouseover + TD_onmouseout + TD_onclick;
    	html += TD + TD_events + dayNum + xTD;
    }
    
    //if this is a Saturday, start a new row
    if(thisDay.getDay()==6){html+=xTR+TR;}
    
    // increment the day
    thisDay.setDate(thisDay.getDate() + 1);
  } 
  while (thisDay.getDate() > 1)
  
  // fill in any trailing blanks
  if (thisDay.getDay() > 0) 
  {
    for (i = 6; i > thisDay.getDay(); i--)
    {
      html += TD + "&nbsp;" + xTD;
    }
  }
  html += xTR;
  
  // and finally, close the table
  html += xTABLE;
  var datePickerDiv = document.getElementById(datePickerDivID);
  datePickerDiv.innerHTML = html;
  // add an "iFrame shim" to allow the datepicker to display above selection lists
  adjustiFrame(datePickerDiv);
}
/** 
 *	Hover functions
 */
function dateHover(element)
{
	element.className = 'DatePickerHover';
}
function dateOut(element)
{
	element.className = 'DatePicker';
}
/**
 *	Try to split a date string into an array of elements, using common date separators.
 *	If the date is split, an array is returned; otherwise, we just return false.
 */
function splitDateString(dateString)
{
  var dArray;
  if (dateString.indexOf("/") >= 0) dArray = dateString.split("/");
  else if (dateString.indexOf(".") >= 0) dArray = dateString.split(".");
  else if (dateString.indexOf("-") >= 0) dArray = dateString.split("-");
  else if (dateString.indexOf("\\") >= 0) dArray = dateString.split("\\");
  else dArray = false;  
  return dArray;
}

function updateDateField(dateFieldId, dateString)
{
  var targetDateField = document.getElementById(dateFieldId);
  if(dateString){targetDateField.value = dateString;$(targetDateField).trigger('change')};
  var datePickerDiv = document.getElementById(datePickerDivID);
  datePickerDiv.style.visibility = "hidden";
  adjustiFrame(datePickerDiv);
  targetDateField.focus();
}
/**
 *	Convenience function for writing the code for the buttons that bring us back or forward
 * 	a month.
 */
function getButtonCode(dateFieldId, dateFormat,dateVal, adjust, src)
{
  var newMonth = (dateVal.getMonth() + adjust) % 12;
  var newYear = dateVal.getFullYear() + parseInt((dateVal.getMonth() + adjust) / 12);
  if(newMonth<0) 
  {
    newMonth += 12;
    newYear += -1;
  }
  src = imageroot+"/icons/"+src;
  return "<img src='"+src+"' class='Icon' onClick='refreshDatePicker(\"" + dateFieldId + "\", \""+dateFormat+"\", " + newYear + ", " + newMonth + ");'>";
}		