Source: uifactory/dateselect.js

/**
 * @module  uifactory/dateselect
 * @author  Andrea Jonus <andrea.jonus@caffeina.com>
 */

var Moment = require('alloy/moment');
var Util = require('T/util');
var Dialog = require('T/dialog');

var Data = {};

var PICKER_WIDTH_IPHONE = Alloy.Globals.SCREEN_WIDTH;
var PICKER_HEIGHT_IPHONE = 216;

var PICKER_WIDTH_IPAD = 320;
var PICKER_HEIGHT_IPAD = 216;

function createTiUIPicker($this, opt) {
	var $picker = Ti.UI.createPicker(_.extend({}, opt, {
		value: $this.getValue(),
		minDate: $this.minDate,
		maxDate: $this.maxDate,
		type: Ti.UI.PICKER_TYPE_DATE,
	}));

	return $picker;
}

// Get the two buttons in the toolbar
function UIPickerButtons($this, $picker, callbacks) {
	var $doneBtn = Ti.UI.createButton({ title: L('done', 'Done') });
	$doneBtn.addEventListener('click', function() {
		$this.setValue($picker.value);

		callbacks.done();
	});

	var $cancelBtn = Ti.UI.createButton({ title: L('cancel', 'Cancel') });
	$cancelBtn.addEventListener('click', function() {
		callbacks.cancel();
	});

	return {
		done: $doneBtn,
		cancel: $cancelBtn
	};
}

var UIPickers = {

	// Show the picker in a Window that slide in from the bottom
	iphone: function($this) {
		var $picker = createTiUIPicker($this, {
			width: PICKER_WIDTH_IPHONE,
			height: PICKER_HEIGHT_IPHONE
		});

		var buttons = UIPickerButtons($this, $picker, {
			cancel: function() {
				$this.fireEvent('cancel');
				$pickerModal.close();
			},
			done: function() {
				$pickerModal.close();
			}
		});

		var $toolbar = Ti.UI.iOS.createToolbar({
			items: [
				buttons.cancel,
				Ti.UI.createButton({ systemButton: Ti.UI.iPhone.SystemButton.FLEXIBLE_SPACE }),
				buttons.done
			],
			borderTop: true,
			borderBottom: false
		});

		var $containerView = Ti.UI.createView({
			height: Ti.UI.SIZE,
			width: Ti.UI.FILL,
			layout: 'vertical',
			bottom: 0,
			transform: Ti.UI.create2DMatrix().translate(0, 300)
		});
		$containerView.add($toolbar);
		$containerView.add($picker);

		var $pickerModal = Ti.UI.createWindow({
			backgroundColor: '#4000',
		});
		$pickerModal.add($containerView);

		$pickerModal.addEventListener('open', function(e) {
			$picker.fireEvent('visible');
		});

		$pickerModal.open();

		$containerView.animate({
			transform: Ti.UI.create2DMatrix()
		});
	},

	// Show the picker in a Popover Window attached to the Label
	ipad: function($this) {
		var $picker = createTiUIPicker($this, {
			width: PICKER_WIDTH_IPAD
		});
		var has_value = false;

		var buttons = UIPickerButtons($this, $picker, {
			cancel: function() {
				has_value = false;
				$popover.hide();
			},
			done: function() {
				has_value = true;
				$popover.hide();
			}
		});

		var $containerWindow = Ti.UI.createWindow({
			leftNavButton: buttons.cancel,
			rightNavButton: buttons.done,
			title: $this.hintText,
			navTintColor: $this.tintColor
		});
		$containerWindow.add($picker);

		$containerWindow.addEventListener('open', function(e) {
			$picker.fireEvent('visible');
		});

		$containerWindow.addEventListener('close', function(e) {
			if (!has_value) {
				$this.fireEvent('cancel');
			}
		});

		var $navigator = Ti.UI.iOS.createNavigationWindow({
			window: $containerWindow,
			width: PICKER_WIDTH_IPAD,
			height: PICKER_HEIGHT_IPAD + 40, // 40 is the toolbar height
		});

		var $popover = Ti.UI.iPad.createPopover({
			contentView: $navigator
		});

		$popover.show({
			view: $this
		});
	},

	android: function($this) {
		Ti.UI.createPicker({
			type: Ti.UI.PICKER_TYPE_DATE
		}).showDatePickerDialog(_.extend(_.pick($this, 'value', 'minDate', 'maxDate'), {
			value: $this.getValue(),
			callback: function(e) {
				if (e.value == null || e.cancel) return;
				Data[ $this._uid ].value = e.value;
				$this.updateUI();
			}
		}));
	}

};


function dataPickerInterface(opt) {
	var self = {
		value: opt.value || new Date()
	};

	return self;
}

module.exports = function(args) {
	args = _.defaults(args || {}, {

		/**
		 * @property {String} [dateFormat='D MMMM YYYY'] The date format to display.
		 * @see {@link http://momentjs.com/docs/#/displaying/format/}
		 */
		dateFormat: 'D MMMM YYYY',

		/**
		 * @property {Date} [value=null] The date object to use as the value.
		 */
		value: null,

		/**
		 * @property {String} [hintText=''] The text to display when no value is selected.
		 */
		hintText: '',

		/**
		 * @property {String} [tintColor=null] **(iOS only)** The tint color for the toolbar buttons of the picker.
		 */
		tintColor: null,

		/**
		 * @property {Date} [minDate=null] Minimum date displayed.
		 */
		minDate: null,

		/**
		 * @property {Date} [maxDate=null] Maximum date displayed.
		 */
		maxDate: null
	});

	args._uid = _.uniqueId();

	// Create a unique interface
	Data[ args._uid ] = dataPickerInterface({
		value: args.value
	});

	delete args.value;

	// Start UI

	var $this = null;
	_.defaults(args, {
		height: 48,
		width: Ti.UI.FILL
	});

	$this = Ti.UI.createLabel(args);

	$this.addEventListener('click', function(){
		$this.open();
	});

	$this.updateUI = function(trigger) {
		var val = $this.getValue();

		if (trigger !== false) {
			$this.fireEvent('change', {
				value: val,
				source: $this
			});
		}

		$this.text = val ? Moment(val).format($this.dateFormat) : ($this.hintText);
	};

	/**
	 * Get the value
	 * @return {Object}
	 */
	$this.getValue = function() {
		return Data[ $this._uid ].value;
	};

	/**
	 * @param {Object} value
	 * Set the current value
	 * Shorthand for setColumnsValues with a single columns picker
	 */
	$this.setValue = function(value) {
		Data[ $this._uid ].value = value;

		$this.updateUI();
	};

	/**
	 * @param {Date} date
	 * Set the minimum date to display
	 */
	$this.setMinDate = function(date) {
		if ($this.maxDate != null && Moment(date).isAfter($this.maxDate)) {
			Ti.API.warn('UIFactory/DatePicker: The new minDate is after the defined maxDate. Falling back to maxDate.');

			$this.minDate = $this.maxDate;
		} else {
			$this.minDate = date;
		}
	};

	/**
	 * @param {Date} date
	 * Set the maximum date to display
	 */
	$this.setMaxDate = function(date) {
		if ($this.minDate != null && Moment(date).isBefore($this.minDate)) {
			Ti.API.warn('UIFactory/DatePicker: The new maxDate is before the defined minDate. Falling back to minDate.');

			$this.maxDate = $this.minDate;
		} else {
			$this.maxDate = date;
		}
	};

	/**
	 * Get the internal data interface
	 */
	$this.getDataInterface = function() {
		return Data[ $this._uid ];
	};

	/**
	 * Open the picker
	 */
	$this.open = function() {
		UIPickers[ Ti.Platform.osname ]($this);
	};

	// Update the UI
	$this.updateUI(false);

	return $this;
};