/**
 * Add appointment date selection from calendar handling for input elements.
 *
 * The `.productUiAppointmentpicker()` method add validate handling to a input elements.
 *
 * The `.productUiAppointmentpicker()` method is a validation input also and using the validation type ''date'' from
 * the ep.validate module. Have a look at the additional options, some options are only available for
 * a special validation types.
 *
 * ### Examples
 * Apply .productUiAppointmentpicker() to input element named date.
 *
 * JavaScript:
 *
 *     de_epages(':input[name=date]')
 *         .productUiAppointmentpicker({
 *             showOn: 'focus',
 *             appointment: {
 *                 id:                 8930,
 *                 quantityMin:        1,
 *                 quantityRequested:  1,
 *                 quantityAvailable:  5,
 *                 minutesRequested:   60
 *             }
 *         });
 *
 * HTML:
 *
 *     <form>
 *       <input type="text" name="date" />
 *     </form>
 *
 *
 * @class jQuery.ui.productUiAppointmentpicker
 * @extends jQuery.ui.uiDatepicker
 *
 * @uses de_epages
 * @uses ep.ui.datepicker
 * @uses ep.alert
 * @uses ep.ajax
 * @since 6.11.0
 */

/**
 * @cfg {Object} appointment A map of options like the ObjectID for the current appointment.
 */

/**
 * See `jQuery.ui.productUiAppointmentpicker` for details.
 *
 * @param {Object} [options] A map of additional options pass to the method.
 * @param {Object} appointment A map of options like the ObjectID for the current appointment.
 *
 * @method productUiAppointmentpicker
 * @member jQuery
 *
 * @since 6.11.0
 */

/*
 * @copyright		© Copyright 2006-2010, epages GmbH, All Rights Reserved.
 *
 * @module			de_epages/product/ui/appointmentpicker
 */

define("de_epages/product/ui/appointmentpicker", [
	"jquery",
	"ep",
	"de_epages",
	"$dict!../dictionary",

	"ep/alert",
	"ep/ajax",
	"ep/ui/datepicker"
], function ($, ep, de_epages, dict) {

/*
 * @dictionary		de_epages.product.dictionary
 *
 * @translation		{Loading}
 *					{BookedUp}
					{CALENDAR_DATA_NOT_LOAD}
 */

 	var tLoading		= dict.translate('Loading')+'...',
 		tBookedOut		= dict.translate('BookedUp'),
 		tDataNotLoad	= dict.translate('CALENDAR_DATA_NOT_LOAD');

	$.widget('ui.productUiAppointmentpicker',$.ui.uiDatepicker,{

		options: {
	// ep.ui.Input
		//	big:				true,
		//	autofocus:			false,
		//	placeholder:		'text',

	// ep.ui.Validate
		//	accept:				'',
		//	min:				1,
		//	max:				20,
		//	minlength:			1,
		//	maxlength:			4,
		//	pattern:			[\w]+,
		//	required:			true,
		//	tooltipOffset:		[0,-7],
		//	valid:				true,
		//	type:				'basic',
		//	format:				'',

	// ep.ui.Datepicker
		//	type:				'date',
		//	format:				'l',
		//	showOn:				'both',
		//	duration:			'normal',
		//	show:				'fadeIn',
		//	hide:				'fadeOut',
		//	weekDaysAvailable:	[0,0,1,1,1,1,1],
		//	numberOfMonths:		1,
		//	showOtherMonth:		true,
		//	selectOtherMonth:	false,
		//	changeMonth:		true,
		//	changeYear:			true,
		//	positionAdjust:		[-1,2],
		//	region:				ep.config.region,
		//	time:				true,
		//	timeStep:			15,

	//	ep.ui.DatepickerApp
			time:				true,
			currentDate: undefined,
			appointment: {							// hash to perform appointment available
				id:					0,
				quantityMin:		1,
				quantityRequested:	1,
				quantityAvailable:	1,
				minutesRequested:	60
			}
		},

		_create: function(){
			this._superApply(arguments);
			this._appointmentSort = {};
			this._appointmentStack = {};

			this._loadDayList( this._date.clone().addDate(-7), true );
		},

		_createTimeSelect: function(){
			this.timeSelect = ep('<select>')
				.attr({
					'class': 'epWidth100'
				})
				.appendTo( this.timeBar )
				.uiInput()
				.uiInput('addClass','ep-uiDatepicker-time')
				.on( 'changeValue.uiAppointmentpicker', $.proxy(this, '_changeTimeVal') );

			this.stack.push( this.timeSelect[0]	);
		},

		_createCalendars: function(){
			this._superApply(arguments);
			this._createTimeSelectData();
		},

		_calendarData: function(){
			var self			= this,
				o				= this.options,
				opt				= o.appointment,
				calendarsData	= this._superApply(arguments),
				appData			= $.scope( opt.minutesRequested+'', this._appointmentStack ),
				load			= false;

			$.each( calendarsData, function( i, calendarData ){
				$.each( calendarData.days, function( j, day ){
					if( this.clickable ){
						var date = day.date,
							dateString = date.getFormat('S'),
							dayObj = appData[ dateString ];

						if( !dayObj && !load ){
							appData	= self._loadDayList( date.clone() );
							dayObj = appData[ dateString ];
							load = true;
						}

						this.clickable = !!(dayObj && dayObj.IsAvailable);
					}
				});
			});

			return calendarsData;
		},

		_createTimeSelectData: function(){
			var self			= this,
				opt				= this.options.appointment,
				dateString		= this._dateSelected.getFormat('S'),
				appStack		= $.scope(  opt.minutesRequested+'', this._appointmentStack ),
				dayObj			= appStack[ dateString ],
				placeholder		= $('<option/>')
					.prop('disabled', true)
					.text(tLoading);


			self.timeSelect
				.empty()
				.append(placeholder);

			if( dayObj ){
				// load TimeList for selected day if not cached
				if( !dayObj.DayList ){
					self._loadTimeList(self._dateSelected);
					return;
				}

				var region		= {region: self.options.region};

				// add TimeList to select field
				if( dayObj.DayList && dayObj.DayList.length ){
					self.timeSelect.empty();
					$.each( dayObj.DayList, function( i, data ){
						if( (opt.quantityAvailable-data[1]) >= opt.quantityRequested ){
							var date = new ep.Date(data[0]);
							$('<option>')
								.val(date.setFullYear(0,0,0).getTime())
								.text( date.getFormat( 't', region ) )
								.appendTo( self.timeSelect );
						}
					});
				}
				// show times are booked out
				else{
					placeholder.text(tBookedOut);
				}

			}
			else{
				placeholder.text(tBookedOut);
				self.elem.trigger('focus');
			}

			self._setTimeVal();
		},

		_setTimeVal: function(){
			var self			= this,
				selectedTime	= this._timeSelected.getTime()+'',
				selectedNode,
				selectedIndex;

			$.each( this.timeSelect[0].options, function( i, node ){
				if( node.value === selectedTime ){
					node.selected = true;
					selectedNode = node;
					selectedIndex = i;
					return false;
				}
			});

			if( !selectedNode ){
				selectedNode = $(this.timeSelect[0].options).not(':disabled').get(0);
				if( selectedNode ){
					selectedNode.selected = true;
					selectedTime = selectedNode.value;
					selectedIndex = 0;
				}
			}

			if( selectedTime ){
				this._timeSelected = new ep.Date(selectedTime);
			}

			if( !this.elem.is(':focus') ){
				this._setElemVal(true);
			}
		},

		_getTimeVal: function(){
			var opt = this.timeSelect[0].selectedIndex >= 0 ?
						this.timeSelect[0].options[ this.timeSelect[0].selectedIndex ] :
						null,
				date = opt ? new ep.Date(opt.value) : new ep.Date();
			return date.setFullYear(0,0,0);
		},
		// attention the date object will be modified, be sure to use an cloned date object
		_loadDayList: function( date, preload ){
			var self		= this,
				o			= this.options,
				opt			= o.appointment,
				dateStart	= date,
				dateEnd		= dateStart.clone().addMonth( o.numberOfMonths + 2 ),
				ret;


			ep.ajax({
				data: {
					'ViewAction':		'JSON-AppointmentCalendar',
					'ObjectID':			opt.id,
					'StartDate':		dateStart.getFormat('S'),
					'EndDate':			dateEnd.getFormat('S'),
					'RequestedMinutes':	opt.minutesRequested,
					'Available':		opt.quantityAvailable,
					'UseTimestamps':	1,
					'IsAvailableOnly':	1
				},
				async: !!preload,
				dataType: 'json'
			})
			.done(function( data ){
				ret = data;
			})
			.fail(function( xhr, status, error ){
				if( !preload ){
					self.hide();
					ep.alert({
						type:		'error',
						content:	tDataNotLoad
					});
				}
			});

			ret = $.extend( true, $.scope( opt.minutesRequested+'', this._appointmentStack ), ret );
			return ret;
		},

		// attention the date object will be modified, be sure to use an cloned date object
		_loadTimeList: function( date ){
			var self		= this,
				o			= this.options,
				opt			= o.appointment,
				dateStart	= date,
				dateEnd		= dateStart.clone().addDate(1),
				ret;

			ep.ajax({
				data: {
					'ViewAction':		'JSON-AppointmentCalendar',
					'ObjectID':			opt.id,
					'StartDate':		dateStart.getFormat('S'),
					'EndDate':			dateEnd.getFormat('S'),
					'RequestedMinutes':	opt.minutesRequested,
					'Available':		opt.quantityAvailable,
					'UseTimestamps':	1
				},
			//	async:		false,
				dataType:	'json'
			})
			.done(function( data ){
				ret = $.extend( true, $.scope( opt.minutesRequested+'', self._appointmentStack ), data );

				self._createTimeSelectData();
			})
			.fail(function( xhr, status, error ){
				self.hide();
				ep.alert({
					type:		'error',
					content:	tDataNotLoad
				});
			});
		},

		/**
		 * Updates the appointment option and refresh the availability.
		 *
		 * @param {Object} appointment A map of options like the ObjectID for the current appointment.
		 *
		 * @method updateAppointment
		 * @member jQuery.ui.productUiAppointmentpicker
		 *
		 * @since 6.11.0
		 */
		updateAppointment: function( options ){
			$.extend( this.options.appointment, options );
			// preload data
			// this._loadDayList( this._date.clone().addDate(-7), true );
		}
	});

	return de_epages;

});