/*
 *  Copyright 2015 Anyware Services
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * This tool displays the glossary.
 * @private
 */
Ext.define('Ametys.plugins.glossary.GlossaryTool', {
	extend: 'Ametys.tool.Tool',

	/**
	 * @private
	 * @property {Ext.grid.Panel} _grid The grid for word definitions
	 */
	
	/**
	 * @private
	 * @property {Ext.data.Store} _store The store for word definitions
	 */
	
	statics: {
	    
	    convertThemes: function(val, record, dataIndex)
	    {
	        var properties = {};
	        record.data[dataIndex + '_map'] = properties;
	        
	        if (Ext.isArray(val) && val.length > 0 && Ext.isObject(val[0]))
	        {
	            for (var i = 0; i < val.length; i++)
	            {
	                properties[val[i].id] = val[i];
	                val[i] = val[i].id;
	            }
	        }
	        else if (Ext.isObject(val))
	        {
	            properties[val.id] = val;
	            val = val.id;
	        }
	        return val;
	    }
	},
	
	constructor: function(config)
	{
		this.callParent(arguments);
		
		Ametys.message.MessageBus.on(Ametys.message.Message.CREATED, this._onMessageCreatedOrModified, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onMessageCreatedOrModified, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onMessageDeleted, this);
	},
	
	createPanel: function()
	{
		this._store = Ext.create('Ext.data.Store', {
			model: 'Ametys.plugins.glossary.GlossaryTool.DefinitionEntry',
			proxy: {
				type: 'ametys',
                role: 'org.ametys.plugins.glossary.GlossaryDAO',
                methodName: 'getDefinitions',
                methodArguments: ['siteName', 'lang'],
				reader: {
					type: 'json',
					rootProperty: 'definitions'
				},
				extraParams: {
					siteName: Ametys.getAppParameter('siteName')
				}
			},
			groupField: 'firstLetter',
			sorters: [{property: 'word', direction: 'ASC'}],
			
			listeners: {
				'beforeload': Ext.bind(this._onBeforeLoad, this)
			}
		});
		
		var langCombo = Ametys.cms.language.LanguageDAO.createComboBox({
			itemId: 'languages-combo',
			fieldLabel: "{{i18n PLUGINS_GLOSSARY_UITOOL_LANGUAGE}}",
			listeners: {
	        	'change': Ext.bind(this._onChangeLang, this)
	        }
		});
		
		this._grid = Ext.create('Ext.grid.Panel', {
			
			stateful: true,
			stateId: this.self.getName() + "$grid",
			
			// Languages combo box
			dockedItems: [{
				dock: 'top',
				xtype: 'toolbar',
				layout: {
			        type: 'hbox',
			        align: 'stretch'
			    },
				
			    border: false,
				defaults : {
					cls: 'ametys',
					labelWidth: 55,
					labelSeparator: ''
				},
				
				items: langCombo
			}],
			
			cls: 'glossary-tool',
			store: this._store,
			
			// Grouping by letter
			features: [
				{
					ftype: 'grouping',
					enableGroupingMenu: true,
					hideGroupedHeader: true,
					groupHeaderTpl: '{name}'
				} 
			],
			
			selModel: {
				mode: 'MULTI'
			},
			
			columns: [
	            {stateId: 'grid-column-word', header: "{{i18n PLUGINS_GLOSSARY_UITOOL_WORD}}", width: 120, sortable: true, dataIndex: 'word'},
	            {stateId: 'grid-column-variants', header: "{{i18n PLUGINS_GLOSSARY_UITOOL_VARIANTS}}", width: 100, sortable: true, dataIndex: 'variants'},
	            {stateId: 'grid-column-content', header: "{{i18n PLUGINS_GLOSSARY_UITOOL_DEFINITION}}", flex: 1, sortable: true, dataIndex: 'content'},
	            {stateId: 'grid-column-themes', header: "{{i18n PLUGINS_GLOSSARY_UITOOL_THEMES}}", sortable: false, width: 100, groupable: true, dataIndex: 'themes', renderer: Ext.bind(this._renderThemes, null, ['themes'], true)},
				{stateId: 'grid-column-display', header: "{{i18n PLUGINS_GLOSSARY_UITOOL_DISPLAY_ON_TEXT}}", width: 100, sortable: true, dataIndex: 'displayOnText', renderer: this._renderBoolean}
			],
			
			listeners: {
				'selectionchange': Ext.bind(this.sendCurrentSelection, this)
			}
		});
		
		return this._grid;
	},
	
	getMBSelectionInteraction: function()
	{
		return Ametys.tool.Tool.MB_TYPE_ACTIVE;
	},
	
	sendCurrentSelection: function()
	{
		var selection = this._grid.getSelectionModel().getSelection();

		var targets = [];
		for (var i = 0; i < selection.length; i++) 
		{
			targets.push({
				id: Ametys.message.MessageTarget.WORD_DEFINITION,
				parameters: {
					id: selection[i].id
				}
			});
		}
		
		Ext.create('Ametys.message.Message', {
			type: Ametys.message.Message.SELECTION_CHANGED,
			targets: targets
		});
	},
	
	/**
	 * Gets the selected language.
	 * @return {String} The selected language.
	 */
	getCurrentLanguage: function()
	{
		return this._grid.down("combobox[itemId='languages-combo']").getValue();
	},
	
	/**
     * @inheritdoc
     * @param {Object} params the parameters
     * @param {String[]} [params.selectedDefinitionIds] The id of word definition to select at opening
     */ 
	setParams: function (params)
	{
		this.callParent(arguments);
		this._initialSelectedDefIds = params.selectedDefinitionIds || [];
		
		this.refresh();
	},
	
	refresh: function()
	{
		this.showRefreshing();
		this._store.load({callback: this._refreshCb, scope: this});
	},
	
	/**
     * Function invoked after loading the store
     * @private
     */
    _refreshCb: function ()
    {
    	this.showRefreshed();
    	
    	if (this._initialSelectedDefIds.length > 0)
    	{
    		var records = [];
    		var sm = this._grid.getSelectionModel();
    		var store = this._grid.getStore();
    		
    		Ext.Array.each (this._initialSelectedDefIds, function (id) {
    			var index = store.find("id", id); 
                if (index != -1)
                {
                	records.push(store.getAt(index));
                }
    		});
    		
    		sm.select(records);
    		
    		this._initialSelectedDefIds = []; // reset
    	}
    },
	
	/**
     * Listener on creation or edition message.
     * @param {Ametys.message.Message} message The edition message.
     * @private
     */
	_onMessageCreatedOrModified: function(message)
	{
		var targets = message.getTargets(Ametys.message.MessageTarget.WORD_DEFINITION);
		if (targets.length > 0)
		{
			this.showOutOfDate();
		}
	},
	
	/**
     * Listener on deletion message.
     * @param {Ametys.message.Message} message The deletion message.
     * @private
     */
	_onMessageDeleted: function(message)
	{
		var targets = message.getTargets(Ametys.message.MessageTarget.WORD_DEFINITION);
		for (var i = 0; i < targets.length; i++)
		{
			var record = this._store.getById(targets[i].getParameters().id);
			this._store.remove(record);
		}
	},
	
	/**
	 * Renders a boolean value.
	 * @param {Object} value The data value for the current cell.
	 * @private
	 */
	_renderBoolean: function(value)
	{
		if (value == true || value == 'true')
	    {
	        return "{{i18n PLUGINS_GLOSSARY_DEFINITION_YES}}";
	    }
	    else
	    {
	        return "{{i18n PLUGINS_GLOSSARY_DEFINITION_NO}}";
	    }
	},
	
	/**
     * Renderer for the themes
     * @param {Object[]} themes themes value.
     * @param {Object} metadata A collection of metadata about the current cell
     * @param {Ext.data.Model} record The record for the current row
     * @param {Number} rowIndex The index of the current row
     * @param {Number} colIndex The index of the current column
     * @param {Ext.data.Store} store The data store
     * @param {Ext.view.View} view The current view
     * @param {String} dataIndex The data index  of the column
     * @return {String} the labels of the themes as a coma-separated string
     */
    _renderThemes: function(value, metadata, record, rowIndex, colIndex, store, view, dataIndex)
    {
    	value = Ext.Array.from(value);
    
    	var labels = [];
    
	    dataIndex = dataIndex || rowIndex; // When used by grouping feature, data index is the 4th arguments
	    
	    var properties = record.get(dataIndex + "_map");
	
	    Ext.Array.forEach(value, function(v) {
	        var property = properties[v]
	        labels.push(Ext.String.escapeHtml(property ? property.label : value));
	    });

        return labels.join(', ')
    },
		
	/**
	 * Listens when a language is changed.
	 * @param {Ext.form.field.Field} field The field
	 * @param {Object} newValue The new value.
	 * @param {Object} oldValue The original value.
	 * @private
	 */
	_onChangeLang: function(field, newValue, oldValue)
	{
	    // Reload grid
		this.refresh();
	},
	
	/**
	 * Listens before loading word definitions. 
	 * The load action will be canceled if it returns false 
	 * @param {Ext.data.Store} store The store.
	 * @param {Ext.data.operation.Operation} operation The Ext.data.operation.Operation object that will be passed to the Proxy to load the Store.
	 * @param {Object} eOpts The options object passed to Ext.util.Observable.addListener.
	 * @return {Boolean} False if the load action will be canceled.
	 * @private
	 */
	_onBeforeLoad: function(store, operation, eOpts)
	{
		// Let the load occur only if we know the language.
		var lang = this._grid.down("combobox[itemId='languages-combo']").getValue();
		
		operation.setParams( Ext.apply(operation.getParams() || {}, {
			lang: lang
		}));
	}
});

Ext.define("Ametys.message.GlossaryMessageTarget",{
	override: "Ametys.message.MessageTarget",
	statics: 
	{
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} WORD_DEFINITION The target of the message is an word definition of glossary 
		 */
		WORD_DEFINITION: "wordDefinition"
	}
});