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

/**
 * @class Zarafa.settings.ui.SettingsCategory
 * @extends Ext.Container
 * @xtype zarafa.settingscategory
 *
 * The main category object which defines the {@link #title name} of the category
 * and all the {@link Zarafa.settings.ui.SettingsWidget widgets} ({@link #items})
 * which should be displayed in the {@link Zarafa.settings.ui.SettingsCategoryWidgetPanel widget panel}.
 *
 * This object should be used for registering new categories through the
 * {@link Zarafa.settings.ui.SettingsMainPanel#context.settings.categories insertion point}.
 */
Zarafa.settings.ui.SettingsCategory = Ext.extend(Ext.Container, {
	/**
	 * @cfg {Array} items The array of configuration
	 * objects for the {@link Zarafa.settings.ui.SettingsWidget Settings Widgets}
	 * which should be shown in the center panel of the
	 * {@link Zarafa.settings.ui.SettingsMainPanel}.
	 */
	items : undefined,

	/**
	 * @cfg {Zarafa.settings.SettingsContext} settingsContext
	 */
	settingsContext : undefined,

	/**
	 * @cfg {String} title The title of the category, this string
	 * will be displayed in the left panel of the
	 * {@link Zarafa.settings.ui.SettingsMainPanel}.
	 */
	title : '',

	/**
	 * @cfg {Number} categoryIndex The index of the category
	 * in the {@link Zarafa.settings.ui.SettingsCategoryPanel category list}
	 */
	categoryIndex : 100,

	/**
	 * The reference as returned by {@link Zarafa.core.ui.notifier.Notifier#notify} to reference the
	 * message in order to remove the message as soon as the save was completed.
	 * @property
	 * @type Ext.Element
	 * @private
	 */
	savingEl : undefined,

	/**
	 * Each widget can have different saving methods (saving settings through the {@link Zarafa.settings.SettingsModel settings}
	 * or perhaps through an alternative {@link Ext.data.Store}. This counter keeps track how many saving methods have been
	 * {@link #displaySavingMask started} and will only {@link #hideSavingMask hide} it when all saving methods have completed.
	 * @property
	 * @type Number
	 * @private
	 */
	savingElCounter : 0,

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

		Ext.applyIf(config, {
			autoScroll: true
		});

		Zarafa.settings.ui.SettingsCategory.superclass.constructor.call(this, config);
	},

	/**
	 * Called by superclass when the Category has been selected and is shown to the user,
	 * this will register the {@link #onBeforeSaveSettings} event handler.
	 * @private
	 */
	onShow : function()
	{
		Zarafa.settings.ui.SettingsCategory.superclass.onShow.apply(this, arguments);

		this.mon(container.getCurrentContext().getModel(), 'beforesavesettings', this.onBeforeSaveSettingsModel, this);
	},

	/**
	 * Called by superclass when the Category has been deselected and is hidden from the user,
	 * this will unregister the {@link #onBeforeSaveSettings} event handler.
	 * @private
	 */
	onHide : function()
	{
		Zarafa.settings.ui.SettingsCategory.superclass.onHide.apply(this, arguments);

		this.mun(container.getCurrentContext().getModel(), 'beforesavesettings', this.onBeforeSaveSettingsModel, this);

		// Unregister the 'beforesave' event. This could be lingering when
		// 'savesettings' was fired but it was cancelled by one of the
		// event handlers.
		this.mun(container.getSettingsModel(), 'beforesave', this.onBeforeSettingsSave, this);
	},

	/**
	 * Event handler for the
	 * {@link Zarafa.settings.SettingsContextModel ContextModel}#{@link Zarafa.settings.SettingsContextModel#beforesavesettings beforesavesettings}
	 * event. It will reset the {@link #savingElCounter} and his will register the event handler for
	 * {@link Zarafa.settings.SettingsModel#beforesave beforesave} event.
	 * @private
	 */
	onBeforeSaveSettingsModel : function()
	{
		// Listen to the settings model to determine when the saving mask can be removed.
		var model = container.getSettingsModel();
		this.mon(model, 'beforesave', this.onBeforeSettingsSave, this, { single : true });

		// We will start saving, however each category can have multiple
		// saving methods (not just settings). So we keep track of those
		// using a counter if this counter reaches 0 we know that all
		// saving methods have completed.
		this.savingElCounter = 0;
	},

	/**
	 * Event handler which is fired when the {@link Zarafa.settings.SettingsModel SettingsModel} fires
	 * the {@link Zarafa.settings.SettingsModel#beforesave beforesave} event.
	 * This will {@link #displaySavingMask Display a notifier} to the user, and will wait until the save was completed.
	 * @param {Zarafa.settings.SettingsModel} model The settings model which fired the event
	 * @private
	 */
	onBeforeSettingsSave : function(model)
	{
		this.displaySavingMask();

		// Unregister the event handler, we will listen for it again when the ContextModel
		// is about to save the settings again.
		this.mun(model, 'beforesave', this.onBeforeSettingsSave, this);

		// We know the settingsmodel is going to be saved, so we can listen for the event.
		this.mon(model, 'save', this.onSettingsSave, this);
		this.mon(model, 'exception', this.onSettingsException, this);
	},

	/**
	 * Event handler which is fired when the {@link Zarafa.settings.SettingsModel SettingsModel}
	 * fires the {@link Zarafa.settings.SettingsModel#save save} event. This will update the
	 * notification messages.
	 * @param {Zarafa.settings.SettingsModel} model The settings model which fired the event
	 * @private
	 */
	onSettingsSave : function(model)
	{
		// Remove event handlers
		this.mun(model, 'save', this.onSettingsSave, this);
		this.mun(model, 'exception', this.onSettingsException, this);

		this.hideSavingMask(true);
	},

	/**
	 * Called when the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#exception exception}
	 * event to indicate the settings were not successfully saved.
	 * @param {Zarafa.settings.SettingsModel} model The settings model which fired the event
	 * @private
	 */
	onSettingsException : function(model)
	{
		// Remove event handlers
		this.mun(model, 'save', this.onSettingsSave, this);
		this.mun(model, 'exception', this.onSettingsException, this);

		this.hideSavingMask(false);
	},

	/**
	 * Show a {@link Zarafa.core.ui.notifier.Notifier Notification} to the user indicating that the
	 * settings are being saved. This will initialize {@link #savingEl}.
	 * This uses the {@link #savingElCounter} counter to determine if this was the first Saving method
	 * to show the notification.
	 * @private
	 */
	displaySavingMask : function()
	{
		// Increase the counter for savingEl, as we have a new saving method
		// which will handle saving.
		this.savingElCounter++;

		// If we don't have the notifier yet, show it now.
		if (!this.savingEl) {
			this.savingEl = container.getNotifier().notify('info.saving', '', _('Saving') + '...', {
				container : container.getContentPanel().getEl(),
				persistent : true
			});
		}
	},

	/**
	 * Hide the {@link Zarafa.core.ui.notifier.Notifier Notification} from {@link #displaySavingMask}
	 * and optionally show a new Notification indicatin that the settings were saved successfully.
	 * This uses the {@link #savingElCounter} counter to determine if this was the last Saving method
	 * in order to update the notifications.
	 * @param {Boolean} success True if a notification should be shown that the settings were saved.
	 * @private
	 */
	hideSavingMask : function(success)
	{
		var contentEl = container.getContentPanel().getEl();

		// Reduce the counter for the savingEl, as one of the used
		// saving methods has completed.
		this.savingElCounter--;

		// If this was the last saving method, we can complete it.
		// If the save was not successful we immediately hide the
		// notification as well, to prevent other saving methods
		// from falsy reporting success.
		if (this.savingElCounter === 0 || !success) {
			if (this.savingEl) {
				container.getNotifier().notify('info.saving', null, null, {
					container : contentEl,
					destroy : true,
					reference : this.savingEl
				});

				delete this.savingEl;

				if (success) {
					container.getNotifier().notify('info.saved', _('Saved'), _('Saved successfully'), {
						container : contentEl
					});
				}
			}
		}
	},

	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategoryWidgetPanel widget panel}
	 * to load the latest version of the settings from the
	 * {@link Zarafa.settings.SettingsModel} into the UI of this category.
	 *
	 * By default this will call {@link Zarafa.settings.ui.SettingsWidget#update} on all
	 * {@link #items}
	 *
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to load
	 */
	update : function(settingsModel)
	{
		var widgets = this.findByType('zarafa.settingswidget');
		for (var i = 0, len = widgets.length; i < len; i++) {
			widgets[i].update.apply(widgets[i], arguments);
		}
	},

	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategoryWidgetPanel widget panel}
	 * to update the settings from the UI into the {@link Zarafa.settings.SettingsModel settings model}.
	 *
	 * By default this will call {@link Zarafa.settings.ui.SettingsWidget#updateSettings} on all
	 * {@link #items}
	 *
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to update
	 */
	updateSettings : function(settingsModel)
	{
		var widgets = this.findByType('zarafa.settingswidget');
		for (var i = 0, len = widgets.length; i < len; i++) {
			widgets[i].updateSettings.apply(widgets[i], arguments);
		}
	}
});

Ext.reg('zarafa.settingscategory', Zarafa.settings.ui.SettingsCategory);