/**
 * @name mojo_widget_date.js
 * @fileOverview This file has functions related to the Date widget 
 * which is used to select a date;
 * See {@link Mojo.Widget.Date} for more info.

Copyright 2009 Palm, Inc.  All rights reserved.

*/

/**
 * 
 * The Date widget is used to select a date value.
 * This widget is declared in the scene HTML like this:
 * 
 * 		<div id="dateDiv" x-mojo-element="Date" ></div>
 * 
 * In your assistant you set the model using:
 * 
 * 		this.controller.setupWidget('dateDiv', attributes, model);
 * 
 * The widget takes a set of attributes including the property name and set of
 * choices and a model declaring the intial date.
 * 
 * 		attributes = {
 * 			property:   propertyName,
 * 						// Determines which model property is used for the widget's 
 * 						// value. Defaults to 'value' if not specified.
 * 			label: 	  	optional label to displayed with the date widget.  If not specified no label is displayed.
 * 			minYear: 	optional minimum year value allowed.  Default is 1900.
 * 			maxYear:	optional maximum year value allowed.  Default is 2100.
 * 		}
 * 
 * 		model = {
 * 			value : dateValue   // Current date value of widget. The date value is a javascript Date object.
 * 			                       May alternatively be the property named by
 * 			                       the 'property' field in the attributes hash.
 * 			}
 * 
 * ## Handling Click & Change events: ##
 * This widget only supports a change event.  
 * To listen to a change event call
 * 
 * 		$('dateDiv').observe(Mojo.Event.proeprtyChange, this.callback);
 * 
 */
Mojo.Widget.Date = Class.create({
  	initialize: function() {
		this.mode = Mojo.Widget.Date.PICK_NONE;
  	},
  
  	setup: function() {
		// Which model property to use for our value?
		this.valueName = this.controller.attributes.property || 'value';
		
		// Year limits
		this.minYear = this.controller.attributes.minYear || 1900;
		this.maxYear = this.controller.attributes.maxYear || 2100;
		
		this.renderWidget();
  	},
	
	getTemplatePath: function(templateDir) {
		// TODO When added to the frame uncomment 
		//return Mojo.Widget.getSystemTemplatePath(templateDir);
		return "../../../com.palm.app.calendar/app/views/" + templateDir;
	},
  
  	renderWidget: function() {
		this.theDate = new Date(this.controller.model.value);
		var day = this.theDate.getDate();
		var month = this.theDate.getMonth();
		var year = this.theDate.getFullYear();		
		
		var target = this.controller.element;
		var content = Mojo.View.render({object: {label: this.controller.attributes.label, 
												 year: year, 
												 month: this.getMonthName(month), 
												 day: day + ','
												 },
										template: this.getTemplatePath("datetime/datePicker"),
									   });
		target.insert(content);
		var picker = target.childElements()[0];	
		picker.palmPicker = this;				// TODO wich property name to use?

	    this.datePickerClickHandler = this.handleDatePicker.bindAsEventListener(this);
		picker.observe('click', this.datePickerClickHandler);
	    this.docClickHandler = this.handleDocClick.bindAsEventListener(this);
		
		this.monthTarget = target.select('div#dp_month_items')[0];
		this.monthIntPopup = new IntegerPopup(this.controller, this.monthTarget, 'dp-month', 'dp-month-open',
										this.monthNavNext.bind(this), 
										this.monthCallback.bind(this), 
										this.monthModeCallback.bind(this), 
										null,
										{currentItem: month,
										 items: Mojo.Widget.Date.MonthsAbbr,
										});
											
		this.dayTarget = target.select('div#dp_day_items')[0];
		this.dayIntPopup = new IntegerPopup(this.controller, this.dayTarget, 'dp-day', 'dp-day-open', 
										this.dayNavNext.bind(this), 
										this.dayCallback.bind(this), 
										this.dayModeCallback.bind(this),
										null, 
										{integerItem: day,
										 min: 1,
										 max: this.getNumDaysInMonth(month, year),
										});
												
		this.yearTarget = target.select('div#dp_year_items')[0];
		this.yearIntPopup = new IntegerPopup(this.controller, this.yearTarget, 'dp-year', 'dp-year-open', 
										this.yearNavNext.bind(this), 
										this.yearCallback.bind(this), 
										this.yearModeCallback.bind(this), 
										this.yearParseCallback.bind(this),
										{integerItem: year,
										 min: this.minYear,
										 max: this.maxYear,
										});
										 
	    this.row = this.monthTarget.parentNode.parentNode;
  	},

	setDate: function(timeStamp) {
		var newDate = new Date(timeStamp);
		
		this.theDate.setFullYear(newDate.getFullYear());
		this.yearTarget.update(newDate.getFullYear());
		this.yearIntPopup.setInteger(this.theDate.getFullYear());
		
		this.theDate.setMonth(newDate.getMonth());
		this.monthTarget.update(this.getMonthName(this.theDate.getMonth()));
		this.monthIntPopup.setIndex(this.theDate.getMonth());
		
		this.theDate.setDate(newDate.getDate());
		this.dayTarget.update(newDate.getDate() + ',');
		this.dayIntPopup.setInteger(this.theDate.getDate());
	},
	
	handleDatePicker: function(e){
		var id = e.target.identify();
		if ((id == 'dp_day') || (id == 'dp_day_items')) {
			this.setPickMode(Mojo.Widget.Date.PICK_DAY);
		}
		else if ((id == 'dp_year') || (id == 'dp_year_items')) {
			this.setPickMode(Mojo.Widget.Date.PICK_YEAR);
		} else if ((id == 'dp_month') || (id == 'dp_month_items')) {
			this.setPickMode(Mojo.Widget.Date.PICK_MONTH);
		} else {
			if (!this.row.hasClassName('focus'))
				this.setPickMode(Mojo.Widget.Date.PICK_MONTH);
		}
		Event.stop(e);
	},
	
	handleDocClick: function(e){
		if (!this.monthIntPopup.snapping &&
			!this.monthIntPopup.flicking &&
			!this.dayIntPopup.snapping &&
			!this.dayIntPopup.flicking &&
			!this.yearIntPopup.snapping &&
			!this.yearIntPopup.flicking) 
		{
			this.setPickMode(Mojo.Widget.Date.PICK_NONE);
		}	
	},
	
	setActive: function() {
		if (!this.row.hasClassName('focus')) {
			var allPickers = Selector.findChildElements(this.controller.element.ownerDocument, ['div.palm-picker']);
			for (var i = 0; i < allPickers.length; i++) {
				allPickers[i].palmPicker.setPickMode(Mojo.Widget.Date.PICK_NONE);
			}
			this.monthTarget.update(this.getMonthNameAbbr(this.theDate.getMonth()));
			this.dayTarget.update(this.theDate.getDate());
		  	this.row.addClassName('focus');
			Element.observe(this.controller.element.ownerDocument, 'click', this.docClickHandler);
		}
	},

	setInactive: function() {
		if (this.row.hasClassName('focus')) {
			this.monthTarget.update(this.getMonthName(this.theDate.getMonth()));
			this.dayTarget.update(this.theDate.getDate() + ',');
		  	this.row.removeClassName('focus');
			Element.stopObserving(this.controller.element.ownerDocument, 'click', this.docClickHandler);
		}
	},

	setPickMode: function(mode) {
		switch (mode) {
			case Mojo.Widget.Date.PICK_NONE:
				this.monthIntPopup.setNoneMode();
				this.dayIntPopup.setNoneMode();
				this.yearIntPopup.setNoneMode();
				this.setInactive();
				break;
			case Mojo.Widget.Date.PICK_MONTH:
				this.setActive();
				this.dayIntPopup.setDisplayMode();
				this.yearIntPopup.setDisplayMode();
				this.monthIntPopup.setPickMode();
				break;
			case Mojo.Widget.Date.PICK_DAY:
				this.setActive();
				this.monthIntPopup.setDisplayMode();
				this.yearIntPopup.setDisplayMode();
				this.dayIntPopup.setPickMode();
				break;
			case Mojo.Widget.Date.PICK_YEAR:
				this.setActive();
				this.monthIntPopup.setDisplayMode();
				this.dayIntPopup.setDisplayMode();
				this.yearIntPopup.setPickMode();
				break;
		}
		this.mode = mode;
	},
	
	monthNavNext: function() {
		this.setPickMode(Mojo.Widget.Date.PICK_DAY);
	},
	
	dayNavNext: function() {
		this.setPickMode(Mojo.Widget.Date.PICK_YEAR);
	},
	
	yearNavNext: function() {
		this.setPickMode(Mojo.Widget.Date.PICK_NONE);
	},
	
	updateMaxDay: function(month, year) {
		var maxDays = this.getNumDaysInMonth(month, year);
		this.dayIntPopup.setMinMax(1, maxDays);
		var day = this.theDate.getDate();
		if (day > maxDays) {
			day = maxDays;
			this.dayTarget.update(day);
		}
		return day;
	},
	
	yearCallback: function(year) {
		this.notifyChange(year, this.theDate.getMonth(), this.updateMaxDay(this.theDate.getMonth(), year));
	},	
	
	monthCallback: function(month) {
		this.notifyChange(this.theDate.getFullYear(), month, this.updateMaxDay(month, this.theDate.getFullYear()));
	},	
	
	dayCallback: function(day) {
		this.notifyChange(this.theDate.getFullYear(), this.theDate.getMonth(), day);
	},	
	
	monthModeCallback: function(mode) {
		if (mode == IntegerPopup.MODE_PICK) {
			this.dayIntPopup.setDisplayMode();
			this.yearIntPopup.setDisplayMode();
			this.mode = Mojo.Widget.Date.PICK_MONTH;
		}
	},
	
	dayModeCallback: function(mode) {
		if (mode == IntegerPopup.MODE_PICK) {
			this.monthIntPopup.setDisplayMode();
			this.yearIntPopup.setDisplayMode();
			this.mode = Mojo.Widget.Date.PICK_DAY;
		}
	},
	
	yearModeCallback: function(mode) {
		if (mode == IntegerPopup.MODE_PICK) {
			this.dayIntPopup.setDisplayMode();
			this.monthIntPopup.setDisplayMode();
			this.mode = Mojo.Widget.Date.PICK_YEAR;
		}
	},
	
	yearParseCallback: function(year) {
		if (year < 50) {
			return 2000 + year;
		} else if (year < 100) {
			return 1900 + year;
		}
		return year;
	},
	
	notifyChange: function(year, month, day) {
		this.theDate.setDate(day);
		this.theDate.setMonth(month);
		this.theDate.setYear(year);
		
		var modelDate = this.controller.model[this.valueName];
		if ((this.theDate.getYear() == modelDate.getYear()) &&
			(this.theDate.getMonth() == modelDate.getMonth()) &&
			(this.theDate.getDate() == modelDate.getDate()))
		{
			return;
		}
		
		// save value:
		modelDate.setDate(day);
		modelDate.setMonth(month);
		modelDate.setYear(year);
		
		// send change event
		Mojo.Event.send(this.controller.element, Mojo.Event.propertyChange,
			{ property: this.valueName,
				value: modelDate,
				model: this.controller.model
			});
	},
	
	// Returns the name of the month given month integer (zero based)
	getMonthName: function(month) {
		return Mojo.Widget.Date.Months[month];
	},
	
	// Returns the abbreviated name of the month given month integer (zero based)
	getMonthNameAbbr: function(month) {
		return Mojo.Widget.Date.MonthsAbbr[month];
	},
	
	isLeapYear: function(year) {
		if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
			return true;
			
		return false;
	},
	
	getNumDaysInMonth: function(month, year) {
		var numDays = Mojo.Widget.Date.MonthDays[month];
		if ((month == 1) && this.isLeapYear(year)) {
			numDays++;
		}
		return numDays;
	},
  
  	handleModelChanged: function(what, model) {
  		this.setDate(this.controller.model[this.valueName]);
  	},
  
});

Mojo.Widget.Date.PICK_NONE = 0;
Mojo.Widget.Date.PICK_MONTH = 1;
Mojo.Widget.Date.PICK_DAY = 2;
Mojo.Widget.Date.PICK_YEAR = 3;

Mojo.Widget.Date.MonthsAbbr = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'];
Mojo.Widget.Date.Months = ['JANUARY','FEBRUARY','MARCH','APRIL','MAY','JUNE','JULY','AUGUST','SEPTEMBER','OCTOBER','NOVEMBER','DECEMBER'];
Mojo.Widget.Date.MonthDays = [31,28,31,30,31,30,31,31,30,31,30,31];
