Ext.namespace('Zarafa.core.ui');

/**
 * @class Zarafa.core.ui.PreviewPanel
 * @extends Ext.Panel
 * @xtype zarafa.previewpanel
 *
 * Panel that shows a preview of a {@link Zarafa.core.data.IPMRecord message}.
 */
Zarafa.core.ui.PreviewPanel = Ext.extend(Ext.Panel, {
	// Insertion points for this class
	/**
	 * @insert previewpanel.toolbar.left
	 * Insertions point for inserting buttons in previewpane's toolbar on left side.
	 * @param {Zarafa.core.ui.PreviewPanel} panel This panel
	 * @param {Zarafa.core.ContextModel} model The contextmodel ({@link #model}).
	 */

	/**
	 * @insert previewpanel.toolbar.right
	 * Insertions point for inserting buttons in previewpane's toolbar on right side.
	 * @param {Zarafa.core.ui.PreviewPanel} panel This panel
	 * @param {Zarafa.core.ContextModel} model The contextmodel ({@link #model}).
	 */

	/**
	 * @cfg {Zarafa.core.ContextModel} model The model for which this
	 * PreviewPanel is being loaded.
	 */
	model : undefined,

	/**
	 * Reference to the {@link Zarafa.core.plugins.RecordComponentPlugin RecordComponent} plugin
	 * which is used to send update events to all child {@link Ext.Container containers}
	 * in this container. This field is initialized by the
	 * {@link Zarafa.core.plugins.RecordComponentPlugin RecordComponent} itself.
	 *
	 * @property
	 * @type Zarafa.core.plugins.RecordComponentPlugin
	 */
	recordComponentPlugin : undefined,

	/**
	 * @cfg {Object} Configuration object which will be used
	 * to instantiate the {@link Zarafa.core.plugins.RecordComponentPlugin RecordComponent}.
	 * See the plugin for the available configuration options.
	 */
	recordComponentPluginConfig : undefined,

	/**
	 * @cfg {Zarafa.core.data.IPMRecord} record (See {@link Zarafa.core.plugins.RecordComponentPlugin#record}).
	 */
	record : undefined,

	/**
	 * @cfg {Boolean} isLoadMaskShown true if load mask should be shown else false.
	 */
	isLoadMaskShown : false,

	/**
	 * The LoadMask object which will be shown when the {@link #record} is being opened, and
	 * the dialog is waiting for the server to respond with the desired data. This will only
	 * be set if {@link #showLoadMask} is true.
	 * @property
	 * @type Zarafa.common.ui.LoadMask
	 */
	loadMask : undefined,

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

		config = Ext.applyIf(config, {
			layout : 'fit',
			stateful : true,
			minWidth : 200,
			minHeight : 200,
			xtype : 'zarafa.previewpanel'
		});

		config.tbar = Ext.applyIf(config.tbar || {}, {
			cls: 'zarafa-previewpanel-toolbar',
			xtype : 'zarafa.toolbar',
			hidden : true,
			items : []
		});

		var tbarItems = [
			container.populateInsertionPoint('previewpanel.toolbar.left', this, config.model),
			{xtype: 'tbfill'},
			container.populateInsertionPoint('previewpanel.toolbar.right.first', {scope : this, model : config.model}),
			config.tbar.items, // Default items in toolbar should be right aligned.
			container.populateInsertionPoint('previewpanel.toolbar.right', {scope : this, model : config.model})
		];

		config.tbar.items = Ext.flatten(tbarItems);
		config.plugins = Ext.value(config.plugins, []);
		config.plugins.push(Ext.applyIf(config.recordComponentPluginConfig || {}, {
			ptype: 'zarafa.recordcomponentplugin',
			useShadowStore : true,
			allowWrite : false
		}));

		config.plugins.push({
			ptype: 'zarafa.recordcomponentupdaterplugin'
		}, {
			ptype : 'zarafa.enablefocusplugin'
		});

		if (container.getSettingsModel().get('zarafa/v1/contexts/mail/readflag_time_enable') === true) {
			config.plugins.push({
				ptype: 'zarafa.markasreadplugin'
			});
		}

		Zarafa.core.ui.PreviewPanel.superclass.constructor.call(this, config);

		if (this.model) {
			this.mon(this.model, 'previewrecordchange', this.onPreviewRecordChange, this);
		}

		this.on({
			'beforeloadrecord' : this.onBeforeLoadRecord,
			'loadrecord' : this.onLoadRecord,
			'exceptionrecord' : this.onExceptionRecord,
			'show' : this.onPreviewPanelShow,
			'expand' : this.onPreviewPanelShow,
			'scope' : this
		});
	},

	/**
	 * Called when the ContentPanel has been rendered.
	 * This activate the keymap on the element of this component after the normal operations of
	 * afterRender have been completed. It will activate by getting the xtype hierarchy from
	 * {@link #getXTypes} and format it into a string usable by the
	 * {@link Zarafa.core.KeyMapMgr KeyMapMgr}.
	 * @private
	 */
	afterRender: function()
	{
		Zarafa.core.ui.PreviewPanel.superclass.afterRender.apply(this, arguments);
		var xtypes = this.getXTypes();

		// The first part leading up to zarafa.previewpanel will be stripped
		xtypes = xtypes.replace('component/box/container/panel/zarafa.previewpanel','');

		// Then the "zarafa." will be stripped off from start, the xtype like "zarafa.previewpanel".
		xtypes = xtypes.replace(/\/zarafa\./g,'.');

		// Finally we string the "previewpanel" from all the xtypes. Otherwise each level will have
		// that "previewpanel" mentioned in them. Also we add previewpanel to the start as that sets
		// it apart from other components in the key mapping.
		xtypes = 'previewpanel' + xtypes.replace(/previewpanel/g, '');

		// This will activate keymaps with 'previewpanel.mail' so the component
		// will have all key events register with 'previewpanel', 'mail'
		Zarafa.core.KeyMapMgr.activate(this, xtypes);
	},

	/**
	 * See {@link Zarafa.core.plugins.RecordComponentPlugin#setRecord}.
	 *
	 * @param {Zarafa.core.data.MAPIRecord} record The record to set
	 */
	setRecord : function(record)
	{
		for (var i = 0; i < this.toolbars.length; i++) {
			this.toolbars[i].setVisible(!!record);
		}

		if (this.recordComponentPlugin) {
			this.recordComponentPlugin.setRecord(record);
		}

		// Remove the update handler of the record in the preview panel
		// before we set a new one
		if ( this.record && this.record.store ){
			this.record.store.un('update', this.updatePreviewPanel, this);
		}
		if ( record && record.store ){
			record.store.on('update', this.updatePreviewPanel, this);
		}
	},

	/**
	 * Updates the categories in the preview panel when the data of the record changes.
	 *
	 * @param {Zarafa.core.data.IPMStore} store The store to which the record belongs
	 * that is shown in the preview panel
	 * @param {Zarafa.core.data.IPMRecord} record The Record that was updated
	 */
	updatePreviewPanel : function(store, record)
	{
		// Only update when we are showing a record in the preview panel
		if ( this.record && record.equals(this.record) ){
			this.record.set('categories', record.get('categories'));
			this.doLayout();
		}
	},

	/**
	 * Update the components with the given record.
	 *
	 * @param {Zarafa.core.data.MAPIRecord} record The record to update in this component
	 * @param {Boolean} contentReset force the component to perform a full update of the data.
	 */
	update : function(record, contentReset)
	{
		this.record = record;
	},

	/**
	 * Function for 'previewrecordchange' and 'show' events before setting record into component
	 * @param {Zarafa.core.data.MAPIRecord} record
	 * @private
	 */
	showRecordInPanel : function(record)
	{
		var panelConstructor;

		// Record is already loaded...
		if (this.record === record) {
			return;
		}

		// Check if same record is loaded again
		if (this.record && record && this.record.equals(record)) {
			return;
		}

		if (Ext.isDefined(record)) {
			panelConstructor = container.getSharedComponent(Zarafa.core.data.SharedComponentType['common.preview'], record);
			if (panelConstructor && this.get(0) instanceof panelConstructor) {
				if(this.isLoadMaskShown){
					this.hideLoadMask();
				}
				this.setRecord(record);
				return;
			}
		}

		// Do a complete refresh, clearing all UI components
		// which might be active inside the panel.
		this.removeAll();

		if (panelConstructor) {
			this.add(new panelConstructor());
		}

		this.setRecord(record);
		this.doLayout();
		this.hideLoadMask();
	},

	/**
	 * Removes all components from this container. Additionally this function will also remove all the items from
	 * {@link Ext.Toolbar toolbar} also.
	 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
	 * Defaults to the value of this Container's {@link #autoDestroy} config.
	 * @return {Array} Array of the destroyed components
	 */
	removeAll : function(autoDestroy)
	{
		// remove toolbar items first
		var destroyedItems = [];
		if(this.getTopToolbar()) {
			destroyedItems.concat(this.getTopToolbar().removeAll.apply(this, arguments));
		}

		if(this.getBottomToolbar()) {
			destroyedItems.concat(this.getBottomToolbar().removeAll.apply(this, arguments));
		}

		destroyedItems.concat(Zarafa.core.ui.PreviewPanel.superclass.removeAll.apply(this, arguments));

		return destroyedItems;
	},

	/**
	 * Event handler which is trigggerd when the {@link Zarafa.core.ContextModel ContextModel} receives a new
	 * record for previewing (it fired the {@link Zarafa.core.ContextModel#previewrecordchange previewrecordchange} event).
	 * This updates the {@link Ext.Container previewpanel} with the selected record to be previewed.
	 *
	 * @param {Zarafa.core.ContextModel} model The context model.
	 * @param {Ext.data.Record} record The record which is selected for preview.
	 * @private
	 */
	onPreviewRecordChange : function(contextModel, record)
	{
		// Load record in preview panel
		if(this.isVisible()) {
			this.showRecordInPanel(record);
		}
	},

	/**
	 * If {@link #showLoadMask} is enabled, this function will display
	 * the {@link #loadMask}.
	 * @param {Boolean} errorMask True to show an error mask instead of the loading mask.
	 * @protected
	 */
	showLoadMask : function(errorMask)
	{
		if (this.isLoadMaskShown === true) {
			return;
		}
		if (!this.loadMask) {
			this.loadMask = new Zarafa.common.ui.LoadMask(this.el);
		}

		if (errorMask) {
			this.loadMask.showError();
		} else {
			this.loadMask.show();
			this.isLoadMaskShown = true;
		}
	},

	/**
	 * If {@link #showLoadMask} is enabled, and {@link #showLoadMask} has been
	 * called to display the {@link #loadMask} this function will disable the
	 * loadMask.
	 * @protected
	 */
	hideLoadMask : function()
	{
		if (this.isLoadMaskShown === false) {
			return;
		}

		if (this.loadMask) {
			this.loadMask.hide();
			this.isLoadMaskShown = false;
		}
	},

	/**
	 * Event handler for the {@link Zarafa.core.plugins.RecordComponentPlugin#beforeloadrecord beforeloadrecord} event.
	 * This will call the {@link #showLoadMask} function to show the loadmask.
	 *
	 * @param {Ext.Container} panel The panel to which the record belongs
	 * @param {Zarafa.core.data.IPMRecord} record The record which was updated
	 * @private
	 */
	onBeforeLoadRecord : function(panel, record)
	{
		this.showLoadMask();
	},

	/**
	 * Event handler for the {@link Zarafa.core.plugins.RecordComponentPlugin#loadrecord loadrecord} event.
	 * This will call the {@link #hideLoadMask} function to hide the loadmask.
	 *
	 * @param {Ext.Container} panel The panel to which the record belongs
	 * @param {Zarafa.core.data.IPMRecord} record The record which was updated
	 * @private
	 */
	onLoadRecord : function(panel, record)
	{
		this.hideLoadMask();
	},

	/**
	 * Event handler for the {@link Zarafa.core.plugins.RecordComponentPlugin#exceptionrecord} event.
	 * This will call {@link #showLoadMask} to update it with a new error message.
	 *
	 * @param {String} type See {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#exception exception}
	 * for description.
	 * @param {String} action See {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#exception exception}
	 * for description.
	 * @param {Object} options See {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#exception exception}
	 * for description.
	 * @param {Object} response See {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#exception exception}
	 * for description.
	 * @param {Zarafa.core.data.MAPIRecord} record The record which was subject of the request
	 * that encountered an exception.
	 * @param {String} error (Optional) Passed when a thrown JS Exception or JS Error is
	 */
	onExceptionRecord : function(type, action, options, response, record)
	{
		this.showLoadMask(true);
	},

	/**
	 * Event handler which is fired when this panel has been set to visible. Fetches previewRecord from
	 * the {@link Zarafa.core.ContextModel ContextModel} and displays into panel.
	 */
	onPreviewPanelShow : function()
	{
		if (Ext.isDefined(this.model)) {
			var record = this.model.getPreviewRecord();
			if (Ext.isDefined(record)) {
				this.showRecordInPanel(record);
			}
		}
	},

	/**
	 * Obtain the path in which the {@link #getState state} must be saved.
	 * This option is only used when the {@link Zarafa.core.data.SettingsStateProvider SettingsStateProvider} is
	 * used in the {@link Ext.state.Manager}. This returns {@link #statefulName} if provided, or else generates
	 * a custom name.
	 * @return {String} The unique name for this component by which the {@link #getState state} must be saved.
	 */
	getStateName : function()
	{
		return 'preview/' + Zarafa.core.ui.PreviewPanel.superclass.getStateName.call(this);
	}
});
Ext.reg('zarafa.previewpanel', Zarafa.core.ui.PreviewPanel);
