Ext.namespace('Zarafa.mail');

/**
 * @class Zarafa.mail.MailContext
 * @extends Zarafa.core.Context
 */
Zarafa.mail.MailContext = Ext.extend(Zarafa.core.Context, {
	// Insertion points for this class
	/**
	 * @insert main.maintoolbar.view.mail
	 * Insertion point for populating the main toolbar with a View button. This item is only visible
	 * when this context is active.
	 * @param {Zarafa.mail.MailContext} context This context
	 */

	/**
	 * When searching, this property marks the {@link Zarafa.core.Context#getCurrentView view}
	 * which was used before {@link #onSearchStart searching started} the view was switched to
	 * {@link Zarafa.mail.data.Views#SEARCH}.
	 * @property
	 * @type Mixed
	 * @private
	 */
	oldView : undefined,

	/**
	 * When searching, this property marks the {@link Zarafa.core.Context#getCurrentViewMode viewmode}
	 * which was used before {@link #onSearchStart searching started} the viewmode was switched to
	 * {@link Zarafa.mail.data.ViewModes#SEARCH}.
	 * @property
	 * @type Mixed
	 * @private
	 */
	oldViewMode : undefined,

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

		Ext.applyIf(config, {
			current_view : Zarafa.mail.data.Views.LIST,
			current_view_mode : Zarafa.mail.data.ViewModes.RIGHT_PREVIEW
		});

		Zarafa.mail.MailContext.superclass.constructor.call(this, config);

		// The "New email" button which is available in all contexts
		this.registerInsertionPoint('main.maintoolbar.new.item', this.createNewMailButton, this);

		// The tab in the top tabbar
		this.registerInsertionPoint('main.maintabbar.left', this.createMainTab, this);

		// Add a tree control showing a list of note folders to the navigation panel.
		// The control will be shown when the user selects the note context from the button panel.
		this.registerInsertionPoint('navigation.center', this.createMailNavigationPanel, this);

		// Register the Mail category for the settings
		this.registerInsertionPoint('context.settings.categories', this.createSettingCategories, this);

		// Register insertion point to insert toolbar buttons on the right side of menu.
		var toolbarButtons = new Zarafa.common.ui.PreviewPanelToolbarButtons({model: this.getModel()});
		this.registerInsertionPoint('previewpanel.toolbar.right', toolbarButtons.getToolbarButtons, toolbarButtons);

		// Extend the Contact and AddressBook context with email buttons
		this.registerInsertionPoint('context.addressbook.contextmenu.actions', this.createSendEmailContextItem, this);
		this.registerInsertionPoint('context.contact.contextmenu.actions', this.createSendEmailContextItem, this);
		this.registerInsertionPoint('context.contact.contactcontentpanel.toolbar.actions', this.createSendEmailButton, this);
		this.registerInsertionPoint('context.contact.distlistcontentpanel.toolbar.actions', this.createSendEmailButton, this);

		// Register mail specific dialog types
		Zarafa.core.data.SharedComponentType.addProperty('mail.dialog.options');
        Zarafa.core.data.SharedComponentType.addProperty('mail.dialog.delayeddelivery');
	},

	/**
	 * @return {Zarafa.mail.MailContextModel} the mail context model
	 */
	getModel : function()
	{
		if (!Ext.isDefined(this.model)) {
			this.model = new Zarafa.mail.MailContextModel();
			this.model.on({
				'searchstart' : this.onModelSearchStart,
				'searchstop' : this.onModelSearchStop,
				'livescrollstart' : this.onModelLiveScrollStart,
				'livescrollstop' : this.onModelLiveScrollStop,
				scope : this
			});
		}
		return this.model;
	},

	/**
	 * Event handler for the {@link #model}#{@link Zarafa.core.ContextModel#livescrollstart live scroll start} event.
	 * This will {@link #switchView switch the view} to {@link Zarafa.mail.data.Views#LIVESCROLL live scroll mode}.
	 * The previously active {@link #getCurrentView view} will be stored in the {@link #oldView} and will
	 * be recovered when the {@link #onModelLiveScrollStop live scroll is stopped}.
	 * @param {Zarafa.core.ContextModel} model The model which fired the event
	 * @private
	 */
	onModelLiveScrollStart : function(model)
	{
		if(this.getCurrentView() !== Zarafa.mail.data.Views.LIVESCROLL && this.getCurrentViewMode() !== Zarafa.mail.data.ViewModes.LIVESCROLL){
			/*
			 * Check that current view model is NO_PREVIEW, RIGHT_PREVIEW,
			 * or BOTTOM_PREVIEW then set the view mode to oldViewMode and view to oldView.
			 */
			if(Zarafa.mail.data.ViewModes.isMainViewMode(this.getCurrentViewMode())) {
				this.oldView = this.getCurrentView();
				this.oldViewMode = this.getCurrentViewMode();
			}
			this.switchView(Zarafa.mail.data.Views.LIVESCROLL, Zarafa.mail.data.ViewModes.LIVESCROLL);
		}
	},

	/**
	 * Event handler for the {@link #model}#{@link Zarafa.core.ContextModel#livescrollstop live scroll stop} event.
	 * This will {@link #switchView switch the view} to the {@link #oldView previous view}.
	 * @param {Zarafa.core.ContextModel} model The model which fired the event
	 * @private
	 */
	onModelLiveScrollStop : function(model)
	{
		/*
		 * Check requires to prevent loading old view again when user
		 * - Loads all mails in grid using live scroll
		 * - Switch the view
		 * - Click on refresh button
		 * To overcome the above mentioned problem,
		 * we have to check that currently selected mode is one of the main view mode
		 * (NO_PREVIEW, RIGHT_PREVIEW and BOTTOM_PREVIEW) then switch the view with it
		 * else switch with old view and view mode.
		 */
		if(Zarafa.mail.data.ViewModes.isMainViewMode(this.getCurrentViewMode())) {
			this.switchView(this.getCurrentView(), this.getCurrentViewMode());
		} else {
			this.switchView(this.oldView, this.oldViewMode);
		}
		delete this.oldView;
		delete this.oldViewMode;
	},

	/**
	 * Event handler for the {@link #model}#{@link Zarafa.core.ContextModel#searchstart searchstart} event.
	 * This will {@link #switchView switch the view} to {@link Zarafa.mail.data.Views#SEARCH search mode}.
	 * The previously active {@link #getCurrentView view} will be stored in the {@link #oldView} and will
	 * be recovered when the {@link #onModelSearchStop search is stopped}.
	 * @param {Zarafa.core.ContextModel} model The model which fired the event
	 * @private
	 */
	onModelSearchStart : function(model)
	{
		if(this.getCurrentView() !== Zarafa.mail.data.Views.SEARCH && this.getCurrentViewMode() !== Zarafa.mail.data.ViewModes.SEARCH){
			/*
			 * Check that current view model is one of the view mode from
			 * NO_PREVIEW, RIGHT_PREVIEW and BOTTOM_PREVIEW then set the view mode to
			 * oldViewMode and view to oldView.
			 */
			if(Zarafa.mail.data.ViewModes.isMainViewMode(this.getCurrentViewMode())) {
				this.oldView = this.getCurrentView();
				this.oldViewMode = this.getCurrentViewMode();
			}
			this.switchView(Zarafa.mail.data.Views.SEARCH, Zarafa.mail.data.ViewModes.SEARCH);
		}
	},

	/**
	 * Event handler for the {@link #model}#{@link Zarafa.core.ContextModel#searchstop searchstop} event.
	 * This will {@link #switchView switch the view} to the {@link #oldView previous view}.
	 * @param {Zarafa.core.ContextModel} model The model which fired the event
	 * @private
	 */
	onModelSearchStop : function(model)
	{
		this.switchView(this.oldView, this.oldViewMode);
		delete this.oldView;
		delete this.oldViewMode;
	},

	/**
	 * Bid for the given {@link Zarafa.hierarchy.data.MAPIFolderRecord folder}
	 * This will bid on any folder of container class 'IPF.Note'.
	 *
	 * @param {Zarafa.hierarchy.data.MAPIFolderRecord} folder The folder for which the context is bidding
	 * @return {Number} 1 when the contexts supports the folder, -1 otherwise
	 */
	bid : function(folder)
	{
		// The folder contains items of type IPF.Note
		if (folder.isContainerClass('IPF.Note', true)) {
			return 1;
		} else if (folder.isContainerClass('IPF', true)) {
			// Fallback for unknown folders...
			return 0;
		}

		// return -1, don't know this content type
		return -1;
	},

	/**
	 * Bid for the type of shared component and the given record.
	 * This will bid on a common.create or common.view for a
	 * record with a message class set to IPM or IPM.Note.
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Number} The bid for the shared component
	 */
	bidSharedComponent: function(type, record)
	{
		var bid = -1;

		if (Array.isArray(record)) {
			record = record[0];
		}

		switch (type) {
			case Zarafa.core.data.SharedComponentType['common.create']:
			case Zarafa.core.data.SharedComponentType['common.view']:
			case Zarafa.core.data.SharedComponentType['common.preview']:
				if (record instanceof Zarafa.core.data.IPMRecord) {
					if (record.get('object_type') === Zarafa.core.mapi.ObjectType.MAPI_MESSAGE) {
						if (record.isMessageClass([ 'IPM.Note', 'IPM.Schedule.Meeting', 'REPORT.IPM','REPORT.IPM.Note' ], true)) {
							bid = 1;
						} else {
							bid = 0;
						}
					}
				}
				break;
			// Bid for mail specific dialog
			case Zarafa.core.data.SharedComponentType['mail.dialog.options']:
            case Zarafa.core.data.SharedComponentType['mail.dialog.delayeddelivery']:
				bid = 1;
				break;
			case Zarafa.core.data.SharedComponentType['common.contextmenu']:
				if (record instanceof Zarafa.core.data.IPMRecord) {
					if (record.get('object_type') === Zarafa.core.mapi.ObjectType.MAPI_MESSAGE) {
						if (record.isMessageClass([ 'IPM.Note', 'IPM.TaskRequest', 'IPM.Schedule.Meeting', 'REPORT.IPM','REPORT.IPM.Note' ], true)) {
							bid = 1;
						} else {
							bid = 0;
						}
					}
				}
				break;
			case Zarafa.core.data.SharedComponentType['common.printer.renderer']:
				if (record instanceof Zarafa.core.data.IPMRecord) {
					if (record.get('object_type') === Zarafa.core.mapi.ObjectType.MAPI_MESSAGE) {
						// @todo test if report mails print well in default mail renderer
						if (record.isMessageClass([ 'IPM.Note', 'REPORT.IPM','REPORT.IPM.Note' ], true)) {
							bid = 1;
						}
					}
				}
				break;
			case Zarafa.core.data.SharedComponentType['common.attachment.dialog.attachitem.columnmodel']:
				if (record instanceof Zarafa.hierarchy.data.MAPIFolderRecord) {
					if (record.isContainerClass('IPF.Note', true)) {
						bid = 1;
					} else if (record.isContainerClass('IPF', true)) {
						// Lowest bid, so if any context has not bidded for any component then by default this context will bid
						bid = 0;
					}
				}
				break;
			case Zarafa.core.data.SharedComponentType['common.attachment.dialog.attachitem.textrenderer']:
				if (record instanceof Zarafa.core.data.IPMRecord) {
					if (record.isMessageClass([ 'IPM.Note', 'REPORT.IPM', 'REPORT.IPM.Note' ], true)) {
						bid = 1;
					} else if (record.isMessageClass('IPM', true)) {
						// Lowest bid, so if any context has not bidded for any component then by default this context will bid
						bid = 0;
					}
				}
				break;
		}
		return bid;
	},

	/**
	 * Will return the reference to the shared component.
	 * Based on the type of component requested a component is returned.
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Ext.Component} Component
	 */
	getSharedComponent: function(type, record)
	{
		var component;
		switch (type) {
			case Zarafa.core.data.SharedComponentType['common.create']:
				component = Zarafa.mail.dialogs.MailCreateContentPanel;
				break;
			case Zarafa.core.data.SharedComponentType['common.view']:
				component = Zarafa.mail.dialogs.ShowMailContentPanel;
				break;
			case Zarafa.core.data.SharedComponentType['mail.dialog.options']:
				if (!record || record.phantom || record.isUnsent()) {
					component = Zarafa.mail.dialogs.MailCreateOptionsContentPanel;
				} else {
					component = Zarafa.mail.dialogs.MailViewOptionsContentPanel;
				}
				break;
			case Zarafa.core.data.SharedComponentType['common.preview']:
				component = Zarafa.mail.ui.MailViewPanel;
				break;
			case Zarafa.core.data.SharedComponentType['common.contextmenu']:
				component = Zarafa.mail.ui.MailGridContextMenu;
				break;
			case Zarafa.core.data.SharedComponentType['common.printer.renderer']:
				if (record instanceof Zarafa.core.data.IPMRecord) {
					component = Zarafa.mail.printer.MailRenderer;
				}
				break;
			case Zarafa.core.data.SharedComponentType['common.attachment.dialog.attachitem.columnmodel']:
				component = Zarafa.mail.attachitem.AttachMailColumnModel;
				break;
			case Zarafa.core.data.SharedComponentType['common.attachment.dialog.attachitem.textrenderer']:
				component = Zarafa.mail.attachitem.AttachMailRenderer;
				break;
            case Zarafa.core.data.SharedComponentType['mail.dialog.delayeddelivery']:
                component = Zarafa.mail.dialogs.DelayedDeliveryContentPanel;
		}
		return component;
	},

	/**
	 * Obtain the {@link Zarafa.mail.ui.MailPanel Mailpanel} object
	 *
	 * @return {Zarafa.mail.ui.MailPanel} The main panel which should
	 * be used within the {@link Zarafa.core.Context context}
	 */
	createContentPanel : function()
	{
		return {
			xtype : 'zarafa.mailpanel',
			id: 'zarafa-mainpanel-contentpanel-mail',
			context: this
		};
	},

	/**
	 * Creates the mail tree that is shown when the user selects the mail context from the
	 * button panel. It shows a tree of available mail folders
	 * @private
	 */
	createMailNavigationPanel : function()
	{
		return {
			xtype : 'zarafa.contextnavigation',
			context : this,
			items : [{
				xtype : 'panel',
				id: 'zarafa-navigationpanel-mail-navigation',
				cls: 'zarafa-context-navigation-block',
				ref: 'mailnavigation',
				layout: 'fit',
				items : [{
					xtype : 'zarafa.hierarchytreepanel',
					id: 'zarafa-navigationpanel-mail-navigation-tree',
					model: this.getModel(),
					IPMFilter: 'IPF.Note',
					hideDeletedFolders : false,
					enableDD : true,
					enableItemDrop : true,
					deferredLoading : true,
					bbarConfig: {
						defaultSelectedSharedFolderType: Zarafa.hierarchy.data.SharedFolderTypes['MAIL'],
						buttonText : _('Open Shared Mails')
					}
				}]
			}]
		};
	},

	/**
	 * Create "New Email" {@link Ext.menu.MenuItem item} for the "New item"
	 * {@link Ext.menu.Menu menu} in the {@link Zarafa.core.ui.MainToolbar MainToolbar}.
	 * This button should be shown in all {@link Zarafa.core.Context contexts} and
	 * is used to create a new Email.
	 *
	 * @return {Object} The menu item for creating a new Email item
	 */
	createNewMailButton: function()
	{
		return {
			xtype: 'menuitem',
			id: 'zarafa-maintoolbar-newitem-mail',
			tooltip : _('Email message')+' (Ctrl + Alt + X)',
			plugins : 'zarafa.menuitemtooltipplugin',
			text: _('Email message'),
			iconCls: 'icon_createEmailMessage',
			newMenuIndex: 1,
			context: 'mail',
			handler: function()
			{
				Zarafa.mail.Actions.openCreateMailContent(this.getModel());
			},
			scope: this
		};
	},

	/**
	 * Handler for the insertion points for extending the Contacts and AddressBook context menus
	 * with buttons to send a mail to the given Contact and Address Book.
	 * @private
	 */
	createSendEmailContextItem : function()
	{
		return {
			text : _('Send E-mail'),
			iconCls : 'icon_send_email_to_recipient',
			scope : this,
			handler : function(item) {
				Zarafa.mail.Actions.openCreateMailContentForContacts(this.getModel(), item.parentMenu.records);
			},
			beforeShow : function(item, records) {
				var visible = false;

				for (var i = 0, len = records.length; i < len; i++) {
					var record = records[i];
					if (this.isSendEmailButtonVisible(record)) {
						visible = true;
						break;
					}
				}
				item.setVisible(visible);
			}
		};
	},

	/**
	 * Handler for the insertion points for extending the Contacts and Distribution Dialogs
	 * with buttons to send a mail to the given Contact or Distribution list.
	 * @private
	 */
	createSendEmailButton : function()
	{
		return {
			xtype : 'button',
			plugins : [ 'zarafa.recordcomponentupdaterplugin' ],
			iconCls : 'icon_send_email_to_recipient',
			overflowText : _('Send E-mail'),
			tooltip : {
				title : _('Send E-mail'),
				text : _('Create a new email message addressed to this recipient.')
			},
			handler : function(btn) {
				Zarafa.mail.Actions.openCreateMailContentForContacts(this.getModel(), btn.record);
			},
			scope : this,
			update : function(record, resetContent) {
				this.record = record;
				if (resetContent) {
					// Smal workaround, update is called from the btn scope,
					// but the handler from the Context scope. So access
					// isSendEmailButtonVisible from the scope.
					if (!this.scope.isSendEmailButtonVisible(record)) {
						this.hide();
					}
				}
			}
		};
	},

	/**
	 * Check if the given record (which represents a Contact or Distribution list
	 * can be mailed (this requires the record not to be a {@link Ext.data.Record#phantom}
	 * and the Contact should {@link Zarafa.contact.ContactRecord#hasEmailAddress have an email address}.
	 * @param {Zarafa.core.data.MAPIRecord} record The record to check
	 * @return {Boolean} True if we can send an email to this contact/distlist
	 * @private
	 */
	isSendEmailButtonVisible : function(record)
	{
		if (record.phantom) {
			return false;
		} else if (record.isMessageClass('IPM.Contact')) {
			if (!record.hasEmailAddress()) {
				return false;
			}
		}

		return true;
	},

	/**
	 * Create the mail {@link Zarafa.settings.ui.SettingsCategory Settings Category}
	 * to the {@link Zarafa.settings.SettingsContext}. This will create new
	 * {@link Zarafa.settings.ui.SettingsCategoryTab tabs} for the
	 * {@link Zarafa.mail.ui.SettingsMailCategory Mail} and the
	 * {@link Zarafa.mail.ui.SettingsOutOfOfficeCategory Out of Office}
	 * in the {@link Zarafa.settings.ui.SettingsCategoryWidgetPanel Widget Panel}.
	 * @param {String} insertionName insertion point name that is currently populated
	 * @param {Zarafa.settings.ui.SettingsMainPanel} settingsMainPanel settings main panel
	 * which is populating this insertion point
	 * @param {Zarafa.settings.SettingsContext} settingsContext settings context
	 * @return {Array} configuration object for the categories to register
	 * @private
	 */
	createSettingCategories: function(insertionName, settingsMainPanel, settingsContext)
	{
		return [{
			xtype : 'zarafa.settingsmailcategory',
			settingsContext : settingsContext
		},{
			xtype : 'zarafa.settingsoutofofficecategory',
			settingsContext : settingsContext
		}];
	},

	/**
	 * Returns the buttons for the dropdown list of the VIEW-button in the main toolbar. It will use the
	 * main.maintoolbar.view.mail insertion point to allow other plugins to add their items at the end.
	 *
	 * @return {Ext.Component[]} an array of components
	 */
	getMainToolbarViewButtons : function()
	{
		var items = container.populateInsertionPoint('main.maintoolbar.view.mail', this) || [];

		var defaultItems = [{
			id: 'zarafa-maintoolbar-view-mail-nopreview',
			overflowText: _('No preview'),
			iconCls: 'icon_previewpanel_off',
			text: _('No preview'),
			valueView : Zarafa.mail.data.Views.LIST,
			valueViewMode : Zarafa.mail.data.ViewModes.NO_PREVIEW,
			valueDataMode : Zarafa.mail.data.DataModes.ALL,
			handler: this.onContextSelectView,
			scope: this
		},{
			id: 'zarafa-maintoolbar-view-mail-previewright',
			overflowText: _('Right preview'),
			iconCls: 'icon_previewpanel_right',
			text: _('Right preview'),
			valueView : Zarafa.mail.data.Views.LIST,
			valueViewMode : Zarafa.mail.data.ViewModes.RIGHT_PREVIEW,
			valueDataMode : Zarafa.mail.data.DataModes.ALL,
			handler: this.onContextSelectView,
			scope: this
		},{
			id: 'zarafa-maintoolbar-view-mail-previewbottom',
			overflowText: _('Bottom preview'),
			iconCls: 'icon_previewpanel_bottom',
			text: _('Bottom preview'),
			valueView : Zarafa.mail.data.Views.LIST,
			valueViewMode : Zarafa.mail.data.ViewModes.BOTTOM_PREVIEW,
			valueDataMode : Zarafa.mail.data.DataModes.ALL,
			handler: this.onContextSelectView,
			scope: this
		}];

		return defaultItems.concat(items);
	},

	/**
	 * Event handler which is fired when one of the View buttons
	 * has been pressed. This will call {@link #setView setView}
	 * to update the view.
	 * @param {Ext.Button} button The button which was pressed
	 * @private
	 */
	onContextSelectView : function(button)
	{
		this.getModel().setDataMode(button.valueDataMode);
		this.switchView(button.valueView, button.valueViewMode);
	},

	/**
	 * Returns the buttons for the dropdown list of the Print button in the main toolbar. It will use the
	 * main.maintoolbar.print.mail insertion point to allow other plugins to add their items at the end.
	 *
	 * @return {Ext.Component[]} an array of components
	 */
	getMainToolbarPrintButtons : function()
	{
		var items = container.populateInsertionPoint('main.toolbar.print.mail', this) || [];

		var defaultItems = [{
			xtype: 'zarafa.conditionalitem',
			id: 'zarafa-maintoolbar-print-singlemail',
			overflowText: _('Print single e-mail'),
			iconCls: 'icon_print_single',
			tooltip : _('Print single e-mail') + ' (Ctrl + P)',
			plugins : 'zarafa.menuitemtooltipplugin',
			text: _('Print single e-mail'),
			hideOnDisabled: false,
			singleSelectOnly: true,
			handler: this.onPrintSingle,
			scope: this
		}];
		return defaultItems.concat(items);
	},

	/**
	 * Event handler which is fired when the 'print single' item in the dropdown has been pressed
	 * This calls {@link Zarafa.common.Actions.openPrintDialog} with the previewed {@link Zarafa.core.data.MAPIRecord} record.
	 * @private
	 */
	onPrintSingle : function()
	{
		var records = this.getModel().getSelectedRecords();
		if (Ext.isEmpty(records)) {
			Ext.MessageBox.alert(_('Print'), _('No message selected'));
		} else {
			Zarafa.common.Actions.openPrintDialog(records);
		}
	},

	/**
	 * Event handler which is fired when the 'print list' item in the dropdown has been pressed
	 * This calls {@link Zarafa.common.Actions.openPrintDialog} with the current context.
	 * @private
	 */
	onPrintList : function()
	{
		Zarafa.common.Actions.openPrintDialog(this);
	},

	/**
	 * Adds a button to the top tab bar for this context.
	 * @return {Object} The button for the top tabbar
	 * @private
	 */
	createMainTab: function()
	{
		return {
			text: this.getDisplayName(),
			tabOrderIndex: 2,
			context: this.getName(),
			id: 'mainmenu-button-mail'
		};
	}
});

Zarafa.onReady(function() {
	container.registerContext(new Zarafa.core.ContextMetaData({
		name : 'mail',
		displayName: _('Mail'),
		allowUserVisible : false,
		pluginConstructor : Zarafa.mail.MailContext
	}));
});