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

Copyright 2009 Palm, Inc.  All rights reserved.

*/

/**
 * 
 * The Time widget is used to select a time value.
 * This widget is declared in the scene HTML like this:
 * 
 * 		<div id="timeDiv" x-mojo-element="Time" ></div>
 * 
 * In your assistant you set the model using:
 * 
 * 		this.controller.setupWidget('timeDiv', attributes, model);
 * 
 * The widget takes a set of attributes including the property name and set of
 * choices and a model declaring which option is currently active.
 * 
 * 		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 time widget.  If not specified no label is displayed.
 * 			minuteInterval: specifies the number of minutes between choices displayed in the minutes popup selector.  
 * 							Must be 1, 5, 10, 15, or 30.  For example minuteInterval of 5 would display 
 * 							minute choices of 00, 05, 10, 15 ... 55. Default value is 1.
 * 		}
 * 
 * 		model = {
 * 			value : timeValue   // Current value of widget. The time 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
 * 
 * 		$('timeDiv').observe(Mojo.Event.proeprtyChange, this.callback);
 * 
 */
Mojo.Widget.Time = Class.create({
  	initialize: function() {
		this.mode = Mojo.Widget.Time.PICK_NONE;
  	},
  
  	setup: function() {
		// Which model property to use for our value?
		this.valueName = this.controller.attributes.property || 'value';
		
		// Make sure we have a valid minute interval
		this.minInterval = this.controller.attributes.minuteInterval || 1;
		if ([1,5,10,15,30].indexOf(this.minInterval) == -1)
			this.minInterval = 1;
		
		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.theTime = new Date(this.controller.model.value);
		var hr = this.getHours12(this.theTime);
		var min = this.getMinutesString(this.theTime);
		var ap = this.getAmPmString(this.theTime);
		
		var target = this.controller.element;
		var content = Mojo.View.render({object: {label: this.controller.attributes.label, 
												 hour: hr, 
												 minute: min, 
												 ampm: ap,
												},
										template: this.getTemplatePath("datetime/timePicker")});
		target.insert(content);
		var picker = target.childElements()[0];	
		picker.palmPicker = this;				// TODO wich property name to use?

	    this.timePickerClickHandler = this.handleTimePicker.bindAsEventListener(this);
		picker.observe('click', this.timePickerClickHandler);
	    this.docClickHandler = this.handleDocClick.bindAsEventListener(this);
		
		this.hourTarget = target.select('div#tp_hour_items')[0];
		this.hourIntPopup = new IntegerPopup(this.controller, this.hourTarget, 'tp-hour', 'tp-hour-open',
										this.hourNavNext.bind(this), 
										this.hourCallback.bind(this), 
										this.hourModeCallback.bind(this), 
										null,
										{currentItem: this.theTime.getHours() % 12,
										 items:['12','1','2','3','4','5','6','7','8','9','10','11'],
										});
											
		this.minTarget = target.select('div#tp_min_items')[0];
		this.minIntPopup = new IntegerPopup(this.controller, this.minTarget, 'tp-minute', 'tp-minute-open', 
										this.minNavNext.bind(this), 
										this.minCallback.bind(this), 
										this.minModeCallback.bind(this), 
										null,
										{currentItem: Math.floor(this.theTime.getMinutes() / this.minInterval),
										 items: this.createMinList(),
										});
												
		this.ampmValue = Math.floor(this.theTime.getHours() / 12);
		this.ampmValueDiv = target.select('div#tp_ampm_items')[0];		
		this.ampmDiv = target.select('div#tp_ampm')[0];		
										
	    this.row = this.hourTarget.parentNode.parentNode;
  	},
  
  	createMinList: function () {
		var minList = [];
		var minIndex = 0;
		while (minIndex < 60) {
			minList.push((minIndex < 10) ? ('0' + minIndex) : ('' + minIndex));
			minIndex += this.minInterval;
		}
		return minList;
	},

	setTime: function(timeStamp) {
		var newTime = new Date(timeStamp);
		
		this.theTime.setHours(newTime.getHours());
		this.hourTarget.update(this.getHours12(this.theTime));
		this.hourIntPopup.setIndex(newTime.getHours()%12);
		
		this.theTime.setMinutes(newTime.getMinutes());
		this.minTarget.update(this.getMinutesString(this.theTime));
		this.minIntPopup.setIndex(Math.floor(this.theTime.getMinutes() / this.minInterval));
		
		this.ampmValue = Math.floor(this.theTime.getHours() / 12);
		this.ampmValueDiv.update(this.getAmPmString(this.theTime));
	},
	
	handleTimePicker: function(e){
		var id = e.target.identify();
		if ((id == 'tp_hour') || (id == 'tp_hour_items')) {
			this.setPickMode(Mojo.Widget.Time.PICK_HOUR);
		}
		else if ((id == 'tp_min') || (id == 'tp_min_items')) {
			if (this.mode == Mojo.Widget.Time.PICK_MIN) {
				if (this.minInterval == 30) {
					this.toggle30MinValue();
				}
			} else {
				this.setPickMode(Mojo.Widget.Time.PICK_MIN);
			}
		}
		else if ((id == 'tp_ampm') || (id == 'tp_ampm_items')) {
			if (this.mode == Mojo.Widget.Time.PICK_AMPM)
				this.toggleAmPmValue();
			else
				this.setPickMode(Mojo.Widget.Time.PICK_AMPM);
		} else {
			if (!this.row.hasClassName('focus'))
				this.setPickMode(Mojo.Widget.Time.PICK_HOUR);
		}
		Event.stop(e);
	},
	
	handleDocClick: function(e){
		if (!this.hourIntPopup.snapping &&
			!this.hourIntPopup.flicking &&
			!this.minIntPopup.snapping &&
			!this.minIntPopup.flicking) 
		{
			this.setPickMode(Mojo.Widget.Time.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.Time.PICK_NONE);
			}
		  	this.row.addClassName('focus');
			Element.observe(this.controller.element.ownerDocument, 'click', this.docClickHandler);
		}
	},

	setInactive: function() {
		if (this.row.hasClassName('focus')) {
		  	this.row.removeClassName('focus');
			Element.stopObserving(this.controller.element.ownerDocument, 'click', this.docClickHandler);
		}
	},

	setPickMode: function(mode) {
		switch (mode) {
			case Mojo.Widget.Time.PICK_NONE:
				this.hourIntPopup.setNoneMode();
				if (this.minInterval == 30) {
					this.setMinDisplayMode();
				} else {
					this.minIntPopup.setNoneMode();
				}
				this.setAmPmDisplayMode();
				this.setInactive();
				break;
			case Mojo.Widget.Time.PICK_HOUR:
				this.setActive();
				if (this.minInterval == 30) {
					this.setMinDisplayMode();
				} else {
					this.minIntPopup.setDisplayMode();
				}
				this.hourIntPopup.setPickMode();
				this.setAmPmDisplayMode();
				break;
			case Mojo.Widget.Time.PICK_MIN:
				this.setActive();
				this.hourIntPopup.setDisplayMode();
				if (this.minInterval == 30) {
					this.setMinEditMode();
				} else {
					this.minIntPopup.setPickMode();
				}
				this.setAmPmDisplayMode();
				break;
			case Mojo.Widget.Time.PICK_AMPM:
				this.setActive();
				this.hourIntPopup.setNoneMode();
				if (this.minInterval == 30) {
					this.setMinDisplayMode();
				} else {
					this.minIntPopup.setNoneMode();
				}
				this.setAmPmEditMode();
				break;
		}
		this.mode = mode;
	},
	
	setAmPmDisplayMode: function() {
	  	this.ampmDiv.removeClassName('focus');
	},
	
	setAmPmEditMode: function() {
	  	this.ampmDiv.addClassName('focus');
	},
	
	setMinDisplayMode: function() {
	  	this.minTarget.parentNode.removeClassName('focus');
	},
	
	setMinEditMode: function() {
	  	this.minTarget.parentNode.addClassName('focus');
	},
	
	toggle30MinValue: function() {
		if (this.min30Value == 0) {
			this.min30Value = 30;
			this.minTarget.update('30');
		} else {
			this.min30Value = 0;
			this.minTarget.update('00');
		}
			
		this.notifyChange(this.theTime.getHours()%12, this.min30Value, this.ampmValue);
	},
	
	toggleAmPmValue: function() {
		this.ampmValue = 1 - this.ampmValue;
		this.updpateAmPmValue();
			
		this.notifyChange(this.theTime.getHours(), this.theTime.getMinutes(), this.ampmValue);
	},
	
	updpateAmPmValue: function() {
		if (this.ampmValue)
			this.ampmValueDiv.update('PM');
		else
			this.ampmValueDiv.update('AM');
	},
	
	hourNavNext: function() {
		this.setPickMode(Mojo.Widget.Time.PICK_MIN);
	},
	
	minNavNext: function() {
		this.setPickMode(Mojo.Widget.Time.PICK_AMPM);
	},
	
	hourCallback: function(hour) {
		this.notifyChange(hour%12, this.theTime.getMinutes(), this.ampmValue);
	},	
	
	minCallback: function(min) {
		this.notifyChange(this.theTime.getHours()%12, min * this.minInterval, this.ampmValue);
	},	
	
	hourModeCallback: function(mode) {
		if (mode == IntegerPopup.MODE_PICK) {
			this.minIntPopup.setDisplayMode();
			this.mode = Mojo.Widget.Time.PICK_HOUR;
		}
	},
	
	minModeCallback: function(mode) {
		if (mode == IntegerPopup.MODE_PICK) {
			this.hourIntPopup.setDisplayMode();
			this.mode = Mojo.Widget.Time.PICK_MIN;
		}
	},
	
	notifyChange: function(hour, min, ampm) {
		if (ampm > 0) {
			if (hour < 12)
				hour += 12;
		} else {
			if (hour >= 12)
				hour -= 12;
		}
		this.theTime.setHours(hour);
		this.theTime.setMinutes(min);
		
		var modelTime = this.controller.model[this.valueName];
		if ((this.theTime.getHours() == modelTime.getHours()) &&
			(this.theTime.getMinutes() == modelTime.getMinutes()))
		{
			return;
		}
		
		// save value:
		modelTime.setHours(this.theTime.getHours());
		modelTime.setMinutes(this.theTime.getMinutes());
		
		// send change event
		Mojo.Event.send(this.controller.element, Mojo.Event.propertyChange,
			{ property: this.valueName,
				value: modelTime,
				model: this.controller.model
			});
			
	},
	
	getHours12: function(time) {
		var hrs = time.getHours() % 12;
		if (hrs == 0)
			return 12;
			
		return hrs;
	},
	
	getMinutesString: function(time) {
		var mins = time.getMinutes();
		return (mins < 10) ? ('0' + mins) : ('' + mins);
	},
	
	getAmPmString: function(time) {
		if (time.getHours() < 12)
			return 'AM';
		else 
			return 'PM';
	},
  
  	handleModelChanged: function(what, model) {
  		this.setTime(this.controller.model[this.valueName]);
  	},
  
});

Mojo.Widget.Time.PICK_NONE = 0;
Mojo.Widget.Time.PICK_HOUR = 1;
Mojo.Widget.Time.PICK_MIN = 2;
Mojo.Widget.Time.PICK_AMPM = 3;

