Ext.namespace('Zarafa.widgets.folderwidgets');

/**
 * @class Zarafa.widgets.folderwidgets.AbstractFolderWidget
 * @extends Zarafa.core.ui.widget.Widget
 *
 * Widget which can be used to show the contents of a
 * {@link Zarafa.hierarchy.data.MAPIFolderRecord folder}
 * using a particular restriction (during {@link #store}{@link Ext.data.Store#load})
 * or a filter (using {@link #store}{@link Ext.data.Store#applyFilter}).
 *
 * Reload time is configurable per instance of the
 * widget (keys: 'reloadinterval', default 5 minutes).  These values are in
 * saved in miliseconds but displayed in seconds. The reload
 * interval is how often the folder is fully reloaded from the
 * server, to show records that were added to the folder
 * outside of WebApp.
 */
Zarafa.widgets.folderwidgets.AbstractFolderWidget = Ext.extend(Zarafa.core.ui.widget.Widget, {
	/**
	 * The folder which is shown inside this widget. This is initialized
	 * by {@link #onHierarchyLoad}.
	 * @property
	 * @type Zarafa.hierarchy.data.MAPIFolderRecord
	 * @private
	 */
	folder: undefined,

	/**
	 * @cfg {Zarafa.core.data.MAPIStore} store The store which is being used for loading the records
	 */
	store: undefined,

	/**
	 * @cfg {String} folderType The folder type to obtain the desired folder
	 * from the {@link Zarafa.hierarchy.data.HierarchyStore hierarchy}.
	 */
	folderType: undefined,

	/**
	 * The task that was {@link Ext.TaskMgr.start started} to reload the folder grid.
	 * @property
	 * @type Object
	 * @private
	 */
	reloadTask: undefined,

	/**
	 * The configuration object for the configure window of the widget
	 * @property
	 * @type Object
	 * @private
	 */
	configurationConfig: undefined,

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

		// Set the guid so we can use the get() function
		this.guid = config.guid;

		Ext.applyIf(config, {
			hasConfig: true,
			height: this.get('widgetheight') || 300
		});

		Zarafa.widgets.folderwidgets.AbstractFolderWidget.superclass.constructor.call(this, config);
	},

	/**
	 * Initialize the event handlers for the {@link #store} and {@link Zarafa.hierarchy.data.HierarchyStore Hierarchy}.
	 * @protected
	 */
	initEvents: function ()
	{
		Zarafa.widgets.folderwidgets.AbstractFolderWidget.superclass.initEvents.apply(this, arguments);

		// Wait for the hierarchy store to be loaded.
		var hierarchyStore = container.getHierarchyStore();
		this.mon(hierarchyStore, 'load', this.onHierarchyLoad, this);
		// needed when adding the widget after hierarchy load
		this.onHierarchyLoad(hierarchyStore);

		// Wait for the store to be loaded, so we can activate
		// the refreshing and reloading times.
		this.mon(this.store, 'load', this.startReloadTask, this, {single: true});

		// Apply the filter when we have new records
		this.mon(this.store, 'load', this.updateFilter, this);

		// Listen for record updates, as that might have impact on the filtering
		// which should be applied.
		this.mon(this.store, 'update', this.onStoreUpdate, this);
	},

	/**
	 * Load the default calendar folder and retrieve the records.
	 * @param {Zarafa.hierarchy.data.HierarchyStore} hierarchyStore The store which fired the event
	 * @private
	 */
	onHierarchyLoad: function (hierarchyStore)
	{
		this.folder = hierarchyStore.getDefaultFolder(this.folderType);
		if (this.folder) {
			this.reloadStore();
		}
	},

	/**
	 * Starts a reload task for the store. If one already exists, it will be stopped first.
	 * @private
	 */
	startReloadTask: function ()
	{
		if ( this.reloadTask ) {
			Ext.TaskMgr.stop(this.reloadTask);
		}

		// Periodically reload data from the server to remove stale
		// data from the store.  But only do this when the store has
		// finished loading for the first time.
		var interval = this.get('reloadinterval') || 300;
		interval *= 1000; // convert seconds in milliseconds

		this.reloadTask = Ext.TaskMgr.start({
			run: this.reloadStore,
			interval: interval,
			scope: this
		});
	},

	/**
	 * When the store record has been changed, {@link #updateFilter apply filter}
	 * to ensure that unwanted records are immediately removed.
	 * @private
	 */
	onStoreUpdate: function ()
	{
		this.updateFilter();
	},

	/**
	 * This will {@link Ext.data.Store#load load} the {@link #store}.
	 * @private
	 */
	reloadStore: function ()
	{
		if (this.folder) {
			this.store.load({folder: this.folder});
		}
	},

	/**
	 * Update the filter.
	 * @private
	 */
	updateFilter: Ext.emptyFn,

	/**
	 * Apply custom style and content for the row body. This will color
	 * a task in red when its due-date is reached. If categories are applied
	 * to a task these categories will be displayed.
	 *
	 * @param {Ext.data.Record} record The {@link Ext.data.Record Record} corresponding to the current row.
	 * @param {Number} rowIndex The row index
	 * @param {Object} rowParams A config object that is passed to the row template during
	 * rendering that allows customization of various aspects of a grid row.
	 * If enableRowBody is configured true, then the following properties may be set by this function,
	 * and will be used to render a full-width expansion row below each grid row.
	 * @return {String} a CSS class name to add to the row
	 * @private
	 */
	viewConfigGetRowClass: function (record, rowIndex, rowParams)
	{
		rowParams.body = '<div class="zarafa-grid-body-container">';

		// Render the categories
		var categories = Zarafa.common.categories.Util.getCategories(record);
		var categoriesHtml = Zarafa.common.categories.Util.getCategoriesHtml(categories);
		rowParams.body += '<div class="k-category-container">' + categoriesHtml + '</div>';

		// Render the subject
		var subject = Zarafa.common.ui.grid.Renderers.subject(record.get('subject'), {});
		rowParams.body += String.format('<div class="grid_compact grid_compact_left grid_compact_subject_cell">{0}</div>', subject);
		rowParams.body += '</div>';

		// Get the due date class from the normal TaskGridView
		var rowClass = Zarafa.task.ui.TaskGridView.prototype.viewConfigGetRowClass(record);

		return "x-grid3-row-expanded " + rowClass;
	},

	/**
	 * Create spinner field with the given minimum and maximum value.
	 * @param {Number} minHeight minimum value of spinner field.
	 * @param {Number} maxHeight maximum value of spinner field.
	 * @return {Object[]} An array with configuration objects of spinner field.
	 */
	createConfigHeight: function (minHeight, maxHeight)
	{
		return {
			xtype: 'zarafa.spinnerfield',
			fieldLabel: _('Widget height'),
			name: 'widgetheight',
			boxLabel: _('pixels'),
			width: 60,
			minValue: minHeight || 100, // 100 pixel
			maxValue: maxHeight || 500, // 500 pixel
			incrementValue: 5, // 5 pixel
			defaultValue: this.get('widgetheight') || 300,
			listeners: {
				'change': this.onFieldChange,
				scope: this
			},
			plugins: ['zarafa.numberspinner']
		};
	},

	/**
	 * Configure the widget.  At this time, only the reload and
	 * refresh times can be configured.
	 * @todo Also allow the user to select the folder(s) to show here.
	 * @private
	 */
	config: function ()
	{
		var config = Ext.apply({}, this.configurationConfig || {}, {
			title: _('Configure widget'),
			layout: 'fit',
			width: 320,
			height: 135,
			modal: true,
			items: [{
				xtype: 'form',
				frame: true,
				cls: 'k-configure-widget',
				labelWidth: 120,
				items: [{
					xtype: 'zarafa.spinnerfield',
					fieldLabel: _('Reload interval'),
					name: 'reloadinterval',
					boxLabel: _('seconds'),
					width: 60,
					minValue: 30, // 30 seconds
					maxValue: 1800, // 30 minutes
					incrementValue: 30, // 30 seconds
					defaultValue: this.get('reloadinterval') || 300,
					listeners: {
						'change': this.onFieldChange,
						scope: this
					},
					plugins: ['zarafa.numberspinner']
				},
					this.createConfigHeight()
				].concat(this.getConfigurationItems()),
				buttons: [{
					text: _('Close'),
					scope: this,
					handler: function () {
						this.win.close();
					}
				}]
			}]
		});

		this.win = new Ext.Window(config);
		this.win.show(this);
	},

	/**
	 * Returns an array with the items that should be added to the configuration window
	 * of the widget. Should be overridden by child classes.
	 * @return {array} An array of configuration objects for {@link Ext.Component components}
	 */
	getConfigurationItems: function()
	{
		return [];
	},

	/**
	 * Event handler which is fired when one of the fields in the Configuration dialog
	 * has been changed. This will update the corresponding option in the settings.
	 * @param {Ext.form.Field} field The field which fired the event
	 * @param {Mixed} newValue The new value which was applied
	 * @param {Mixed} oldValue The old value which was applied
	 * @private
	 */
	onFieldChange: function (field, newValue, oldValue)
	{
		var fieldName = field.getName();
		this.set(fieldName, newValue);

		if (fieldName === 'widgetheight') {
			this.setHeight(newValue);
		}

		if (fieldName === 'reloadinterval') {
			this.startReloadTask();
		}
	}
});
Ext.namespace('Zarafa.widgets.folderwidgets');

/**
 * @class Zarafa.widgets.folderwidgets.AppointmentsWidget
 * @extends Zarafa.widgets.folderwidgets.AbstractFolderWidget
 *
 * Widget that displays the appointments for today, from the default
 * calendar.  It only displays appointments that occur on or after the
 * current time, so outdated information is never shown.
 *
 * Reload time is configurable per instance of the
 * widget (keys: 'reloadinterval', default 5 minutes).  These values are in
 * saved in miliseconds but displayed in seconds. The reload
 * interval is how often the calendar is fully reloaded from the
 * server, to show records that were added to the folder
 * outside of WebApp.
 */
Zarafa.widgets.folderwidgets.AppointmentsWidget = Ext.extend(Zarafa.widgets.folderwidgets.AbstractFolderWidget, {

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

		var store = new Zarafa.calendar.AppointmentStore();

		Ext.applyIf(config, {
			autoScroll: true,
			layout: 'fit',
			folderType: 'calendar',
			store: store,
			items: [{
				xtype: 'zarafa.gridpanel',
				cls: 'k-appointmentwidget',
				store: store,
				hideHeaders: true,
				loadMask: {
					msg: _('Loading appointments...')
				},
				sm: new Zarafa.common.ui.grid.RowSelectionModel({
					singleSelect: true
				}),
				viewConfig: {
					deferEmptyText: false,
					emptyText: '<div class="emptytext">' + _('No appointments') + '</div>',
					forceFit: true,
					enableRowBody: true,
					rowSelectorDepth: 15,
					getRowClass: this.viewConfigGetRowClass,
					scope: this
				},
				colModel: new Ext.grid.ColumnModel({
					columns: [{
						header: _('Time'),
						dataIndex: 'startdate',
						renderer: this.timeRenderer,
						scope: this
					}]
				}),
				listeners: {
					'rowcontextmenu': this.onRowContextMenu,
					'rowdblclick': this.onRowDblClick,
					scope: this
				}
			}]
		});

		// Customize the configuration of the settings window
		this.configurationConfig = {
			height: 180
		};

		Zarafa.widgets.folderwidgets.AppointmentsWidget.superclass.constructor.call(this, config);
	},

	/**
	 * Adds a field to configure the number of days for which appointments will be shown
	 * @return {array} An array of configuration objects for {@link Ext.Component components}
	 */
	getConfigurationItems: function()
	{
		return [{
			xtype: 'zarafa.spinnerfield',
			fieldLabel: _('Number of days'),
			name: 'numdays',
			boxLabel: _('day(s)'),
			width: 60,
			minValue: 1, // 1 day
			maxValue: 365, // 1 year
			incrementValue: 1, // 1 day
			defaultValue: this.get('numdays') || 5,
			listeners: {
				'change': this.onNumDaysChange,
				scope: this
			},
			plugins: ['zarafa.numberspinner']
		}];
	},

	/**
	 * Event handler which is fired when 'Number of Days' field in the Configuration dialog
	 * has been changed. This will update the corresponding option in the settings.
	 * @param {Ext.form.Field} field The field which fired the event
	 * @param {Mixed} newValue The new value which was applied
	 * @param {Mixed} oldValue The old value which was applied
	 * @private
	 */
	onNumDaysChange: function (field, newValue, oldValue)
	{
		this.set(field.getName(), newValue);
		this.reloadStore();
	},

	/**
	 * Initialize the event handlers for the {@link #store} and {@link Zarafa.hierarchy.data.HierarchyStore Hierarchy}.
	 * @protected
	 */
	initEvents: function ()
	{
		Zarafa.widgets.folderwidgets.AppointmentsWidget.superclass.initEvents.apply(this, arguments);

		// Wait for the store to be loaded, so we can activate
		// the filter task.
		this.mon(this.store, 'load', this.startFilterTask, this, {single: true});
	},

	/**
	* Starts a filter task for the store. Will make sure that the filter is updated at
	* every 30 seconds so old appointments will be filtered out.
	* @private
	*/
	startFilterTask: function ()
	{
		Ext.TaskMgr.start({
			run: this.updateFilter,
			interval: 30000,
			scope: this
		});
	},

	/**
	 * This will {@link Ext.data.Store#load load} the {@link #store} using
	 * a restriction which only allows todays appointments.
	 * @private
	 */
	reloadStore: function ()
	{
		if (!this.folder) {
			return;
		}

		var numDays = this.get('numdays') || 5;

		var startdate = new Date().clearTime().getTime() / 1000;
		var duedate = new Date().clearTime().add(Date.DAY, numDays).getTime() / 1000;

		this.store.load({
			folder: this.folder,
			params: {
				restriction: {
					startdate: startdate,
					duedate: duedate
				}
			}
		});
	},

	/**
	 * Update the filter with the current time. Items that end
	 * before now are removed.
	 * @private
	 */
	updateFilter: function ()
	{
		var now = new Date().getTime() / 1000;
		this.store.filterBy(function (record) {
			var dueDate = record.get('duedate').getTime() / 1000;
			return !dueDate || dueDate >= now;
		}, this);
	},

	/**
	 * Renderer for the time column. Adds a recurrence icon and a private icon if applicable
	 *
	 * @param {Mixed} value The subject of the appointment
	 * @param {Object} metaData Used to set style information to gray out appointments that occur now
	 * @param {Ext.data.Record} record The record being displayed, used to retrieve the start and end times
	 * @private
	 */
	timeRenderer: function (value, metaData, record)
	{
		var recurringIcon = '';
		var recurringPattern = record.get('recurring_pattern');
		if (recurringPattern) {
			if (record.get('exception') === true) {
				recurringIcon =
					'&nbsp;<span ext:qwidth="300" ext:qtip="' + recurringPattern + '">' +
						'<img src="' + Zarafa.calendar.ui.IconCache.getExceptionIcon().src + '"/>' +
					'</span>';
			} else {
				recurringIcon =
					'&nbsp;<span ext:qwidth="300" ext:qtip="' + recurringPattern + '">' +
						'<img src="' + Zarafa.calendar.ui.IconCache.getRecurringIcon().src + '"/>' +
					'</span>';
			}
		}

		var privateIcon = '';
		if (record.get('private') === true) {
			privateIcon = '&nbsp;<img src="' + Zarafa.calendar.ui.IconCache.getPrivateIcon().src + '"/>';
		}

		var dayStart = new Date().clearTime();
		var dayEnd = new Date().add(Date.DAY, 1).clearTime();
		var start = value;
		var end = record.get('duedate');
		var allDayEvent = record.get('alldayevent');

		if ( start >= dayStart && end <= dayEnd ) {
			if ( !allDayEvent ) {
				return String.format(_('Today {0} - {1}'), start.format(_('G:i')), end.format(_('G:i'))) + recurringIcon + privateIcon;
			}

			return _('Today (all day)') + recurringIcon + privateIcon;
		}

		if ( !allDayEvent ) {
			return String.format(_('{0} - {1}'), start.format(_('d/m/y G:i')), end.format(_('d/m/y G:i'))) + recurringIcon + privateIcon;
		}

		return String.format(_('{0} - {1} (all day)'), start.format(_('d/m/y')), end.format(_('d/m/y'))) + recurringIcon + privateIcon;
	},

	/**
	 * Event handler which is triggered when user opens context menu
	 * @param {Ext.grid.GridPanel} grid grid panel object
	 * @param {Number} rowIndex index of row
	 * @param {Ext.EventObject} event event object of the event
	 * @private
	 */
	onRowContextMenu: function (grid, rowIndex, event)
	{
		// check row is already selected or not, if its not selected then select it first
		var selectionModel = grid.getSelectionModel();
		if (!selectionModel.isSelected(rowIndex)) {
			selectionModel.selectRow(rowIndex);
		}

		// The ContextMenu needs the ContextModel for cases where we want to reply the mail.
		var model;
		if (this.folder) {
			var context = container.getContextByFolder(this.folder);
			if (context) {
				model = context.getModel();
				Zarafa.core.data.UIFactory.openDefaultContextMenu(selectionModel.getSelections(), {
					position: event.getXY(),
					model: model
				});
			}
		}
	},

	/**
	 * Called when the user double-clicks on an appointment.
	 * @param {Ext.grid.GridPanel} grid The grid which fired the event
	 * @param {Number} rowIndex The row which was double clicked
	 * @param {Ext.EventObject} event The event object
	 * @private
	 */
	onRowDblClick: function (grid, rowIndex, event)
	{
		var record = grid.getSelectionModel().getSelected();
		if (!Ext.isEmpty(record)) {
			// FIXME what about recurring series records ?
			if (record.isRecurringOccurence()) {
				record = record.convertToOccurenceRecord();
			}
		}
		Zarafa.core.data.UIFactory.openViewRecord(record);
	}
});

Zarafa.onReady(function () {
	container.registerWidget(new Zarafa.core.ui.widget.WidgetMetaData({
		name : 'appointments',
		displayName : _('Upcoming Appointments'),
		widgetConstructor : Zarafa.widgets.folderwidgets.AppointmentsWidget
	}));
});
Ext.namespace('Zarafa.widgets.folderwidgets');

/**
 * @class Zarafa.widgets.folderwidgets.AppointmentsWidget
 * @extends Zarafa.widgets.folderwidgets.AbstractFolderWidget
 *
 * Widget that displays the appointments for today, from the default
 * calendar.  It only displays appointments that occur on or after the
 * current time, so outdated information is never shown.
 *
 * Reload time is configurable per instance of the
 * widget (keys: 'reloadinterval', default 5 minutes).  These values are in
 * saved in miliseconds but displayed in seconds. The reload
 * interval is how often the calendar is fully reloaded from the
 * server, to show records that were added to the folder
 * outside of WebApp.
 */
Zarafa.widgets.folderwidgets.DatepickerWidget = Ext.extend(Zarafa.widgets.folderwidgets.AbstractFolderWidget, {

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

		var store = new Zarafa.calendar.AppointmentStore();

		Ext.applyIf(config, {
			autoScroll: false,
			autoHeight: true,
			layout: 'hbox',
			folderType: 'calendar',
			store: store,
			items: [{
				xtype: 'zarafa.datepicker',
				ref: 'datePicker',
				hideLabel: true,
				showWeekNumber: true,
				showToday: true,
				width: '100%',
				listeners: {
					scope: this
				},
				handler: this.datePickerHandler
			}]
		});


		Zarafa.widgets.folderwidgets.DatepickerWidget.superclass.constructor.call(this, config);

		// FIXME Workaround for KW-1812 (not rendering busy days bold when coming back to current month)
		Ext.TaskMgr.start({
			run: this.updateFilter,
			interval: 2000, // every 2 seconds
			scope: this
		});
	},

	/**
	 * FIXME React on clicks: switch to calendar-view + selected date
	 * Event handler which is triggered when user clicks on any date
	 * @param {DatePicker} DatePicker object
	 * @param {Date} Date that was clicker
	 * @private
	 */
	datePickerHandler: Ext.emptyFn,

	/**
	 * Update the DatePicker when the calender is changed
	 * @private
	 */
	updateFilter: function ()
	{
		if (this.datePicker) {
			this.datePicker.show();
		}

		return Zarafa.widgets.folderwidgets.DatepickerWidget.superclass.updateFilter.apply(this, arguments);
	}
});

Zarafa.onReady(function () {
	container.registerWidget(new Zarafa.core.ui.widget.WidgetMetaData({
		name: 'datepicker',
		displayName: _('Datepicker'),
		widgetConstructor: Zarafa.widgets.folderwidgets.DatepickerWidget
	}));
});
Ext.namespace('Zarafa.widgets.folderwidgets');

/**
 * @class Zarafa.widgets.folderwidgets.MailWidget
 * @extends Zarafa.widgets.folderwidgets.AbstractFolderWidget
 *
 * Widget that shows the unread mail.
 */
Zarafa.widgets.folderwidgets.MailWidget = Ext.extend(Zarafa.widgets.folderwidgets.AbstractFolderWidget, {
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config)
	{
		config = config || {};

		var store = new Zarafa.mail.MailStore();

		// The store already has the default sort info, but we
		// must apply it still. (Bug in the ListModuleStore?).
		store.setDefaultSort(store.defaultSortInfo.field, store.defaultSortInfo.direction);

		// Create a restriction, we only want unread mails, so mails which
		// do not have the MSGFLAG_READ flag on the PR_MESSAGE_FLAGS
		store.setRestriction({
			'search' : Zarafa.core.data.RestrictionFactory.dataResBitmask(
				'0x00E070003', /* PR_MESSAGE_FLAGS */
				Zarafa.core.mapi.Restrictions.BMR_EQZ,
				Zarafa.core.mapi.MessageFlags.MSGFLAG_READ
			)
		});
		// If we want to use a search restriction we must say that this store is an advanceSearchStore
		// or it will be removed.
		store.isAdvanceSearchStore = function(){
			return true;
		};

		Ext.applyIf(config, {
			autoScroll: true,
			layout: 'fit',
			folderType : 'inbox',
			store : store,
			items : [{
				xtype: 'zarafa.gridpanel',
				id: 'unread-mail-widget',
				store: store,
				border: true,
				loadMask : {
					msg : _('Loading mail') + '...'
				},
				sm: new Zarafa.common.ui.grid.RowSelectionModel({
					singleSelect: true
				}),
				viewConfig: {
					deferEmptyText: false,
					emptyText: '<div class="emptytext">' + _('No unread mail.') + '</div>',
					forceFit: true,

					// Enable the row body in which we can render
					// the subject of the mail and some icons
					// for the attachment and importance.
					enableRowBody : true,
					rowSelectorDepth : 15,
					getRowClass : this.viewConfigGetRowClass
				},
				colModel : new Ext.grid.ColumnModel({
					columns: [{
						header: _('From'),
						dataIndex: 'sent_representing_name',
						menuDisabled : true,
						renderer: Ext.util.Format.htmlEncode
					},{
						header: _('Received'),
						dataIndex: 'message_delivery_time',
						editable: false,
						menuDisabled : true,
						renderer : Zarafa.common.ui.grid.Renderers.datetime
					}]
				}),
				listeners: {
					'rowcontextmenu' : this.onRowContextMenu,
					'rowdblclick': this.onRowDblClick,
					scope: this
				}
			}]
		});

		Zarafa.widgets.folderwidgets.MailWidget.superclass.constructor.call(this, config);
	},

	/**
	 * Update the filter. This will filter the records using
	 * {@link Zarafa.core.data.IPMRecord#isRead}.
	 * @private
	 */
        updateFilter : function()
	{
		this.store.filterBy(function(record) {
			return !record.isRead();
		}, this);
	},

	/**
	 * Apply custom style and content for the row body. This will always
	 * apply the Read/Unread style to the entire row. Optionally it will
	 * enable the row body containing the subject and icons for attachment
	 * and priority.
	 *
	 * @param {Ext.data.Record} record The {@link Ext.data.Record Record} corresponding to the current row.
	 * @param {Number} rowIndex The row index
	 * @param {Object} rowParams A config object that is passed to the row template during
	 * rendering that allows customization of various aspects of a grid row.
	 * If enableRowBody is configured true, then the following properties may be set by this function,
	 * and will be used to render a full-width expansion row below each grid row.
	 * @param {Ext.data.Store} store The Ext.data.Store this grid is bound to
	 * @return {String} a CSS class name to add to the row
	 * @private
	 */
	viewConfigGetRowClass : function(record, rowIndex, rowParams, store)
	{
		var cssClass = (record.isRead() ? 'mail_read' : 'mail_unread');

		var meta = {}; // Metadata object for Zarafa.common.ui.grid.Renderers.
		var value = ''; // The value which must be rendered
		rowParams.body = '<table cellspacing="0" cellpadding="0" border="0" style="width: 100%;">';
		rowParams.body += '<tr>';

		// Render the subject
		meta = {};
		value = Zarafa.common.ui.grid.Renderers.subject(record.get('subject'), meta, record);
		rowParams.body += String.format('<td style="width: 100%"><div class="grid_compact grid_compact_left grid_compact_subject_cell {0}" style="height: 24px;">{1}</div></td>', meta.css, value);

		// Render the attachment icon (always aligned to the right)
		meta = {};
		value = Zarafa.common.ui.grid.Renderers.attachment(record.get('hasattach'), meta, record);
		rowParams.body += String.format('<td style="width: 24px"><div class="grid_compact {0}" style="height: 24px; width: 24px;">{1}</div></td>', meta.css, value);

		// Render the importance icon (always aligned to the right)
		meta = {};
		value = Zarafa.common.ui.grid.Renderers.importance(record.get('importance'), meta, record);
		rowParams.body += String.format('<td style="width: 24px"><div class="grid_compact {0}" style="height: 24px; width: 24px;">{1}</div></td>', meta.css, value);

		rowParams.body += '</tr></table>';
		return 'x-grid3-row-expanded ' + cssClass;
	},

	/**
	 * Event handler which is triggered when user opens context menu
	 * @param {Ext.grid.GridPanel} grid grid panel object
	 * @param {Number} rowIndex index of row
	 * @param {Ext.EventObject} eventObj eventObj object of the event
	 * @private
	 */
	onRowContextMenu : function(grid, rowIndex, event)
	{
		// check row is already selected or not, if its not selected then select it first
		var selectionModel = grid.getSelectionModel();
		if (!selectionModel.isSelected(rowIndex)) {
			selectionModel.selectRow(rowIndex);
		}

		// The ContextMenu needs the ContextModel for cases where we want to reply the mail.
		var model;
		if (this.folder) {
			var context = container.getContextByFolder(this.folder);
			if (context) {
				model = context.getModel();
			}
		}

		Zarafa.core.data.UIFactory.openDefaultContextMenu(selectionModel.getSelections(), { position : event.getXY(), model : model });
	},

	/**
	 * Called when the user double-clicks on a mail.
	 * @param {Ext.grid.GridPanel} grid The grid which fired the event
	 * @param {Number} rowIndex The row which was double clicked
	 * @param {Ext.EventObject} event The event object
	 * @private
	 */
	onRowDblClick : function(grid, rowIndex, event)
	{
		Zarafa.core.data.UIFactory.openViewRecord(grid.getSelectionModel().getSelected());
	}
});

Zarafa.onReady(function() {
	container.registerWidget(new Zarafa.core.ui.widget.WidgetMetaData({
		name : 'mail',
		displayName : _('Unread Mail'),
		widgetConstructor : Zarafa.widgets.folderwidgets.MailWidget
	}));
});
Ext.namespace('Zarafa.widgets.folderwidgets');

/**
 * @class Zarafa.widgets.folderwidgets.TasksWidget
 * @extends Zarafa.widgets.folderwidgets.AbstractFolderWidget
 *
 * Widget that shows current, non-completed tasks incl. its duedate, importance,
 * % completed, owner and categories
 */
Zarafa.widgets.folderwidgets.TasksWidget = Ext.extend(Zarafa.widgets.folderwidgets.AbstractFolderWidget, {
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor: function (config)
	{
		config = config || {};

		// FIXME - add something to find mails marked for follow-up as well
		var store = new Zarafa.task.TaskStore();

		// sort by duedate
		store.setDefaultSort('duedate', 'asc');

		// Create a restriction, we only want uncomplete tasks, so tasks which
		// do not have the status flag set to Zarafa.core.mapi.TaskStatus.COMPLETE or
		// Zarafa.core.mapi.FlagStatus.completed
		store.setRestriction({
			'task': Zarafa.core.data.RestrictionFactory.createResAnd([Zarafa.core.data.RestrictionFactory.dataResProperty(
				'status',
				Zarafa.core.mapi.Restrictions.RELOP_NE,
				Zarafa.core.mapi.TaskStatus.COMPLETE
			),Zarafa.core.data.RestrictionFactory.dataResProperty(
				'flag_status',
				Zarafa.core.mapi.Restrictions.RELOP_NE,
				Zarafa.core.mapi.FlagStatus.completed
			)])
		});

		Ext.applyIf(config, {
			autoScroll: true,
			layout: 'fit',
			folderType: 'todolist',
			store: store,
			items: [{
				xtype: 'zarafa.gridpanel',
				cls: 'k-taskwidget',
				store: store,
				loadMask: {
					msg: _('Loading tasks') + '...'
				},
				sm: new Zarafa.common.ui.grid.RowSelectionModel({
					singleSelect: true
				}),
				viewConfig: {
					deferEmptyText: false,
					emptyText: '<div class="emptytext">' + _('No tasks.') + '</div>',
					forceFit: true,
					enableRowBody: true,
					rowSelectorDepth: 15,
					getRowClass: this.viewConfigGetRowClass

				},
				colModel: new Ext.grid.ColumnModel({
					columns: [{
						header: _("Due"),
						tooltip : _('Sort by: Due Date'),
						dataIndex: "duedate",
						renderer: Zarafa.common.ui.grid.Renderers.utcdate
					}, {
						header: "<p class='icon_importance'>&nbsp;</p>",
						tooltip : _('Sort by: Priority'),
						dataIndex: "importance",
						width: 24,
						fixed: true,
						renderer: Zarafa.common.ui.grid.Renderers.importance
					}, {
						header: "%",
						tooltip : _('Sort by: Percentage Completed'),
						dataIndex: "percent_complete",
						width : 75,
						renderer: Zarafa.common.ui.grid.Renderers.percentage
					}, {
						header: _('Owner'),
						tooltip : _('Sort by: Owner'),
						dataIndex: 'owner',
						renderer: this.ownerRenderer
					}],
					defaults: {
						sortable: true,
						menuDisabled: true
					}
				}),
				listeners: {
					'rowcontextmenu': this.onRowContextMenu,
					'rowdblclick': this.onRowDblClick,
					scope: this
				}
			}]
		});

		Zarafa.widgets.folderwidgets.TasksWidget.superclass.constructor.call(this, config);
	},

	/**
	 * Update the filter to make sure only non-completed tasks are shown
	 * @private
	 */
	updateFilter: function ()
	{
		this.store.filterBy(function (record) {
			return (record.get('status') != Zarafa.core.mapi.TaskStatus.COMPLETE);
		}, this);
	},

	/**
	 * Renders the owner of the task as its initials and adds its full
	 * form as a tooltip
	 *
	 * @param {Mixed} value The subject of the appointment
	 * @param {Object} metaData Used to set style information to gray out appointments that occur now
	 * @param {Ext.data.Record} record The record being displayed, used to retrieve the start and end times
	 * @private
	 */
	ownerRenderer: function (value, metaData, record)
	{
		var owner = record.get("owner");
		if (!Ext.isString(owner)) {
			return '';
		}

		var ownerNames = owner.split(" "); // array of all parts of the owner's name
		var initials = '';

		for (var i = 0, len = ownerNames.length; i < len; i++) {
			initials += ownerNames[i].substring(0, 1);
		}

		return '<span ext:qtip="' + Ext.util.Format.htmlEncode(owner) + '" ext:qwidth="100%">' + Ext.util.Format.htmlEncode(initials) + '</span>';
	},

	/**
	 * Event handler which is triggered when user opens context menu
	 * @param {Ext.grid.GridPanel} grid grid panel object
	 * @param {Number} rowIndex index of row
	 * @param {Ext.EventObject} event event object of the event
	 * @private
	 */
	onRowContextMenu: function (grid, rowIndex, event)
	{
		// check row is already selected or not, if its not selected then select it first
		var selectionModel = grid.getSelectionModel();
		if (!selectionModel.isSelected(rowIndex)) {
			selectionModel.selectRow(rowIndex);
		}

		// The ContextMenu needs the ContextModel for cases where we want to reply the mail.
		var model;
		if (this.folder) {
			var context = container.getContextByFolder(this.folder);
			if (context) {
				model = context.getModel();
				Zarafa.core.data.UIFactory.openDefaultContextMenu(selectionModel.getSelections(), {
					position: event.getXY(),
					model: model
				});
			}
		}
	},

	/**
	 * Called when the user double-clicks on a task.
	 * @param {Ext.grid.GridPanel} grid The grid which fired the event
	 * @param {Number} rowIndex The row which was double clicked
	 * @param {Ext.EventObject} event The event object
	 * @private
	 */
	onRowDblClick: function (grid, rowIndex, event)
	{
		Zarafa.core.data.UIFactory.openViewRecord(grid.getSelectionModel().getSelected());
	}
});

Zarafa.onReady(function () {
	container.registerWidget(new Zarafa.core.ui.widget.WidgetMetaData({
		name : 'tasks',
		displayName : _('Tasks / To-Do'),
		widgetConstructor : Zarafa.widgets.folderwidgets.TasksWidget
	}));
});
