/*----------------------------------------------------------------------------\

|                              Date Picker 1.06                               |

|-----------------------------------------------------------------------------|

|                         Created by Erik Arvidsson                           |

|                  (http://webfx.eae.net/contact.html#erik)                   |

|                      For WebFX (http://webfx.eae.net/)                      |

|-----------------------------------------------------------------------------|

|                            A DOM based Date Picker                          |

|-----------------------------------------------------------------------------|

|       Copyright (c) 1999, 2002, 2002, 2003, 2004, 2006 Erik Arvidsson       |

|-----------------------------------------------------------------------------|

| Licensed under the Apache License, Version 2.0 (the "License"); you may not |

| use this file except in compliance with the License.  You may obtain a copy |

| of the License at http://www.apache.org/licenses/LICENSE-2.0                |

| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |

| Unless  required  by  applicable law or  agreed  to  in  writing,  software |

| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |

| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |

| License  for the  specific language  governing permissions  and limitations |

| under the License.                                                          |

|-----------------------------------------------------------------------------|

| Dependencies: datepicker.css      Date picker style declarations            |

|-----------------------------------------------------------------------------|

| 2002-02-10 | Changed _update method to only update the text nodes instead   |

|            | rewriting the entire table. Also added support for mouse wheel |

|            | in IE6.                                                        |

| 2002-01-14 | Cleaned up for 1.0 public version                              |

| 2002-01-15 | Replace all innerHTML calls with DOM1 methods                  |

| 2002-01-18 | Minor IE6 bug that occured when dragging the mouse             |

| 2002-01-19 | Added a popup that is shown when the user clicks on the month. |

|            | This allows navigation to 6 adjacent months.                   |

| 2002-04-10 | Fixed a bug that occured in the popup when a date was selected |

|            | that caused surroundung months to "overflow"                   |

|            | This had the effect that one could get two October months      |

|            | listed.                                                        |

| 2002-09-06 | I had missed one place were window was used instead of         |

|            | doc.parentWindow                                               |

| 2003-08-28 | Added support for ensurin no date overflow when changing       |

|            | months.                                                        |

| 2004-01-10 | Adding type on the buttons to ensure they are not submit       |

|            | buttons. Minor CSS change for CSS2                             |

| 2006-05-28 | Changed license to Apache Software License 2.0.                |

|-----------------------------------------------------------------------------|

| Created 2001-10-?? | All changes are in the log above. | Updated 2006-05-28 |

\----------------------------------------------------------------------------*/



// The DatePicker constructor

// oDate : Date Optional argument representing the date to select

function DatePicker( oDate ) {

	// check arguments

	if ( arguments.length == 0 ) {

		this._selectedDate = new Date;

		this._none = false;

	}

	else {

		this._selectedDate = oDate || new Date();

		this._none = oDate == null;

	}



	this._matrix = [[],[],[],[],[],[],[]];

	this._showNone = true;

	this._showToday = true;

	this._firstWeekDay = 0;	// start week with monday according to standards

	this._redWeekDay = 6;	// sunday is the default red day.



	this._dontChangeNone = false;

}



// two static fields describing the name of the months abd days

DatePicker.months = [

	"January", "February", "March", "April",

	"May", "June", "July", "August",

	"September", "October", "November", "December"];

DatePicker.days = ["m", "t", "w", "t", "f", "s", "s"];





DatePicker.prototype.onchange = function () {};



// create the nodes inside the date picker

DatePicker.prototype.create = function ( doc ) {

	if ( doc == null ) doc = document;



	this._document = doc;



	// create elements

	this._el = doc.createElement( "div" );

	this._el.className = "datePicker";



	// header

	var div = doc.createElement( "div" );

	div.className = "header";

	this._el.appendChild( div );



	var headerTable = doc.createElement( "table" );

	headerTable.className = "headerTable";

	headerTable.cellSpacing = 0;

	div.appendChild( headerTable );



	var tBody = doc.createElement( "tbody" );

	headerTable.appendChild( tBody );



	var tr = doc.createElement( "tr" );

	tBody.appendChild( tr );



	var td = doc.createElement( "td" );

	this._previousMonth = doc.createElement( "button" );

	this._previousMonth.className = "previousButton";

	this._previousMonth.setAttribute("type", "button");

	td.appendChild( this._previousMonth );

	tr.appendChild( td );



	td = doc.createElement( "td" );

	td.className = "labelContainer";

	tr.appendChild( td );



	this._topLabel = doc.createElement( "a" );

	this._topLabel.className = "topLabel";

	this._topLabel.href = "#";

	this._topLabel.appendChild( doc.createTextNode( String.fromCharCode( 160 ) ) );

	td.appendChild( this._topLabel );



	this._labelPopup = doc.createElement( "div" );

	this._labelPopup.className = "labelPopup";

	// no insertion



	td = doc.createElement( "td" );

	this._nextMonth = doc.createElement( "button" );

	this._nextMonth.className = "nextButton";

	this._nextMonth.setAttribute("type", "button");

	td.appendChild( this._nextMonth );

	tr.appendChild( td );



	// grid

	div = doc.createElement( "div" );

	div.className = "grid";

	this._el.appendChild( div );

	this._table = div;



	// footer

	div = doc.createElement( "div" );

	div.className = "footer";

	this._el.appendChild( div );



	var footerTable = doc.createElement( "table" );

	footerTable.className = "footerTable";

	footerTable.cellSpacing = 0;

	div.appendChild( footerTable );



	tBody = doc.createElement( "tbody" );

	footerTable.appendChild( tBody );



	tr = doc.createElement( "tr" );

	tBody.appendChild( tr );



	td = doc.createElement( "td" );

	this._todayButton = doc.createElement( "button" );

	this._todayButton.className = "todayButton";

	this._todayButton.setAttribute("type", "button");

	this._todayButton.appendChild( doc.createTextNode( "Today" ) );

	td.appendChild( this._todayButton );

	tr.appendChild( td );



	td = doc.createElement( "td" );

	td.className = "filler";

	td.appendChild( doc.createTextNode( String.fromCharCode( 160 ) ) );

	tr.appendChild( td );



	td = doc.createElement( "td" );

	this._noneButton = doc.createElement( "button" );

	this._noneButton.className = "noneButton";

	this._noneButton.setAttribute("type", "button");

	this._noneButton.appendChild( doc.createTextNode( "None" ) );

	td.appendChild( this._noneButton );

	tr.appendChild( td );







	this._createTable( doc );



	this._updateTable();

	this._setTopLabel();



	if ( !this._showNone )

		this._noneButton.style.visibility = "hidden";

	if ( !this._showToday )

		this._todayButton.style.visibility = "hidden";



	// IE55+ extension

	this._previousMonth.hideFocus = true;

	this._nextMonth.hideFocus = true;

	this._todayButton.hideFocus = true;

	this._noneButton.hideFocus = true;

	// end IE55+ extension



	// hook up events

	var dp = this;

	// buttons

	this._previousMonth.onclick = function () {

		dp._hideCalendar = false;

		dp._dontChangeNone = true;

		dp.goToPreviousMonth();

		dp._dontChangeNone = false;

	};

	this._nextMonth.onclick = function () {

		this._hideCalendar = false;

		dp._dontChangeNone = true;

		dp.goToNextMonth();

		dp._dontChangeNone = false;

	};

	this._todayButton.onclick = function () {

		dp.goToToday();

	};

	this._noneButton.onclick = function () {

		dp.setDate( null );

	};



	this._el.onselectstart = function () {

		return false;

	};



	this._table.onclick = function ( e ) {

		// find event

		if ( e == null ) e = doc.parentWindow.event;



		// find td

		var el = e.target != null ? e.target : e.srcElement;

		while ( el.nodeType != 1 )

			el = el.parentNode;

		while ( el != null && el.tagName && el.tagName.toLowerCase() != "td" )

			el = el.parentNode;



		// if no td found, return

		if ( el == null || el.tagName == null || el.tagName.toLowerCase() != "td" )

			return;



		var d = new Date( dp._selectedDate );

		var n = Number( el.firstChild.data );

		if ( isNaN( n ) || n <= 0 || n == null )

			return;

		

		dp._hideCalendar = true;

		d.setDate( n );

		dp.setDate( d );

	};



	// show popup

	this._topLabel.onclick = function ( e ) {

		dp._hideCalendar = false;

		dp._showLabelPopup();

		return false;

	};



	this._el.onkeydown = function ( e ) {

		if ( e == null ) e = doc.parentWindow.event;

		var kc = e.keyCode != null ? e.keyCode : e.charCode;



		if ( kc < 37 || kc > 40 ) return true;



		var d = new Date( dp._selectedDate ).valueOf();

		if ( kc == 37 ) // left

			d -= 24 * 60 * 60 * 1000;

		else if ( kc == 39 ) // right

			d += 24 * 60 * 60 * 1000;

		else if ( kc == 38 ) // up

			d -= 7 * 24 * 60 * 60 * 1000;

		else if ( kc == 40 ) // down

			d += 7 * 24 * 60 * 60 * 1000;

		dp._hideCalendar = true;

		dp.setDate( new Date( d ) );

		return false;

	}



	// ie6 extension

	this._el.onmousewheel = function ( e ) {

		if ( e == null ) e = doc.parentWindow.event;

		var n = - e.wheelDelta / 120;

		var d = new Date( dp._selectedDate );

		var m = d.getMonth() + n;

		d.setMonth( m );





		dp._dontChangeNone = true;

		dp.setDate( d );

		dp._dontChangeNone = false;



		return false;

	}



	return this._el;

};



DatePicker.prototype.setDate = function ( oDate ) {



	this._hideLabelPopup();



	// if null then set None

	if ( oDate == null ) {

		if ( !this._none ) {

			this._none = true;

			this._setTopLabel();

			this._updateTable();



			if ( typeof this.onchange == "function" )

				this.onchange();

		}

		return;

	}



	// if string or number create a Date object

	if ( typeof oDate == "string" || typeof oDate == "number" ) {

		oDate = new Date( oDate );

	}





	// do not update if not really changed

	if ( this._selectedDate.getDate() != oDate.getDate() ||

		this._selectedDate.getMonth() != oDate.getMonth() ||

		this._selectedDate.getFullYear() != oDate.getFullYear() ||

		this._none ) {



		if ( !this._dontChangeNone )

			this._none = false;



		this._selectedDate = new Date( oDate );



		this._setTopLabel();

		this._updateTable();



		

	}

	if ( typeof this.onchange == "function" && this._hideCalendar == true ){

		

		this.onchange();

	}

	if ( !this._dontChangeNone )

		this._none = false;

}





DatePicker.prototype.getDate = function () {

	if ( this._none ) return null;

	return new Date( this._selectedDate );	// create a new instance

}



// creates the table elements and inserts them into the date picker

DatePicker.prototype._createTable = function ( doc ) {

	var str, i;

	var rows = 6;

	var cols = 7;

	var currentWeek = 0;



	var table = doc.createElement( "table" );

	table.className = "gridTable";

	table.cellSpacing = 0;



	var tBody = doc.createElement( "tbody" );

	table.appendChild( tBody );



	// days row

	var tr = doc.createElement( "tr" );

	tr.className = "daysRow";



	var td, tn;

	var nbsp = String.fromCharCode( 160 );

	for ( i = 0; i < cols; i++ ) {

		td = doc.createElement( "td" );

		td.appendChild( doc.createTextNode( nbsp ) );

		tr.appendChild( td );

	}

	tBody.appendChild( tr );



	// upper line

	tr = doc.createElement( "tr" );

	td = doc.createElement( "td" );

	td.className = "upperLine";

	td.colSpan = 7;

	tr.appendChild( td );

	tBody.appendChild( tr );



	// rest

	for ( i = 0; i < rows; i++ ) {

		tr = doc.createElement( "tr" );

		for ( var j = 0; j < cols; j++ ) {

			td = doc.createElement( "td" );

			td.appendChild( doc.createTextNode( nbsp ) );

			tr.appendChild( td );

		}

		tBody.appendChild( tr );

	}

	str += "</table>";



	if ( this._table != null )

		this._table.appendChild( table )

};

// this method updates all the text nodes inside the table as well

// as all the classNames on the tds

DatePicker.prototype._updateTable = function () {

	// if no element no need to continue

	if ( this._table == null ) return;



	var i;

	var str = "";

	var rows = 6;

	var cols = 7;

	var currentWeek = 0;



	var cells = new Array( rows );

	this._matrix = new Array( rows )

	for ( i = 0; i < rows; i++ ) {

		cells[i] = new Array( cols );

		this._matrix[i] = new Array( cols );

	}



	// Set the tmpDate to this month

	var tmpDate = new Date( this._selectedDate.getFullYear(),

							this._selectedDate.getMonth(), 1 );

	var today = new Date();

	// go thorugh all days this month and store the text

	// and the class name in the cells matrix

	for ( i = 1; i < 32; i++ ) {

		tmpDate.setDate( i );

		// convert to ISO, Monday is 0 and 6 is Sunday

		var weekDay = ( tmpDate.getDay() + 6 ) % 7;

		var colIndex = ( weekDay - this._firstWeekDay + 7 ) % 7;

		if ( tmpDate.getMonth() == this._selectedDate.getMonth() ) {



			var isToday = tmpDate.getDate() == today.getDate() &&

						tmpDate.getMonth() == today.getMonth() &&

						tmpDate.getFullYear() == today.getFullYear();



			cells[currentWeek][colIndex] = { text: "", className: "" };



			if ( this._selectedDate.getDate() == tmpDate.getDate() && !this._none )

				cells[currentWeek][colIndex].className += "selected ";

			if ( isToday )

				cells[currentWeek][colIndex].className += "today ";

			if ( ( tmpDate.getDay() + 6 ) % 7 == this._redWeekDay ) // ISO

				cells[currentWeek][colIndex].className += "red";



			cells[currentWeek][colIndex].text =

				this._matrix[currentWeek][colIndex] = tmpDate.getDate();



			if ( colIndex == 6 )

				currentWeek++;

		}

	}



	// fix day letter order if not standard

	var weekDays = DatePicker.days;

	if (this._firstWeekDay != 0) {

		weekDays = new Array(7);

		for ( i = 0; i < 7; i++)

			weekDays[i] = DatePicker.days[ (i + this._firstWeekDay) % 7];

	}



	// update text in days row

	var tds = this._table.firstChild.tBodies[0].rows[0].cells;

	for ( i = 0; i < cols; i++ )

		tds[i].firstChild.data = weekDays[i];



	// update the text nodes and class names

	var trs = this._table.firstChild.tBodies[0].rows;

	var tmpCell;

	var nbsp = String.fromCharCode( 160 );

	for ( var y = 0; y < rows; y++ ) {

		for (var x = 0; x < cols; x++) {

			tmpCell = trs[y + 2].cells[x];

			if ( typeof cells[y][x] != "undefined" ) {

				tmpCell.className = cells[y][x].className;

				tmpCell.firstChild.data = cells[y][x].text;

			}

			else {

				tmpCell.className = "";

				tmpCell.firstChild.data = nbsp;

			}

		}

	}

}



// sets the label showing the year and selected month

DatePicker.prototype._setTopLabel = function () {

	var str = this._selectedDate.getFullYear() + " " + DatePicker.months[ this._selectedDate.getMonth() ];

	if ( this._topLabel != null )

		this._topLabel.lastChild.data = str;

}



DatePicker.prototype.goToNextMonth = function () {

	var d = new Date( this._selectedDate );

	d.setDate( Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() + 1,

		d.getFullYear())) ); // no need to catch dec -> jan for the year

	d.setMonth( d.getMonth() + 1 );

	this.setDate( d );

}



DatePicker.prototype.goToPreviousMonth = function () {

	var d = new Date( this._selectedDate );

	d.setDate( Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() - 1,

		d.getFullYear())) ); // no need to catch jan -> dec for the year

	d.setMonth( d.getMonth() - 1 );

	this.setDate( d );

}



DatePicker.prototype.goToToday = function () {

	if ( this._none )

		// change the selectedDate to force update if none was true

		this._selectedDate = new Date( this._selectedDate + 10000000000 );

	this._none = false;

	this.setDate( new Date() );

}



DatePicker.prototype.setShowToday = function ( bShowToday ) {

	if ( typeof bShowToday == "string" )

		bShowToday = !/false|0|no/i.test( bShowToday );



	if ( this._todayButton != null )

		this._todayButton.style.visibility = bShowToday ? "visible" : "hidden";

	this._showToday = bShowToday;

}



DatePicker.prototype.getShowToday = function () {

	return this._showToday;

}



DatePicker.prototype.setShowNone = function ( bShowNone ) {

	if ( typeof bShowNone == "string" )

		bShowNone = !/false|0|no/i.test( bShowNone );



	if ( this._noneButton != null )

		this._noneButton.style.visibility = bShowNone ? "visible" : "hidden";

	this._showNone = bShowNone;

}



DatePicker.prototype.getShowNone = function () {

	return this._showNone;

}



// 0 is monday and 6 is sunday as in the ISO standard

DatePicker.prototype.setFirstWeekDay = function ( nFirstWeekDay ) {

	if ( this._firstWeekDay != nFirstWeekDay ) {

		this._firstWeekDay = nFirstWeekDay;

		this._updateTable();

	}

}



DatePicker.prototype.getFirstWeekDay = function () {

	return this._firstWeekDay;

}



// 0 is monday and 6 is sunday as in the ISO standard

DatePicker.prototype.setRedWeekDay = function ( nRedWeekDay ) {

	if ( this._redWeekDay != nRedWeekDay ) {

		this._redWeekDay = nRedWeekDay;

		this._updateTable();

	}

}



DatePicker.prototype.getRedWeekDay = function () {

	return this._redWeekDay;

}





DatePicker.prototype._showLabelPopup = function () {



	/*

	this._labelPopup document.createElement( "DIV" );

	div.className = "month-popup";

	div.noWrap = true;

	el.unselectable = div.unselectable = "on";

	el.onselectstart = div.onselectstart = function () { return false; };

	*/



	var dateContext = function ( dp, d ) {

		return function ( e ) {

			dp._dontChangeNone = true;

			dp._hideLabelPopup();

			dp.setDate( d );

			dp._dontChangeNone = false;

			return false;

		};

	};



	var dp = this;



	// clear all old elements in the popup

	while ( this._labelPopup.hasChildNodes() )

		this._labelPopup.removeChild( this._labelPopup.firstChild );



	var a, tmp, tmp2;

	for ( var i = -3; i < 4; i++ ) {

		tmp = new Date( this._selectedDate );

		tmp2 = new Date( this._selectedDate );	// need another tmp to catch year change when checking leap

		tmp2.setDate(1);

		tmp2.setMonth( tmp2.getMonth() + i );

		tmp.setDate( Math.min(tmp.getDate(), DatePicker.getDaysPerMonth(tmp.getMonth() + i,

			tmp2.getFullYear())) );

		tmp.setMonth( tmp.getMonth() + i );



		a = this._document.createElement( "a" );

		a.href = "javascript:void 0;";

		a.onclick = dateContext( dp, tmp );

		a.appendChild( this._document.createTextNode( tmp.getFullYear() + " " +

									DatePicker.months[ tmp.getMonth() ] ) );

		if ( i == 0 )

			a.className = "selected";

		this._labelPopup.appendChild( a );

	}



	this._topLabel.parentNode.insertBefore( this._labelPopup, this._topLabel.parentNode.firstChild );

};



DatePicker.prototype._hideLabelPopup = function () {

	if ( this._labelPopup.parentNode )

		this._labelPopup.parentNode.removeChild( this._labelPopup );

};



DatePicker._daysPerMonth = [31,28,31,30,31,30,31,31,30,31,30,31];

DatePicker.getDaysPerMonth = function (nMonth, nYear) {

	nMonth = (nMonth + 12) % 12;

	var res = DatePicker._daysPerMonth[nMonth];

	if (nMonth == 1) {

		res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0;

	}

	return res;

};



function getFullISODateString(d)

{

 var year = d.getFullYear();

 var month = leadingZero(d.getMonth()+1);

 var day = leadingZero(d.getDate());



 var date = year+"-"+month+"-"+day;

 return date;

}



function leadingZero(x){

 return (x>9)?x:'0'+x;

}
