Prado.WebUI.TDatePicker = Class.create();
Prado.WebUI.TDatePicker.prototype = 
{
	MonthNames : [	"January",		"February",		"March",	"April",
		"May",			"June",			"July",		"August",
		"September",	"October",		"November",	"December"
	],

	ShortWeekDayNames : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],

	Format : "yyyy-MM-dd",

	FirstDayOfWeek : 1, // 0 for sunday
	
	ClassName : "TDatePicker",

	FromYear : 2000, UpToYear: 2015,
	
	initialize : function(control, attr)
	{
		this.attr = attr || [];
		this.control = $(control);	
		this.dateSlot = new Array(42);
		this.weekSlot = new Array(6);
		this.minimalDaysInFirstWeek	= 4;
		this.selectedDate = this.newDate();
		
		//which element to trigger to show the calendar
		if(this.attr.Trigger)
		{
			this.trigger = $(this.attr.Trigger) ;
			var triggerEvent = this.attr.TriggerEvent || "click";
		}
		else
		{
			this.trigger  = this.control;
			var triggerEvent = this.attr.TriggerEvent || "focus";
		}
		
		Event.observe(this.trigger, triggerEvent, this.show.bindEvent(this));
			
		Object.extend(this,attr);

		this.create();	
	},

	create : function()
	{
		var div;
		var table;
		var tbody;
		var tr;
		var td;
	
		// Create the top-level div element
		this._calDiv = document.createElement("div");
		this._calDiv.className = this.ClassName;
		this._calDiv.style.display = "none";		
		this._calDiv.style.position = "absolute"
		
		// header div
		div = document.createElement("div");
		div.className = "calendarHeader";
		this._calDiv.appendChild(div);
		
		table = document.createElement("table");
		table.style.cellSpacing = 0;
		div.appendChild(table);
		
		tbody = document.createElement("tbody");
		table.appendChild(tbody);
		
		tr = document.createElement("tr");
		tbody.appendChild(tr);
		
		// Previous Month Button
		td = document.createElement("td");
		var previousMonth = document.createElement("button");
		previousMonth.className = "prevMonthButton";
		previousMonth.appendChild(document.createTextNode("<<"));
		td.appendChild(previousMonth);
		tr.appendChild(td);
		
		
		
		//
		// Create the month drop down 
		//
		td = document.createElement("td");
		tr.appendChild(td);
		this._monthSelect = document.createElement("select");
		this._monthSelect.className = "months";
	    for (var i = 0 ; i < this.MonthNames.length ; i++) {
	        var opt = document.createElement("option");
	        opt.innerHTML = this.MonthNames[i];
	        opt.value = i;
	        if (i == this.selectedDate.getMonth()) {
	            opt.selected = true;
	        }
	        this._monthSelect.appendChild(opt);
	    }
		td.appendChild(this._monthSelect);
		

		// 
		// Create the year drop down
		//
		td = document.createElement("td");
		td.className = "labelContainer";
		tr.appendChild(td);
		this._yearSelect = document.createElement("select");
		for(var i=this.FromYear; i <= this.UpToYear; ++i) {
			var opt = document.createElement("option");
			opt.innerHTML = i;
			opt.value = i;
			if (i == this.selectedDate.getFullYear()) {
				opt.selected = false;
			}
			this._yearSelect.appendChild(opt);
		}
		td.appendChild(this._yearSelect);
		
		
		td = document.createElement("td");
		td.className = "nextMonthButton";
		var nextMonth = document.createElement("button");
		nextMonth.appendChild(document.createTextNode(">>"));
		td.appendChild(nextMonth);
		tr.appendChild(td);
		
		// Calendar body
		div = document.createElement("div");
		div.className = "calendarBody";
		this._calDiv.appendChild(div);
		var calendarBody = div;
		
		// Create the inside of calendar body	
		
		var text;
		table = document.createElement("table");
		table.className = "grid";
	
	    div.appendChild(table);
		var thead = document.createElement("thead");
		table.appendChild(thead);
		tr = document.createElement("tr");
		thead.appendChild(tr);
		
		for(i=0; i < 7; ++i) {
			td = document.createElement("th");
			text = document.createTextNode(this.ShortWeekDayNames[(i+this.FirstDayOfWeek)%7]);
			td.appendChild(text);
			td.className = "weekDayHead";
			tr.appendChild(td);
		}
		
		// Date grid
		tbody = document.createElement("tbody");
		table.appendChild(tbody);
		
		for(week=0; week<6; ++week) {
			tr = document.createElement("tr");
			tbody.appendChild(tr);

		for(day=0; day<7; ++day) {
				td = document.createElement("td");
				td.className = "calendarDate";
				text = document.createTextNode(String.fromCharCode(160));
				td.appendChild(text);

				tr.appendChild(td);
				var tmp = new Object();
				tmp.tag = "DATE";
				tmp.value = -1;
				tmp.data = text;
				this.dateSlot[(week*7)+day] = tmp;
				
				Event.observe(td, "mouseover", this.hover.bindEvent(this));
				Event.observe(td, "mouseout", this.hover.bindEvent(this));
				
			}
		}
		
		// Calendar Footer
		div = document.createElement("div");
		div.className = "calendarFooter";
		this._calDiv.appendChild(div);

		var todayButton = document.createElement("button");
		todayButton.className = "todayButton";
		var today = this.newDate();
		var buttonText = today.SimpleFormat(this.Format);
		todayButton.appendChild(document.createTextNode(buttonText));
		div.appendChild(todayButton);
		
		/*var clearButton = document.createElement("button");
		clearButton.className = "clearButton";
		buttonText = "Clear";
		clearButton.appendChild(document.createTextNode(buttonText));
		div.appendChild(clearButton);
		*/

		if(Prado.Browser().ie)
		{
			this.iePopUp = document.createElement('iframe');
			this.iePopUp.src = "";
			this.iePopUp.style.position = "absolute"
			this.iePopUp.scrolling="no"
			this.iePopUp.frameBorder="0"
			document.body.appendChild(this.iePopUp);
		}

		document.body.appendChild(this._calDiv);
		
		this.update();
		this.updateHeader();
		
		this.ieHack(true);

		// IE55+ extension		
		previousMonth.hideFocus = true;
		nextMonth.hideFocus = true;
		todayButton.hideFocus = true;
		// end IE55+ extension
		
		// hook up events
		Event.observe(previousMonth, "click", this.prevMonth.bindEvent(this));
		Event.observe(nextMonth, "click", this.nextMonth.bindEvent(this));
		Event.observe(todayButton, "click", this.selectToday.bindEvent(this));
		//Event.observe(clearButton, "click", this.clearSelection.bindEvent(this));
		Event.observe(this._monthSelect, "change", this.monthSelect.bindEvent(this));
		Event.observe(this._yearSelect, "change", this.yearSelect.bindEvent(this));

		// ie6 extension
		Event.observe(this._calDiv, "mousewheel", this.mouseWheelChange.bindEvent(this));		
		
		Event.observe(calendarBody, "click", this.selectDate.bindEvent(this));
				
	},
	
	ieHack : function(cleanup) 
	{
		// IE hack
		if(this.iePopUp) 
		{
			this.iePopUp.style.display = "block";
			this.iePopUp.style.top = (this._calDiv.offsetTop -1 ) + "px";
			this.iePopUp.style.left = (this._calDiv.offsetLeft -1)+ "px";
			this.iePopUp.style.width = Math.abs(this._calDiv.offsetWidth -2)+ "px";
			this.iePopUp.style.height = (this._calDiv.offsetHeight + 1)+ "px";
			if(cleanup) this.iePopUp.style.display = "none";
		}
	},

	keyPressed : function(ev)
	{
		if(!this.showing) return;
		if (!ev) ev = document.parentWindow.event;
		var kc = ev.keyCode != null ? ev.keyCode : ev.charCode;
		
		if(kc == Event.KEY_RETURN)
		{
			this.setSelectedDate(this.selectedDate);
			Event.stop(ev);
			this.hide();
		}
		if(kc == Event.KEY_ESC)
		{
			Event.stop(ev); this.hide();
		}
		
		
		var getDaysPerMonth = function (nMonth, nYear) 
		{
			nMonth = (nMonth + 12) % 12;
	        var days= [31,28,31,30,31,30,31,31,30,31,30,31];
			var res = days[nMonth];
			if (nMonth == 1) //feburary, leap years has 29
                res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0;
	        return res;
		}

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

		var current = this.selectedDate;
		var d = current.valueOf();
		if(kc == Event.KEY_LEFT)
		{
			if(ev.ctrlKey || ev.shiftKey) // -1 month
			{
                current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth() - 1,current.getFullYear())) ); // no need to catch dec -> jan for the year
                d = current.setMonth( current.getMonth() - 1 );
			}
			else
				d -= 86400000; //-1 day
		}
		else if (kc == Event.KEY_RIGHT)
		{
			if(ev.ctrlKey || ev.shiftKey) // +1 month
			{
				current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth() + 1,current.getFullYear())) ); // no need to catch dec -> jan for the year
				d = current.setMonth( current.getMonth() + 1 );
			}
			else
				d += 86400000; //+1 day
		}
		else if (kc == Event.KEY_UP)
		{
			if(ev.ctrlKey || ev.shiftKey) //-1 year
			{
				current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth(),current.getFullYear() - 1)) ); // no need to catch dec -> jan for the year
				d = current.setFullYear( current.getFullYear() - 1 );
			}
			else
				d -= 604800000; // -7 days
		}
		else if (kc == Event.KEY_DOWN) 
		{
			if(ev.ctrlKey || ev.shiftKey) // +1 year
			{
				current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth(),current.getFullYear() + 1)) ); // no need to catch dec -> jan for the year
				d = current.setFullYear( current.getFullYear() + 1 );
			}
			else 
				d += 7 * 24 * 61 * 60 * 1000; // +7 days
		}
		this.setSelectedDate(d);
		Event.stop(ev);	
	},
	
	selectDate : function(ev)
	{
		var el = Event.element(ev);
		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 = this.newDate(this.selectedDate);
		var n = Number(el.firstChild.data);
		if (isNaN(n) || n <= 0 || n == null)
			return;
					
		d.setDate(n);
		this.setSelectedDate(d);
		this.hide();
	},
	
	selectToday : function()
	{
		if(this.selectedDate.toISODate() == this.newDate().toISODate())
			this.hide();

		this.setSelectedDate(this.newDate());
	},
	
	clearSelection : function()
	{
		this.setSelectedDate(this.newDate());
		this.hide();
	},
	
	monthSelect : function(ev)
	{
		this.setMonth(Form.Element.getValue(Event.element(ev)));
	},
	
	yearSelect : function(ev)
	{
		this.setYear(Form.Element.getValue(Event.element(ev)));
	},
	
	// ie6 extension
	mouseWheelChange : function (e) 
	{
		if (e == null) e = document.parentWindow.event;
		var n = - e.wheelDelta / 120;
		var d = this.newDate(this.selectedDate);
		var m = d.getMonth() + n;
		this.setMonth(m);
			
		return false;
	},

	onchange : function() 
	{
		this.control.value = this.formatDate();
	},
	
	formatDate : function()
	{
		return this.selectedDate ? this.selectedDate.SimpleFormat(this.Format) : '';
	},

	newDate : function(date)
	{
		if(!date)
			date = new Date();
		if(isString(date)  || isNumber(date))
			date = new Date(date);
		return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0,0,0);
	},

	setSelectedDate : function(date) 
	{
		if (date == null)
			return;
		this.selectedDate = this.newDate(date);
	
		this.updateHeader();
		this.update();
		if (isFunction(this.onchange))
			this.onchange();
	},

	getElement : function() 
	{
		return this._calDiv;
	},

	getSelectedDate : function () 
	{
		return isNull(this.selectedDate) ? null : this.newDate(this.selectedDate);
	},
	
	setYear : function(year) 
	{
		var d = this.newDate(this.selectedDate);
		d.setFullYear(year);
		this.setSelectedDate(d);
	},

	setMonth : function (month) 
	{
		var d = this.newDate(this.selectedDate);
		d.setMonth(month);
		this.setSelectedDate(d);
	},

	nextMonth : function () 
	{
		this.setMonth(this.selectedDate.getMonth()+1);
	},

	prevMonth : function () 
	{
		this.setMonth(this.selectedDate.getMonth()-1);
	},
	
	show : function() 
	{
		if(!this.showing)
		{
			var pos = Position.cumulativeOffset(this.control);
			pos[1] += this.control.offsetHeight;
			this._calDiv.style.display = "block";
			this._calDiv.style.top = (pos[1]-1) + "px";
			this._calDiv.style.left = pos[0] + "px";
			
			this.ieHack(false);
			this.documentClickEvent = this.hideOnClick.bindEvent(this);
			this.documentKeyDownEvent = this.keyPressed.bindEvent(this);
			Event.observe(document.body, "click", this.documentClickEvent);
			var date = Date.SimpleParse(Form.Element.getValue(this.control), this.Format);
			if(!isNull(date))
			{
				this.selectedDate = date;
				this.setSelectedDate(date);
			}
			Event.observe(document,"keydown", this.documentKeyDownEvent); 
			this.showing = true;
		}
	},
	
	//hide the calendar when clicked outside any calendar
	hideOnClick : function(ev)
	{
		if(!this.showing) return;
		var el = Event.element(ev);
		var within = false;
		do
		{
			within = within || el.className == this.ClassName;
			within = within || el == this.trigger;
			within = within || el == this.control;
			if(within) break;
			el = el.parentNode;			
		}
		while(el);
		if(!within) this.hide();
	},
	
	hide : function()
	{
		if(this.showing)
		{
			this._calDiv.style.display = "none";
			if(this.iePopUp)
				this.iePopUp.style.display = "none";
			this.showing = false;	
			Event.stopObserving(document.body, "click", this.documentClickEvent);	
			Event.stopObserving(document,"keydown", this.documentKeyDownEvent); 
		}	
	},
	
	update : function() 
	{
		// Calculate the number of days in the month for the selected date
		var date = this.selectedDate;
		var today = (this.newDate()).toISODate();
		
		var selected = date.toISODate();
		var d1 = new Date(date.getFullYear(), date.getMonth(), 1);
		var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1);
		var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000));
		
		// Find out the weekDay index for the first of this month
		var firstIndex = (d1.getDay() - this.FirstDayOfWeek) % 7 ;
	    if (firstIndex < 0)
	    	firstIndex += 7;
		
		var index = 0;
		while (index < firstIndex) {
			this.dateSlot[index].value = -1;
			this.dateSlot[index].data.data = String.fromCharCode(160);
			this.dateSlot[index].data.parentNode.className = "empty";
			index++;
		}
	        
	    for (i = 1; i <= monthLength; i++, index++) {
			var slot = this.dateSlot[index];
			var slotNode = slot.data.parentNode;
			slot.value = i;
			slot.data.data = i;
			slotNode.className = "date";
			//slotNode.style.color = "";
			if (d1.toISODate() == today) {
				slotNode.className += " today";
			}
			if (d1.toISODate() == selected) {
			//	slotNode.style.color = "blue";
				slotNode.className += " selected";
			}
			d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1);
		}
		
		var lastDateIndex = index;
	        
	    while(index < 42) {
			this.dateSlot[index].value = -1;
			this.dateSlot[index].data.data = String.fromCharCode(160);
			this.dateSlot[index].data.parentNode.className = "empty";
			++index;
		}
		
	},
	
	hover : function(ev)
	{
		//conditionally add the hover class to the event target element.
		Element.condClassName(Event.element(ev), "hover", ev.type=="mouseover");	
	},
	
	updateHeader : function () {

		var options = this._monthSelect.options;
		var m = this.selectedDate.getMonth();
		for(var i=0; i < options.length; ++i) {
			options[i].selected = false;
			if (options[i].value == m) {
				options[i].selected = true;
			}
		}
		
		options = this._yearSelect.options;
		var year = this.selectedDate.getFullYear();
		for(var i=0; i < options.length; ++i) {
			options[i].selected = false;
			if (options[i].value == year) {
				options[i].selected = true;
			}
		}
	
	}
	
	
};