//Create a namespace if it does not yet exist
Ext.namespace('Zarafa.plugins.spellchecker');

/**
 * @class Zarafa.plugins.spellchecker.SpellcheckerPlugin
 * @extends Zarafa.core.Plugin
 * 
 * A plugin that gives to user the ability to set reminders for e-mail messages.
 */
Zarafa.plugins.spellchecker.SpellcheckerPlugin = Ext.extend(Zarafa.core.Plugin, {

	/**
	 * Initialise the plugin.
	 * @protected
	 */
	initPlugin : function()
	{
		//Call the parent method
		Zarafa.plugins.spellchecker.SpellcheckerPlugin.superclass.initPlugin.apply(this, arguments);

		//Register the language settings widget
		this.registerInsertionPoint('context.settings.category.mail.aftercomposesettings', this.createSettingsWidget, this);

		//Register the provided languages
		this.registerInsertionPoint('common.htmleditor.tinymceconfig', this.createTinyMCEConfig, this);
	},

	/**
	 * Returns an object with the languages that this plugin supports
	 * @return {Object}
	 * @private
	 */
	getSupportedLanguages : function()
	{
		// The plugin needs language pack plugins for any language to work
		// It does not have language support itself
		var supportedLanguages = {};
		
		container.populateInsertionPoint('plugins.spellchecker.supportedlanguages', {scope: this, languages: supportedLanguages});
		
		return supportedLanguages;
	},
	
	/**
	 * Returns the language code for the language that should be used as the default language
	 * @return {String}
	 * @private
	 */
	getDefaultLanguage : function()
	{
		var spellcheckerDefaultLanguage = container.getSettingsModel().get('zarafa/v1/plugins/spellchecker/spellchecker_language');
		var spellcheckerLanguagesSetByUser = this.getUserSelectedLanguages(true);

		if ( !Ext.isEmpty(spellcheckerDefaultLanguage) && spellcheckerLanguagesSetByUser.indexOf(spellcheckerDefaultLanguage) >= 0 ){
			return spellcheckerDefaultLanguage;
		}
		
		// If no default language is selected then do some intelligent stuff to choose a default one
		var language = container.getSettingsModel().get('zarafa/v1/main/language');
		switch ( language.substr(0,2) ){
			case 'de':
				spellcheckerDefaultLanguage = 'de_DE';
				break;
			case 'fr':
				spellcheckerDefaultLanguage = 'fr_FR';
				break;
			case 'it':
				spellcheckerDefaultLanguage = 'it_IT';
				break;
			case 'es':
				spellcheckerDefaultLanguage = 'es_ES';
				break;
			case 'nl':
				spellcheckerDefaultLanguage = 'nl_NL';
				break;
			case 'pt':
				spellcheckerDefaultLanguage = 'pt_PT';
				break;
			case 'ru':
				spellcheckerDefaultLanguage = 'ru_RU';
				break;
			default:
				spellcheckerDefaultLanguage = 'en_US';
		}
		
		if ( spellcheckerLanguagesSetByUser.indexOf(spellcheckerDefaultLanguage) < 0 ){
			// Set the first language as default language
			spellcheckerDefaultLanguage = spellcheckerLanguagesSetByUser.length>0 ? spellcheckerLanguagesSetByUser[0] : '';
		}
		
		container.getSettingsModel().set('zarafa/v1/plugins/spellchecker/spellchecker_language', spellcheckerDefaultLanguage);
		
		return spellcheckerDefaultLanguage;
	},
	
	/**
	 * Returns the languages that the user has selected in the settings for use with the spellchecker
	 * @param {Boolean} languageCodesOnly Set to true if the returned array should only contain the language codes
	 * @private
	 */
	getUserSelectedLanguages : function(languageCodesOnly)
	{
		// Get the languages that are supported by this plugin (and possible language pack plugins) 
		var languageMap = this.getSupportedLanguages();
		
		// Get the languages that the user wants to see in the dropdown and create a string we can pass to tinyMCE in the config
		var spellCheckerLanguagesSetByUser = container.getSettingsModel().get('zarafa/v1/plugins/spellchecker/spellchecker_languages').split(', ');
		
		var spellCheckerLanguages = [];
		Ext.each(spellCheckerLanguagesSetByUser, function(languageKey){
			if ( languageMap.hasOwnProperty(languageKey) ){
				if ( languageCodesOnly ){
					spellCheckerLanguages.push(languageKey);
				}else{
					spellCheckerLanguages.push(languageMap[languageKey] + '=' + languageKey);
				}
			}
		});
		// Sort the array alphabetically (note that translation can change the order)
		spellCheckerLanguages.sort();
		
		return spellCheckerLanguages;
	},
	
	/**
	 * Changes the configuration object for tinyMCE
	 * @param {String} insertionPoint The insertionpoint that the function is populating
	 * @param {Object} options The options object for this insertionpoint
	 * It contains a property called config that holds the configuration for tinyMCE
	 */
	createTinyMCEConfig : function(insertionPoint, options)
	{
		var userSelectedLanguages = this.getUserSelectedLanguages();
		if ( userSelectedLanguages.length === 0 ){
			// When no languages are selected, we don't initialize the spellchecker
			// This way the browsers internal spellchecker can do the work
			return;
		}
		
		// Add the configuration for the tinymce spellchecker plugin
		options.config.spellchecker_rpc_url = 'spellchecker.php';
		options.config.spellchecker_language = this.getDefaultLanguage();
		options.config.spellchecker_languages = userSelectedLanguages.join(', ');
		options.config.browser_spellcheck = false;
		if ( !Ext.isDefined(options.config.external_plugins) ){
			options.config.external_plugins = {};
		}
		// The path is relative from the tinymce folder!
		options.config.external_plugins.spellchecker = '../../plugins/spellchecker/tinymce-plugin/spellchecker/plugin.min.js';
		options.config.toolbar1 = options.config.toolbar1 + ' | spellchecker';
	},
	
	/**
	 * Creates a configuration object for the settings widget used to let the user select the languages he wants
	 * to see in the spellchecker dropdown
	 * @return {Object} Configuration object
	 */
	createSettingsWidget : function()
	{
		return {
			xtype : 'zarafa.settingshtmleditorwidget'
		};
	}
});


//Wait for the DOM and Kopano to be ready and register the plugin
Zarafa.onReady(function() {
	
	//Register the plugin
	container.registerPlugin(new Zarafa.core.PluginMetaData({
		name : 'spellchecker',
		displayName : _('Spellchecker'),
		pluginConstructor : Zarafa.plugins.spellchecker.SpellcheckerPlugin
	}));
});

Ext.namespace('Zarafa.plugins.spellchecker.settings');

/**
 * @class Zarafa.plugins.spellchecker.settings.SettingsHtmlEditorWidget
 * @extends Zarafa.settings.ui.SettingsWidget
 * @xtype zarafa.settingshtmleditorwidget
 *
 * The {@link Zarafa.settings.ui.SettingsWidget widget} for configuring
 * the html editor.
 */
Zarafa.plugins.spellchecker.settings.SettingsHtmlEditorWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, {
	
	/**
	 * The name that is used in the settings for the selected languages
	 * @property
	 * @private
	 */
	settingsLanguagesName : 'zarafa/v1/plugins/spellchecker/spellchecker_languages',
	
	/**
	 * The name that is used in the settings for the selected languages
	 * @property
	 * @private
	 */
	settingsDefaultLanguageName : 'zarafa/v1/plugins/spellchecker/spellchecker_language',
	
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config)
	{
		config = config || {};

		var spellcheckerPlugin = container.getPluginByName('spellchecker');
		var supportedLanguages = spellcheckerPlugin.getSupportedLanguages();
		
		Ext.applyIf(config, {
			title : _('HTML editor settings'),
			layout : 'form',
			items : []
		});

		if ( Object.keys(supportedLanguages).length > 0 ){
			var selectedLanguages = spellcheckerPlugin.getUserSelectedLanguages();
			var defaultLanguage = spellcheckerPlugin.getDefaultLanguage();
			var data = [];
			Ext.each(selectedLanguages, function(language){
				language = language.split('=');
				data.push([language[1], language[0]]);
			});
			var store = new Ext.data.ArrayStore({
				fields: ['code', 'display'],
				data: data
			});
			
			config.items = [
				{
					xtype : 'displayfield',
					hideLabel : true,
					value : _('Enable the following languages for the spell checker') +':<br><span style="opacity:0.5;">(' + _('Note: When no language is selected the browsers spell checking features will be enabled if available') +')</span>'
				},{
					xtype : 'checkboxgroup',
					name : this.settingsLanguagesName,
					ref : 'spellCheckerLanguagesGroup',
					columns : 1,
					hideLabel : true,
					items: this.createSpellCheckerLanguageOptions(),
					listeners : {
						change : this.onSpellCheckerLanguagesChange,
						scope : this
					}
				},{
					xtype : 'combo',
					name : this.settingsDefaultLanguageName,
					ref : 'spellCheckerDefaultLanguageCombo',
					fieldLabel : _('Default selected language'),
					store : store,
					displayField : 'display',
					valueField : 'code',
					editable : false,
					mode : 'local',
					triggerAction : 'all',
					allowBlank : true,
					autoSelect : true,
					typeAhead : false,
					value : defaultLanguage,
					disabled : selectedLanguages.length === 0 ? true : false,
					validateOnBlur : false,
					invalidClass : '',
					listeners : {
						change : this.onSpellCheckerLanguageChange,
						scope : this
					}
				}
			];
		}else{
			config.items = [{
				xtype : 'displayfield',
				hideLabel : true,
				value : _('No language pack found. Ask your administrator to install language pack plugins to use the spellchecker in the HTML editor.')
			}];
		}

		Zarafa.plugins.spellchecker.settings.SettingsHtmlEditorWidget.superclass.constructor.call(this, config);
	},
	
	/**
	 * Creates the configuration objects for the HTML editor spellchecker language picker
	 * @return {Ext.form.Checkbox|Array} Array with configuration object for the checkboxes in the
	 * spellchecker language picker
	 */
	createSpellCheckerLanguageOptions : function()
	{
		var spellcheckerPlugin = container.getPluginByName('spellchecker');
		var supportedLanguages = spellcheckerPlugin.getSupportedLanguages();
		var selectedLanguages = spellcheckerPlugin.getUserSelectedLanguages(true);
		
		var items = [];
		
		Ext.iterate(supportedLanguages, function(languageKey, languageDisplayName){
			items.push({
				xtype : 'checkbox',
				name : 'spellCheckerLanguages',
				inputValue : languageKey,
				boxLabel : languageDisplayName,
				checked : selectedLanguages.indexOf(languageKey)>=0 ? true : false
			});
		});

		//Sort the array alphabetically (note that translation can change the order)
		items.sort(function(a, b){
			return a.boxLabel < b.boxLabel ? -1 : 1;
		});
		
		return items;
	},
	
	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategory Category} when
	 * it has been called with {@link zarafa.settings.ui.SettingsCategory#update}.
	 * This is used to load the latest version of the settings from the
	 * {@link Zarafa.settings.SettingsModel} into the UI of this category.
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to load
	 */
	update : function(settingsModel)
	{
		if ( !Ext.isDefined(this.spellCheckerLanguagesGroup) ){
			// No language packs were found, so there is nothing to do for us
			return;
		}
		
		this.model = settingsModel;
		
		var spellCheckerLanguagesValue = settingsModel.get(this.settingsName);
		if ( !Ext.isDefined(spellCheckerLanguagesValue) ){
			spellCheckerLanguagesValue = '';
		}
		spellCheckerLanguagesValue = spellCheckerLanguagesValue.split(', ');
		Ext.each(this.spellCheckerLanguagesGroup.items.items, function(checkbox){
			if ( spellCheckerLanguagesValue.indexOf(checkbox.getRawValue())>-1 ){
				checkbox.setValue(true);
			}
		}, this);
	},

	/**
	 * Event handler that handles changes in the spellchecker language settings
	 * @param {Ext.form.CheckboxGroup} checkboxGroup The checkboxgroup that contains the checkboxes
	 * of the spellchecker language picker
	 * @param {Ext.form.Checkbox|Array} checkedCheckboxes The checked checkboxes in the group
	 */
	onSpellCheckerLanguagesChange : function(checkboxGroup, checkedCheckboxes)
	{
		if (this.model) {
			var value = [];
			Ext.each(checkedCheckboxes, function(checkbox){
				value.push(checkbox.getRawValue());
			});
			value.sort();
			value = value.join(', ');

			// FIXME: The settings model should be able to detect if
			// a change was applied
			if (this.model.get(checkboxGroup.name) !== value) {
				this.model.set(checkboxGroup.name, value);
			}
		}
		
		// Change the store of the combobox (the default language picker) to contain the selected languages
		var comboBoxValue = this.spellCheckerDefaultLanguageCombo.getValue();
		var comboBoxValueStillChecked = false;
		var data = [];
		Ext.each(checkedCheckboxes, function(checkbox){
			data.push([checkbox.getRawValue(), checkbox.boxLabel]);
			if ( checkbox.getRawValue() === comboBoxValue ){
				comboBoxValueStillChecked = true;
			}
		});
		this.spellCheckerDefaultLanguageCombo.getStore().loadData(data);
		
		if ( checkedCheckboxes.length === 0 ){
			// When no language is selected, we disable the combobox for the default language
			this.spellCheckerDefaultLanguageCombo.setValue('');
			this.spellCheckerDefaultLanguageCombo.disable();
		}else{
			// We make sure the combobox is enabled 
			this.spellCheckerDefaultLanguageCombo.enable();
			if ( !comboBoxValueStillChecked ){
				// Set the selected value to the first value
				this.spellCheckerDefaultLanguageCombo.setValue(checkedCheckboxes[0].getRawValue());
			}
		}
	},

	/**
	 * Event handler that handles changes in the spellchecker default language settings
	 * @param {Ext.form.ComboBox} combo The combobox that contains the default language
	 * of the spellchecker
	 * @param {String} newValue The selected value of the combobox
	 * @param {String} oldValue The previously selected value of the combobox
	 */
	onSpellCheckerLanguageChange : function(combo, newValue, oldValue)
	{
		if (this.model) {
			// FIXME: The settings model should be able to detect if
			// a change was applied
			if (this.model.get(combo.name) !== newValue) {
				this.model.set(combo.name, newValue);
			}
		}
	}
});

Ext.reg('zarafa.settingshtmleditorwidget', Zarafa.plugins.spellchecker.settings.SettingsHtmlEditorWidget);
