Ext.namespace('Zarafa.calendar.dialogs');

/**
 * @class Zarafa.calendar.dialogs.AppointmentTab
 * @extends Ext.form.FormPanel
 * @xtype zarafa.appointmenttab
 *
 * Main tab in the {@link Zarafa.calendar.dialogs.AppointmentPanel}
 * that is used to create Appointments and Meeting Requests.
 */
Zarafa.calendar.dialogs.AppointmentTab = Ext.extend(Ext.form.FormPanel, {
	/**
	 * @cfg {String} trackingInfoString string which must be displayed in the dialog
	 * if any attendee has responded to the meeting request in {@link Zarafa.core.data.IPMRecord record}
	 */
	trackingInfoString : pgettext('calendar.dialog', '{0} attendees accepted, {1} tentatively accepted, {2} declined.'),

	/**
	 * @cfg {String} proposedTimeInfoString string which must be displayed in the dialog
	 * if there is any counter proposal for change in meeting time set in {@link Zarafa.core.data.IPMRecord record}
	 */
	proposedTimeInfoString : pgettext('calendar.dialog', '{0} attendees proposed a new time for this meeting. Click the Scheduling tab for details.'),

	/**
	 * @cfg {String} proposeNewTimeInfoString string which must be displayed in the dialog
	 * if there is any counter proposal for change in meeting time set in {@link Zarafa.core.data.IPMRecord record}
	 */
	proposeNewTimeInfoString : pgettext('calendar.dialog', 'You proposed a new time for this meeting on {0}'),

	/**
	 * @cfg {String} proposeNewTimeDelegateInfoString string which must be displayed in the dialog
	 * if there is any counter proposal for change in meeting time set in {@link Zarafa.core.data.IPMRecord record}
	 * and meeting is proposed by delegate
	 */
	proposeNewTimeDelegateInfoString : pgettext('calendar.dialog', '{0} proposed a new time for this meeting on {1}'),

	/**
	 * @cfg {String} acceptedInfoString string which must be displayed in the dialog
	 * if meeting accepted time set in {@link Zarafa.core.data.IPMRecord record}
	 */
	acceptedInfoString : pgettext('calendar.dialog', 'Accepted on {0}'),

	/**
	 * @cfg {String} acceptedDelegateInfoString string which must be displayed in the dialog
	 * if meeting accepted time set in {@link Zarafa.core.data.IPMRecord record}
	 * and meeting is accepted by delegate
	 */
	acceptedDelegateInfoString : pgettext('calendar.dialog', 'Accepted by {0} on {1}'),

	/**
	 * @cfg {String} tentativeInfoString string which must be displayed in the dialog
	 * if meeting tentatively accepted time set in {@link Zarafa.core.data.IPMRecord record}
	 */
	tentativeInfoString : pgettext('calendar.dialog', 'Tentatively Accepted on {0}'),

	/**
	 * @cfg {String} tentativeDelegateInfoString string which must be displayed in the dialog
	 * if meeting tentatively accepted time set in {@link Zarafa.core.data.IPMRecord record}
	 * and meeting is accepted by delegate
	 */
	tentativeDelegateInfoString : pgettext('calendar.dialog', 'Tentatively Accepted by {0} on {1}'),

	/**
	 * @cfg {String} elapsedTimeInfoString string which must be displayed in the dialog
	 * if meeting time set in {@link Zarafa.core.data.IPMRecord record} is already elapsed.
	 */
	elapsedTimeInfoString : pgettext('calendar.dialog', 'This appointment occurs in the past.'),

	/**
	 * @cfg {String} responseRequiredString string which must be displayed in the dialog
	 * if meeting accepted time set in {@link Zarafa.core.data.IPMRecord record} is empty.
	 * which means that, meeting request is not responded yet
	 */
	responseRequiredString : pgettext('calendar.dialog', 'Please respond.'),

	/**
	 * @cfg {String} noResponseReceivedString string which must be displayed in the dialog
	 * if no recipient has responded to meeting request
	 */
	noResponseReceivedString : pgettext('calendar.dialog', 'No responses have been received for this meeting.'),

	/**
	 * @cfg {String} meetingCanceledString string which must be displayed in the dialog
	 * if meeting has been canceled.
	 */
	meetingCanceledString : pgettext('calendar.dialog', 'Meeting has been canceled.'),

	/**
	 * @cfg {String} meetingUnsentString string which must be displayed in the dialog
	 * if meeting has not yet been sent.
	 */
	meetingUnsentString : pgettext('calendar.dialog', 'Invitations have not been sent for this meeting.'),

	/**
	 * @cfg {String} meetingOverwrittenString string which must be displayed in the dialog
	 * to inform the user his changes will be overwritten when the meeting organizer updates
	 * the meeting.
	 */
	meetingOverwrittenString : pgettext('calendar.dialog', 'Please note that any changes you make will be overwritten when this meeting request is updated by the organizer'),

	/**
	 * Property which is set to true when user changes location manually, If user has
	 * changed/set location manually. {@link updateLocation} function will use this
	 * property to chech whether has changed location or not, if this property is false
	 * then it will change location generated using recipients without any confirmation.
	 * @property
	 * @type Boolean
	 * @private
	 */
	hasUserSetLocation : false,

	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config)
	{
		config = config || {};

		config.plugins = Ext.value(config.plugins, []);
		config.plugins.push('zarafa.recordcomponentupdaterplugin');

		Ext.applyIf(config, {
			xtype: 'zarafa.appointmenttab',
			cls: 'k-appointmentcreatetab',
			layout: {
				type: 'vbox',
				align: 'stretch'
			},
			border: false,
			labelPad: 0,
			items: [
				this.createExtraInfoPanel(),
				this.createMeetingOrganizerPanel(),
				this.createRecipientPanel(),
				this.createSubjectPanel(),
				this.createLocationPanel(),
				this.createDateTimePanel(),
				this.createinPanel(),
				this.createAttachmentsPanel(),
				this.createBodyPanel()
			]
		});

		Zarafa.calendar.dialogs.AppointmentTab.superclass.constructor.call(this, config);
	},

	/**
	 * Create the {@link Ext.Panel panel} containing the information about response from attendees
	 * and some extra information regarding meeting item.
	 * @return {Object} Configuration object for the panel containing the fields
	 * @private
	 */
	createExtraInfoPanel : function()
	{
		return {
			xtype: 'container',
			cls: 'zarafa-calendar-appointment-extrainfo',
			ref: 'extraInfoPanel',
			autoHeight: true,
			hidden: true
		};
	},

	/**
	 * Create the {@link Ext.Panel panel} containing the information about meeting organizer
	 * @return {Object} Configuration object for the panel containing the fields
	 * @private
	 */
	createMeetingOrganizerPanel : function()
	{
		return {
			xtype: 'panel',
			ref: 'meetingOrganizerPanel',
			layout: 'form',
			autoHeight: true,
			border: false,
			items: [{
				xtype: 'displayfield',
				ref: '../meetingOrganizerField',
				fieldLabel: _('Organizer'),
				htmlEncode : true,
				flex: 1
			}],
			hidden: true
		};
	},

	/**
	 * Create the {@link Zarafa.common.ui.RecipientField RecipientField}
	 * where the recipients for the Meeting requests can be selected
	 * @return {Object} Configuration object for the panel containing the composite field
	 * @private
	 */
	createRecipientPanel : function()
	{
		return {
			xtype : 'zarafa.resizablecompositefield',
			cls : 'k-field-to',
			ref: 'recipientPanel',
			anchor : '100%',
			autoHeight: false,
			items: [{
				xtype: 'button',
				autoHeight: true,
				text: _('To') + ':',
				handler: this.showRecipientContent,
				scope: this
			},{
				xtype: 'zarafa.recipientfield',
				plugins : [ 'zarafa.recordcomponentupdaterplugin' ],
				flex: 1
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel panel} containing the form element
	 * to set the subject
	 * @return {Object} Configuration object for the panel containing the fields
	 * @private
	 */
	createSubjectPanel : function()
	{
		return {
			xtype: 'panel',
			cls: 'k-subject-panel',
			layout: 'form',
			labelWidth: 85,
			labelAlign: 'left',
			autoHeight: true,
			border: false,
			items: [{
				xtype: 'textfield',
				name: 'subject',
				fieldLabel: _('Subject'),
				anchor: '100%',
				listeners: {
					change: this.onFieldChange,
					scope: this
				}
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel panel} containing the form element
	 * to set the location
	 * @return {Object} Configuration object for the panel containing the fields
	 * @private
	 */
	createLocationPanel : function()
	{
		return {
			xtype: 'panel',
			cls: 'k-location-panel',
			layout: 'form',
			labelWidth: 85,
			labelAlign: 'left',
			autoHeight: true,
			border: false,
			items: [{
				xtype: 'textfield',
				name: 'location',
				fieldLabel: _('Location'),
				anchor: '100%',
				enableKeyEvents: true,
				listeners: {
					change: this.onFieldChange,
					keypress: this.onLocationKeyPress,
					scope: this
				}
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel panel} containing the following elements
	 * in a table layout: the date panel, recurrence panel, busy status panel,
	 * reminder panel, and the label panel.
	 * @return {Object} Configuration object for the panel containing the fields
	 * @private
	 */
	createDateTimePanel : function()
	{
		return {
			xtype: 'panel',
			cls: 'k-datetime-panel',
			border: false,
			autoHeight: true,
			layout: {
				type: 'table',
				columns: 2
			},
			items : [
				{
					xtype: 'panel',
					border: false,
					items: [
						this.createDatePanel(),
						this.createRecurrencePanel()
					]
				},
				this.createBusyStatusPanel(),

				this.createReminderPanel(),
				{
					xtype: 'container',
					cls: 'filler'
				}
			]
		};
	},

	/**
	 * Create the {@link Ext.Panel panel} containing the form element
	 * to set the calendar in which the appointment or meeting-request will be
	 * created.
	 * @return {Object} Configuration object for the panel containing the fields
	 * @private
	 */
	createinPanel : function()
	{
		//config options necessary to create store which feeds the data to create-in-combo.
		const createInStore = {
			xtype: 'jsonstore',
			fields: ['entryid', 'store_entryid', 'displayString', 'iconColor'],
			data : this.getCreateInData()
		};

		const tplString = '<tpl for=".">' +
			'<div class="x-combo-list-item">' +
				'{[Zarafa.calendar.ui.IconCache.getCalendarSvgStructure(values.iconColor)]}' +
				'{displayString}' +
			'</div>' +
		'</tpl>';

		return {
			xtype: 'panel',
			cls: 'k-createin-panel',
			hidden: (createInStore.data.length < 2),
			layout: 'form',
			labelWidth: 85,
			labelAlign: 'left',
			autoHeight: true,
			border: false,
			items: [{
				xtype: 'combo',
				tpl : tplString,
				fieldLabel: _('Create in'),
				ref: '../comboCreateIn',
				store: createInStore,
				cls : 'k-createin-combo',
				listClass : 'k-createin-combo-list-svg',
				mode: 'local',
				triggerAction: 'all',
				displayField: 'displayString',
				valueField: 'entryid',
				lazyInit: false,
				forceSelection: true,
				editable: false,
				listeners: {
					select: this.onCreateInSelect,
					beforeexpand: this.onCreateInBeforeExpand,
					collapse: this.setCursorPosition,
					expand: this.setCursorPosition,
					scope: this
				}
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel Panel} containing the
	 * {@link Zarafa.common.ui.DateTimePeriodField DateTimePeriodField}.
	 * @return {Object} Configuration object for the panel with time selection fields
	 * @private
	 */
	createDatePanel : function()
	{
		return {
			xtype: 'panel',
			cls: 'k-date-panel',
			layout: {
				type: 'table',
				columns: 3
			},
			ref: '../../datePanel',
			autoHeight: true,
			autoWidth: true,
			border: false,
			items: [{
				xtype: 'zarafa.datetimeperiodfield',
				ref: '../../../datetimePeriod',
				defaultPeriod: container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_appointment_period'),
				defaultPeriodType : Date.MINUTE,
				timeIncrement: container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_zoom_level'),
				width: 585,
				allowEqualValue : true,
				layout: 'hbox',
				listeners: {
					change: this.onDateRangeFieldChange,
					scope: this
				},
				startFieldConfig: {
					fieldLabel: _('Time'),
					labelWidth: 84,

					cls: 'from-field'
				},
				endFieldConfig: {
					fieldLabel: _('until'),
					labelWidth: 84,
					cls: 'to-field'
				}
			},{
				xtype: 'spacer',
				width: 10
			},{
				xtype: 'panel',
				border: false,
				items: [{
					xtype: 'checkbox',
					name: 'alldayevent',
					boxLabel: _('All Day Event'),
					handler: this.onToggleAllDay,
					scope: this
				}]
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel Panel} containing the form fields
	 * for displaying the recurrence information.
	 * @return {Object} Configuration object for the panel with recurrence fields
	 * @private
	 */
	createRecurrencePanel : function()
	{
		return {
			xtype: 'panel',
			cls: 'k-recurrence-panel',
			ref: '../../recurrencePanel',
			layout: 'form',
			autoHeight: true,
			border: false,
			items: [{
				xtype: 'displayfield',
				ref: '../../../recurrencePatternField',
				fieldLabel: _('Recurrence'),
				htmlEncode : true
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel Panel} containing the form fields
	 * for setting the reminder information.
	 * @return {Object} Configuration object for the panel with reminder fields
	 * @private
	 */
	createReminderPanel : function()
	{
		var reminderStore = {
			xtype: 'jsonstore',
			fields: ['name', 'value'],
			data : Zarafa.calendar.data.ReminderPeriods
		};

		return {
			xtype: 'panel',
			cls: 'k-reminder-panel',
			autoHeight: true,
			border: false,
			items: [{
				xtype: 'zarafa.compositefield',
				autoHeight: true,
				items: [{
					xtype: 'checkbox',
					name: 'reminder',
					boxLabel: _('Reminder') + ':',
					width: 79,
					handler: this.onToggleReminder,
					scope: this
				},{
					xtype: 'combo',
					ref: '../../../comboReminder',
					name: 'reminder_minutes',
					store: reminderStore,
					mode: 'local',
					triggerAction: 'all',
					displayField: 'name',
					valueField: 'value',
					lazyInit: false,
					forceSelection: true,
					editable: false,
					listeners: {
						select: this.onFieldSelect,
						scope: this
					}
				}]
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel Panel} containing the form fields
	 * for setting the busy status.
	 * @return {Object} Configuration object for the panel with reminder fields
	 * @private
	 */
	createBusyStatusPanel : function()
	{
		var busyStore = {
			xtype: 'jsonstore',
			fields: ['name', 'value'],
			data : Zarafa.calendar.data.BusyStatus
		};

		return {
			xtype: 'panel',
			cls: 'k-busystatus-panel',
			layout: 'form',
			autoHeight: true,
			border: false,
			labelAlign: 'left',
			items: [{
				xtype: 'combo',
				ref: '../../comboBusyStatus',
				name: 'busystatus',
				fieldLabel: _('Show as'),
				store: busyStore,
				mode: 'local',
				triggerAction: 'all',
				displayField: 'name',
				valueField: 'value',
				lazyInit: false,
				forceSelection: true,
				editable: false,
				listeners: {
					select: this.onFieldSelect,
					scope: this
				}
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel Panel} which contains all attachment selection fields
	 * @return {Object} configuration object for the panel containing the attachment fields
	 * @private
	 */
	createAttachmentsPanel : function()
	{
		return {
			xtype: 'zarafa.resizablecompositefield',
			hideLabel: true,
			anchor: '100%',
			cls: 'k-field-attachments',
			autoHeight: true,
			items: [{
				// FIXME: Remove after WA-4880 is implemented
				xtype : 'button',
				ref : '../occurenceAttachmentsButton',
				text : _('Attachments') + ':',
				width: 100,
				handler: function() {
					Ext.MessageBox.show({
						title : _('Warning'),
						msg : _('Attachments cannot be modified for a single occurence'),
						buttons: Ext.Msg.OK,
						icon: Ext.MessageBox.WARNING
					});
				}
			},{
				xtype: 'zarafa.attachmentbutton',
				ref : '../normalAttachmentsButton', // FIXME: Remove after WA-4880 is implemented
				plugins : [ 'zarafa.recordcomponentupdaterplugin' ],
				text: _('Attachments') + ':',
				autoHeight: true,
				width: 100
			},{
				xtype: 'spacer',
				width: 5
			},{
				xtype: 'zarafa.attachmentfield',
				plugins : [ 'zarafa.recordcomponentupdaterplugin' ],
				ref : '../attachField',
				flex: 1,
				hideLabel: true
			}]
		};
	},

	/**
	 * Create the {@link Ext.Panel Panel} containing the
	 * {@link Zarafa.common.ui.htmleditor.HtmlEditor HtmlEditor} form field.
	 * @return {Object} Configuration object containing the HtmlEditor
	 * @private
	 */
	createBodyPanel : function()
	{
		return {
			xtype: 'panel',
			cls: 'k-body-panel',
			layout: 'fit',
			border: false,
			flex: 1,
			autoHeight: false,
			items: [{
				xtype: 'zarafa.editorfield',
				ref: '../editorField',
				hideLabel: true,
				flex: 1,
				useHtml: false,
				listeners: {
					// Use the afterrender event to place the placeholder attribute
					afterrender: function(){
						this.editorField.getEditor().getEl().set({
							placeholder: _('Type your message here...')
						});
					},
					change: this.onBodyChange,
					scope: this
				}
			}]
		};
	},

	/**
	 * Event is fired when keypress event is fired on location field, ie. user changes location manually
	 * @param {HtmlElement} element The target of the event
	 * @param {Ext.EventObject} event The Ext.EventObject encapsulating the DOM event
	 */
	onLocationKeyPress : function(element, event)
	{
		this.hasUserSetLocation = true;
	},

	/**
	 * Enable/disable/hide/unhide all {@link Ext.Component Components} within the {@link Ext.Panel Panel}
	 * using the given {@link Zarafa.core.data.IPMRecord IPMRecord}.
	 * @param {Zarafa.core.data.IPMRecord} record The record to update the panel with
	 * @param {Boolean} contentReset force the component to perform a full update of the data.
	 * @private
	 */
	updateUI : function(record, contentReset)
	{
		var layout = false;

		if (contentReset === true || record.isModifiedSinceLastUpdate('meeting')) {
			switch (record.get('meeting')) {
				case Zarafa.core.mapi.MeetingStatus.NONMEETING:
				/* falls through */
				default:
					this.dialog.closeOnSave = true;
					this.dialog.closeOnSend = false;
					this.recipientPanel.setVisible(false);
					break;
				case Zarafa.core.mapi.MeetingStatus.MEETING:
					this.dialog.closeOnSave = false;
					this.dialog.closeOnSend = true;
					this.recipientPanel.setVisible(true);
					break;
				case Zarafa.core.mapi.MeetingStatus.MEETING_RECEIVED:
				case Zarafa.core.mapi.MeetingStatus.MEETING_CANCELED:
				case Zarafa.core.mapi.MeetingStatus.MEETING_RECEIVED_AND_CANCELED:
					// here we ensure that response status,is nither none nor organizer
					if(record.get('responsestatus') != Zarafa.core.mapi.ResponseStatus.RESPONSE_NONE || record.get('responsestatus') != Zarafa.core.mapi.ResponseStatus.RESPONSE_ORGANIZED) {
						this.meetingOrganizerPanel.setVisible(true);
						this.recipientPanel.setVisible(false);
					}
					break;
			}

			layout = true;
		}

		if (contentReset === true || record.isModifiedSinceLastUpdate('alldayevent')) {
			if (record.get('alldayevent')) {
				this.datetimePeriod.setEnabledTimeSelection(false);
				// For allday events, we only allow selections of entire days
				this.datetimePeriod.defaultPeriod = 1;
				this.datetimePeriod.defaultPeriodType = Date.DAY;
			} else {
				this.datetimePeriod.setEnabledTimeSelection(true);
				// For normal events, we have to configure the normal period options again
				this.datetimePeriod.defaultPeriod = container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_appointment_period');
				this.datetimePeriod.defaultPeriodType = Date.MINUTE;
			}
		}

		if (contentReset === true || record.isModifiedSinceLastUpdate('reminder')) {
			if (record.get('reminder')) {
				this.comboReminder.enable();
			} else {
				this.comboReminder.disable();
			}
		}

		if (contentReset === true || record.isModifiedSinceLastUpdate('recurring')) {
			if (record.get('recurring') && Ext.isEmpty(record.get('basedate'))) {
				this.datePanel.setVisible(false);
				this.recurrencePanel.setVisible(true);
			} else {
				this.datePanel.setVisible(true);
				this.recurrencePanel.setVisible(false);
				this.recurrencePatternField.setValue('');
			}

			layout = true;
		}

		// FIXME: Remove after WA-4880 is implemented
		if (contentReset === true) {
			if (record.isRecurringOccurence()) {
				this.occurenceAttachmentsButton.setVisible(true);
				this.normalAttachmentsButton.setVisible(false);

				this.attachField.setEditable(false);
			} else {
				this.occurenceAttachmentsButton.setVisible(false);
				this.normalAttachmentsButton.setVisible(true);

				this.attachField.setEditable(true);
			}

			layout = true;
		}

		if (contentReset === true || record.isModifiedSinceLastUpdate('reminder')) {
			if (record.get('alldayevent')) {
				this.comboReminder.setValue(container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_allday_reminder_time'));
				this.comboBusyStatus.setValue(Zarafa.core.mapi.BusyStatus.FREE);
			} else {
				this.comboReminder.setValue(container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_reminder_time'));
				this.comboBusyStatus.setValue(Zarafa.core.mapi.BusyStatus.BUSY);
			}
		}

		if (layout) {
			this.doLayout();
		}
	},

	/**
	 * Update the {@link Ext.Panel Panel} with the given {@link Zarafa.core.data.IPMRecord IPMRecord}
	 * @param {Zarafa.core.data.IPMRecord} record The record to update the panel with
	 * @param {Boolean} contentReset force the component to perform a full update of the data.
	 */
	update : function(record, contentReset)
	{
		this.record = record;
		this.updateUI(record, contentReset);
		this.getForm().loadRecord(record);

		var startDate = record.get('startdate');
		var startDateUpdate = false;
		if (Ext.isDate(startDate)) {
			startDate = startDate.clone();
			startDateUpdate = contentReset || record.isModifiedSinceLastUpdate('startdate');
		}
		var dueDate = record.get('duedate');
		var dueDateUpdate = false;
		if (Ext.isDate(dueDate)) {
			dueDate = dueDate.clone();
			dueDateUpdate = contentReset || record.isModifiedSinceLastUpdate('duedate');
		}

		// For all day events we store the due date as 00:00 on the day after
		// it ends. For the UI, this means we have to substract 1 day to get
		// the date on which the appointment actually ends for the user.
		if (record.get('alldayevent')) {
			startDate.clearTime();

			// Set time to 12:00 when using Date.add(Date.DAY)
			// to prevent problems with DST switches at 00:00
			// (like in Brasil).
			dueDate.setHours(12);
			dueDate = dueDate.add(Date.DAY, -1).clearTime();
		}

		if (startDateUpdate || dueDateUpdate) {
			this.datetimePeriod.getValue().set(startDate, dueDate);
		}

		if (contentReset && record.isOpened()) {
			this.editorField.setValue(record.getBody(this.editorField.isHtmlEditor()));
		}

		if (contentReset && this.comboCreateIn.isVisible()) {
			const model = container.getContextByName('calendar').model;
			const selectedFolder = model.getFolder(record.get('parent_entryid'));
			var folderToSelect;

			if (Ext.isDefined(selectedFolder) && selectedFolder.isInDeletedItems()){
				folderToSelect = model.defaultFolder.get('entryid');
			} else {
				folderToSelect = record.get('parent_entryid');
			}

			this.comboCreateIn.setValue(folderToSelect);
			const folderColor = this.getFolderColor(folderToSelect);
			this.comboCreateIn.el.setStyle('background-image', 'url(\'' + Zarafa.calendar.ui.IconCache.getCalendarSvgIcon(folderColor) + '\')');
		}

		this.updateExtraInfoPanel();

		if (contentReset === true || record.isModifiedSinceLastUpdate('recurring_pattern')) {
			this.recurrencePatternField.setValue(record.get('recurring_pattern'));
		}

		/*
		 * When any property with reminder is changed then we need
		 * to update reminder_time and flagdueby aswell, When
		 * 1) flagdueby is changed
		 * 2) reminder minutes is changed
		 * 3) startdate and reminder time not same
		 */
		if (record.get('reminder') === true) {
			if(!record.get('flagdueby') ||  record.isModifiedSinceLastUpdate('reminder_minutes') || record.get('reminder_time') !== record.get('startdate')) {
				var reminderDate;

				if (record.isRecurring() || record.isRecurringOccurence()) {
					reminderDate = record.get('startdate_recurring');
				}

				if (!reminderDate) {
					reminderDate = record.get('startdate');
				}

				if (Ext.isDate(reminderDate)) {
					record.set('reminder_time', reminderDate.clone());
					record.set('flagdueby', reminderDate.add(Date.MINUTE, -record.get('reminder_minutes')));
				}
			}
		}

		if(record.isOpened() && record.isSubStoreModifiedSincelastUpdate('recipients')) {
			var recipients = record.updateSubStoreModifications.recipients;

			// Check if changes (Added/Removed/Updated) are room resource
			if(recipients && recipients.changes) {
				var changedRecipients = recipients.changes;
				var isResouceChanged = false;

				for(var i = 0; i < changedRecipients.length; i++) {
					if(changedRecipients[i].get('display_type_ex') === Zarafa.core.mapi.DisplayTypeEx.DT_ROOM) {
						isResouceChanged = true;
						break;
					}
				}

				if(isResouceChanged) {
					this.updateLocation();
				}
			}
		}
	},

	/**
	 * Function updates the location in the {@link Zarafa.core.data.IPMRecord record}
	 * It uses {@link Zarafa.core.mapi.DisplayTypeEx.DT_ROOM room} resources to
	 * generate location from the recipient table.
	 *
	 * @private
	 */
	updateLocation : function()
	{
		var locations = [];
		var recipientStore = this.record.getSubStore('recipients');

		// Create location suggestion string using room resources of the recipient store
		recipientStore.each(function(recipient) {
			if (recipient.get('display_type_ex') === Zarafa.core.mapi.DisplayTypeEx.DT_ROOM){
				var name = recipient.get('display_name');

				if (!Ext.isEmpty(name)) {
					locations.push(name);
				}
			}
		});

		var locationSuggestion = locations.join('; ');
		var meetingLocation = this.record.get('location');

		// If suggested location and current location is same then no need to set/suggest.
		if(meetingLocation == locationSuggestion) {
			return;
		}

		if(this.hasUserSetLocation === false || Ext.isEmpty(meetingLocation) || meetingLocation.toUpperCase() == locationSuggestion.toUpperCase()) {
			// If user haven't changed location by himself or record's location is empty or
			// it is already suggested location in different case(upper/lower) then set it.
			this.doSetLocation(locationSuggestion);
		} else {
			//If suggested location seems different then ask user whether want to use suggested location or not.
			Ext.MessageBox.show({
				title: _('Kopano WebApp'),
				msg: String.format(_('Do you want to update the location "{0}" with the new location "{1}"?'), Ext.util.Format.htmlEncode(meetingLocation), Ext.util.Format.htmlEncode(locationSuggestion)),
				buttons: Ext.Msg.YESNO,
				icon: Ext.MessageBox.WARNING,
				fn: this.setLocation,
				locationSuggestion: locationSuggestion,
				scope: this
			});
		}
	},

	/**
	 * Function sets location that is suggested to the user if user confirms.
	 *
	 * @param {String} buttonId The ID of the button pressed, here 'yes' or 'no'
	 * @param {String} text String Value of the input field if either prompt
	 * @param {Object} opt The config object passed to the messagebox.
	 *
	 * @private
	 */
	setLocation : function(button, text, opt)
	{
		if(button == "yes") {
			this.doSetLocation(opt.locationSuggestion);
		}
	},

	/**
	 * Function sets location which is given as suggestion is passed to the function.
	 * Function also clears {@link hasUserSetLocation} flag as we have overwritten
	 * user changed location with our generated location string so from next time this
	 * should not be considered as user change
	 * @param {String} locationString String value of the location.
	 *
	 * @private
	 */
	doSetLocation : function(locationString)
	{
		this.record.set('location', locationString);

		// We have automatically changed location, so this flag needs to be cleared.
		this.hasUserSetLocation = false;
	},

	/**
	 * Update the {@link Zarafa.core.data.IPMRecord IPMRecord} with the data from the {@link Ext.Panel Panel}.
	 * @param {Zarafa.core.data.IPMRecord} record The record which has to be updated
	 */
	updateRecord : function(record)
	{
		record.beginEdit();
		this.getForm().updateRecord(record);
		this.updateStartDueDate(record, this.datetimePeriod.getValue());

		/*
		 * When any property with reminder is changed then we need
		 * to update reminder_time and flagdueby aswell, When
		 * 1) flagdueby is changed
		 * 2) reminder minutes is changed
		 * 3) startdate is changed
		 */
		if (record.get('reminder') === true) {
			if(!record.get('flagdueby') || record.isModifiedSinceLastUpdate('reminder_minutes') || record.isModifiedSinceLastUpdate('startdate')) {
				var reminderDate;

				if (record.isRecurring() || record.isRecurringOccurence()) {
					reminderDate = record.get('startdate_recurring');
				}

				if (!reminderDate) {
					reminderDate = record.get('startdate');
				}

				if (Ext.isDate(reminderDate)) {
					record.set('reminder_time', reminderDate.clone());
					record.set('flagdueby', reminderDate.add(Date.MINUTE, -record.get('reminder_minutes')));
				}
			}
		}

		// Remove auxiliary_flags if unset copy meeting is going to send.
		if (record.hasMessageAction('send') && record.isCopied()) {
			record.set('auxiliary_flags', 0);
		}

		this.onBodyChange(this.editorField.getEditor(), this.editorField.getValue());

		record.endEdit();
	},

	/**
	 * Event handler which is fired when a field has been changed.
	 * This will update the corresponding field inside the {@link Zarafa.core.data.IPMRecord record}.
	 * @param {Ext.form.Field} field The field which has changed
	 * @param {Mixed} newValue The new value for the field
	 * @param {Mixed} oldValue The original value for the field
	 * @private
	 */
	onFieldChange : function(field, newValue, oldValue)
	{
		this.record.set(field.getName(), newValue);
	},

	/**
	 * Event handler which is triggered when one of the Input fields
	 * has been changed by the user. It will validate the new value,
	 * and if correct, will apply it to the {@link Zarafa.core.data.IPMRecord record}.
	 * @param {Ext.form.Field} field The {@link Ext.form.Field field} which was changed.
	 * @param {Mixed} newValue The new value
	 * @param {Mixed} oldValue The old value
	 * @private
	 */
	onBodyChange : function(field, newValue, oldValue)
	{
		var record = this.record;
		var isHtmlEditor = field instanceof Ext.form.HtmlEditor;

		record.beginEdit();
		record.setBody(newValue, isHtmlEditor);
		record.endEdit();
	},

	/**
	 * Event handler which is fired when a combobox selection has changed.
	 * This will update the corresponding field inside the {@link Zarafa.core.data.IPMRecord record}
	 * @param {Ext.form.ComboBox} combo The combobox which was selected
	 * @param {Ext.data.Record} record The selected record
	 * @param {Number} index The index of the selected record
	 * @private
	 */
	onFieldSelect : function(combo, record, index)
	{
		this.record.set(combo.getName(), record.get(combo.valueField));
	},

	/**
	 * Event handler which is fired when a combobox selection has changed.
	 * This will update the corresponding field inside the {@link Zarafa.core.data.IPMRecord record}
	 * @param {Ext.form.ComboBox} combo The combobox which was selected
	 * @param {Ext.data.Record} record The selected calender-folder record
	 * @param {Number} index The index of the selected record
	 * @private
	 */
	onCreateInSelect : function(combo, record, index)
	{
		if (this.record.phantom) {
			this.record.set('parent_entryid', record.get('entryid'));
			this.record.set('store_entryid', record.get('store_entryid'));
		} else {
			this.record.moveTo(record);
		}

		combo.el.setStyle('background-image', 'url(\'' + Zarafa.calendar.ui.IconCache.getCalendarSvgIcon(record.get('iconColor')) + '\')');
	},

	/**
	 * Event handler which is fired when combobox-list expanded or collapsed.
	 * This will put cursor at the beginning of combobox content to avoid
	 * text overlapping calendar-icon.
	 * @param {Ext.form.ComboBox} combo The combobox which was selected
	 * @private
	 */
	setCursorPosition : function(combo)
	{
		combo.el.dom.setSelectionRange(0, 0);
	},

	/**
	 * Helper function to obtain color for given folder entryid.
	 * @param {String} entryid Entry id of a folder
	 * @return {String} The color as defined in {@link Zarafa.calendar.ui.ColorSchemes color-scheme}
	 * for given folder
	 */
	getFolderColor : function(entryid)
	{
		var calendarContext = container.getContextByName('calendar');
		var scheme = calendarContext.getModel().getColorScheme(entryid);

		return scheme.base;
	},

	/**
	 * Helper function to return array containing options necessary to create
	 * store which feeds the data to create-in-combo along with entryid of respective
	 * calendar folder.
	 * @return {Object} Config set which has all calendar folders.
	 */
	getCreateInData : function()
	{
		var calendarFolders = container.getHierarchyStore().getByContainerClass('IPF.Appointment');
		var createInData = [];

		calendarFolders.forEach(function(dataItem) {
			if (!(dataItem.get('rights') & Zarafa.core.mapi.Rights.RIGHTS_CREATE)) {
				return;
			}

			var displayString = dataItem.get('display_name');
			var mapiStore = dataItem.getParentFolder().getMAPIStore();

			if (mapiStore.isSharedStore()) {
				displayString += ' - ' + mapiStore.get('mailbox_owner_name');
			}

			createInData.push({
				'entryid' : dataItem.get('entryid'),
				'store_entryid' : dataItem.get('store_entryid'),
				'displayString' : displayString,
				'iconColor' : this.getFolderColor(dataItem.get('entryid'))
			});
		}, this);

		return createInData;
	},

	/**
	 * Event handler which is fired before a combobox-list gets expanded.
	 * This will update combobox-store according to the current calendar folders available.
	 * @param {Ext.form.ComboBox} combo The combobox which was selected
	 * @private
	 */
	onCreateInBeforeExpand : function(combo)
	{
		const createInStore = combo.store;
		const readerData = createInStore.reader.readRecords(this.getCreateInData());
		createInStore.removeAll();
		createInStore.add(readerData.records);
		createInStore.applySort();
	},

	/**
	 * Event handler which is fired when the {@link Zarafa.common.ui.DateRangeField} has been changed.
	 * This will update the start and due date inside the {@link #record} accordingly.
	 * @param {Ext.form.Field} field The field which has changed
	 * @param {Mixed} newValue The new value for the field
	 * @param {Mixed} oldValue The original value for the field
	 * @private
	 */
	onDateRangeFieldChange : function(field, newRange, oldRange)
	{
		this.updateStartDueDate(this.record, newRange);
	},

	/**
	 * Update the 'startdate' and 'duedate' in the given record from
	 * the given daterange. When the appointment is an allday event, then
	 * the times are always set to midnight. However when selecting
	 * the duedate the user selects on which day the appointment
	 * ends, so in reality the appointment ends on 00:00 hours on
	 * the following day.
	 * @param {Zarafa.core.data.MAPIRecord} record the Record to update
	 * @param {Zarafa.core.DateRange} daterange the Daterange to apply
	 * @private
	 */
	updateStartDueDate : function(record, daterange)
	{
		var startDate = daterange.getStartDate().clone();
		var dueDate = daterange.getDueDate().clone();

		if (record.get('alldayevent') === true) {
			startDate = startDate.clearTime();
			// Set time to 12:00 when using Date.add(Date.DAY)
			// to prevent problems with DST switches at 00:00
			// (like in Brasil).
			dueDate.setHours(12);
			dueDate = dueDate.add(Date.DAY, 1).clearTime();
		}

		record.beginEdit();
		record.set('startdate', startDate);
		record.set('duedate', dueDate);
		record.set('commonstart', startDate);
		record.set('commonend', dueDate);
		record.set('duration', (dueDate - startDate) / (60 * 1000));
		record.endEdit();
	},

	/**
	 * A function called when the checked value changes for the
	 * reminder checkbox.
	 * @param {Ext.form.Checkbox} checkbox The Checkbox being toggled.
	 * @param {Boolean} checked The new checked state of the checkbox.
	 * @private
	 */
	onToggleReminder : function(checkbox, checked)
	{
		this.record.set('reminder', checked);
	},

	/**
	 * A function called when the checked value changes for the
	 * all day event checkbox.
	 * @param {Ext.form.Checkbox} checkbox The Checkbox being toggled.
	 * @param {Boolean} checked The new checked state of the checkbox.
	 * @private
	 */
	onToggleAllDay : function(checkbox, checked)
	{
		if (this.record.get('alldayevent') !== checked) {
			this.record.beginEdit();
			this.record.set('alldayevent', checked);
			if (checked) {
				this.updateStartDueDate(this.record, this.datetimePeriod.getValue());

				this.record.set('reminder_minutes', container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_allday_reminder_time'));
				this.record.set('busystatus', Zarafa.core.mapi.BusyStatus.FREE);
			} else {
				var zoomLevel = container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_zoom_level');
				var defaultPeriod = container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_appointment_period');

				var startDate = new Date();
				if(this.record.get('startdate')) {
					// use existing date if it is set
					startDate = this.record.get('startdate').clearTime(true);
				}

				startDate = startDate.ceil(Date.MINUTE, zoomLevel);
				var dueDate = startDate.add(Date.MINUTE, defaultPeriod);

				this.record.set('reminder_minutes', container.getSettingsModel().get('zarafa/v1/contexts/calendar/default_reminder_time'));
				this.record.set('busystatus', Zarafa.core.mapi.BusyStatus.BUSY);
				this.record.set('startdate', startDate);
				this.record.set('duedate', dueDate);
				this.record.set('commonstart', startDate);
				this.record.set('commonend', dueDate);
				this.record.set('duration', (dueDate - startDate) / (60 * 1000));
			}
			this.record.endEdit();
		}
	},

	/**
	 * Function will open AddressBook dialog to add attendees
	 * @private
	 */
	showRecipientContent : function()
	{
		Zarafa.calendar.Actions.openRecipientSelectionContent(this.record, { defaultRecipientType : Zarafa.core.mapi.RecipientType.MAPI_TO });
	},

	/**
	 * Function will update the {@link #extraInfoPanel} with extra information that should be shown
	 * for the meeting item.
	 * @private
	 */
	updateExtraInfoPanel : function()
	{
		// clear the previous contents
		var el = this.extraInfoPanel.getEl();
		if(Ext.isDefined(el.dom)) {
			el.dom.innerHTML = '';
		}

		var visible = this.setOldAppointmentInfo(el);

		if(this.record.isRecurringOccurence()){
			visible = (this.setRecurrencePatternInfo(el) === true) ? true : visible;
		}

		if(this.record.isMeeting()) {
			if(!this.record.phantom) {
				if (this.record.isMeetingOrganized()) {
					// set information for organizer
					if (!this.record.isMeetingSent()) {
						visible = (this.setMeetingUnsentInfo(el) === true) ? true : visible;
					} else {
						visible = (this.setMeetingResponseInfo(el) === true) ? true : visible;
					}
				} else {
					var responseStatus = this.record.get('responsestatus');

					if(responseStatus !== Zarafa.core.mapi.ResponseStatus.RESPONSE_NONE) {
						this.setOrganizerInfo();
						visible = (this.setMeetingOverwrittenInfo(el) === true) ? true : visible;
					}

					if (this.record.isMeetingCanceled()) {
						// set information for canceled meeting in attendee's calendar
						visible = (this.setMeetingCanceledInfo(el) === true) ? true : visible;
					} else if (this.record.isMeetingResponseRequired()) {
						// set information for attendees
						visible = (this.setReplyTimeInfo(responseStatus, el) === true) ? true : visible;
					}
				}
			}
		}

		this.extraInfoPanel.setVisible(visible);
		this.doLayout();
	},

	/**
	 * Function will display message regarding response's from attendee(s) in the dialog
	 * thus will update the status of attendee(s) to meeting organizer
	 * @param {HtmlElement} HTML element
	 * @return Boolean true if new component is added in {@link #extraInfoPanel} else false.
	 * @private
	 */
	setMeetingResponseInfo : function(el)
	{
		// check for meeting items which are not sent yet
		if(this.record.isMeetingSent()) {
			return false;
		}

		var accepted = 0, tentative = 0, declined = 0, numProposingAttendees = 0;
		var recipientStore = this.record.getRecipientStore();

		recipientStore.each(
			function (recipient) {
				switch(recipient.get('recipient_trackstatus'))
				{
					case Zarafa.core.mapi.RecipientTrackStatus.RECIPIENT_TRACKSTATUS_TENTATIVE: // tentative
						tentative++;
						break;
					case Zarafa.core.mapi.RecipientTrackStatus.RECIPIENT_TRACKSTATUS_ACCEPTED: //accepted
						accepted++;
						break;
					case Zarafa.core.mapi.RecipientTrackStatus.RECIPIENT_TRACKSTATUS_DECLINED: //decline
						declined++;
						break;
				}

				if(recipient.get('proposednewtime')) {
					numProposingAttendees++;
				}
			}, this);

		if(accepted !== 0 || tentative !== 0 || declined !== 0) {
			// set response string
			var trackString = String.format(this.trackingInfoString, accepted, tentative, declined);
			el.createChild({tag: 'div', html: trackString});

			if(this.record.get('counter_proposal') && numProposingAttendees !== 0) {
				var proposeString = String.format(this.proposedTimeInfoString, numProposingAttendees);
				el.createChild({tag: 'div', html: proposeString});
			}
		} else {
			// set no response string
			el.createChild({tag: 'div', html: this.noResponseReceivedString });
		}

		return true;
	},

	/**
	 * Function will display message regarding request accepted time for an attendee
	 * @param {Zarafa.core.mapi.ResponseStatus} responseStatus for the meeting
	 * @param {HtmlElement} HTML element
	 * @return Boolean true if new component is added in {@link #extraInfoPanel} else false.
	 * @private
	 */
	setReplyTimeInfo : function(responseStatus,el)
	{
		var responseString = '';
		var replyTime = this.record.get('reply_time');
		var replyName = this.record.get('reply_name');
		var dueDate = this.record.get('duedate');

		if(responseStatus !== Zarafa.core.mapi.ResponseStatus.RESPONSE_NOT_RESPONDED) {
			// # TRANSLATORS: See http://docs.sencha.com/ext-js/3-4/#!/api/Date for the meaning of these formatting instructions
			replyTime = Ext.isDate(replyTime) ? replyTime.format(_('jS F Y G:i')) : _('None');

			if(this.record.get('counter_proposal')) {
				if(!Ext.isEmpty(replyName)) {
					responseString = String.format(this.proposeNewTimeDelegateInfoString, replyName, replyTime);
				} else {
					responseString = String.format(this.proposeNewTimeInfoString, replyTime);
				}
			} else {
				switch(responseStatus) {
					case Zarafa.core.mapi.ResponseStatus.RESPONSE_ACCEPTED :
						if(!Ext.isEmpty(replyName)) {
							responseString = String.format(this.acceptedDelegateInfoString, replyName, replyTime);
						} else {
							responseString = String.format(this.acceptedInfoString, replyTime);
						}
						break;
					case Zarafa.core.mapi.ResponseStatus.RESPONSE_TENTATIVE :
						if(!Ext.isEmpty(replyName)) {
							responseString = String.format(this.tentativeDelegateInfoString, replyName, replyTime);
						} else {
							responseString = String.format(this.tentativeInfoString, replyTime);
						}
						break;
				}
			}
		} else {
			if(Ext.isDate(dueDate) && dueDate.getTime() >= (new Date().getTime())) {
				// Meeting is in future, but not replied yet
				responseString = this.responseRequiredString;
			}
		}

		if(!Ext.isEmpty(responseString)) {
			el.createChild({tag: 'div', html: responseString});
			return true;
		}

		return false;
	},

	/**
	 * Function will set information string to show that appointment occurs in past.
	 * @param {HtmlElement} HTML element
	 * @return Boolean true if new component is added in {@link #extraInfoPanel} else false.
	 * @private
	 */
	setOldAppointmentInfo : function(el)
	{
		if(this.record.isAppointmentInPast()) {
			el.createChild({tag: 'div', html: this.elapsedTimeInfoString});

			return true;
		}

		return false;
	},

	/**
	 * Function will add information regarding organizer of the meeting.
	 * @private
	 */
	setOrganizerInfo : function()
	{
		this.meetingOrganizerField.setValue(this.record.getSenderString());
	},

	/**
	 * Function will set information string to show that meeting is canceled in the attendee's calendar.
	 * @param {HtmlElement} HTML element
	 * @return Boolean true if new component is added in {@link #extraInfoPanel} else false.
	 * @private
	 */
	setMeetingCanceledInfo : function(el)
	{
		el.createChild({tag: 'div', html: this.meetingCanceledString});
		return true;
	},

	/**
	 * Function will set information string to show that meeting invites have not yet been sent.
	 * @param {HtmlElement} HTML element
	 * @return Boolean true if new component is added in {@link #extraInfoPanel} else false.
	 * @private
	 */
	setMeetingUnsentInfo : function(el)
	{
		el.createChild({tag : 'div', html: this.meetingUnsentString});
		return true;
	},

	/**
	 * Function will set the information string to show that changes made by attendee will
	 * be overwritten when the meeting request is updated by the organizer.
	 * @param {HtmlElement} HTML element
	 * @return Boolean true if new component is added in {@link #extraInfoPanel} else false.
	 * @private
	 */
	setMeetingOverwrittenInfo : function(el)
	{
		el.createChild({tag : 'div', html: this.meetingOverwrittenString});
		return true;
	},

	/**
	 * Function will set information string to show the recurring pattern the occurrence is part of.
	 * @param {HtmlElement} HTML element
	 * @return Boolean true if new component is added in {@link #extraInfoPanel} else false.
	 * @private
	 */
	setRecurrencePatternInfo: function(el)
	{
		el.createChild({tag: 'div', html: Ext.util.Format.htmlEncode(this.record.get('recurring_pattern'))});
		return true;
	}
});

Ext.reg('zarafa.appointmenttab', Zarafa.calendar.dialogs.AppointmentTab);