/*
 *  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 class controls a ribbon query editor button.
 * @private
 */
Ext.define('Ametys.plugins.externaldata.editor.QueryEditorButton', {
	extend: 'Ametys.cms.editor.EditorButtonController',
	
	statics: {
		/**
		 * @private
		 * @property {Object} _queryData Query parameter cache. Avoids making a request each time a query is clicked in the editor.
		 */
		_queryData: {},
		
		/**
		 * @private
		 * @property {Object} _listeners The listeners of the button.
		 */
		_listeners: {},
		
		/**
		 * @private
		 * @property {Ext.form.Panel} _queryParamsPanel The params panel (on the right).
		 */
		
		/**
		 * @private
		 * @property {Ext.form.Panel} _queryDetailsPanel The params panel (on the left).
		 */
		
		/**
		 * @property {String} width. The width config.
		 */
		
		/**
		 * @property {String} disabled. The disabled config.
		 */
		
		/**
		 * Sets 'query-parameters' element to current node when the input loses the focus.
		 * @param {Ext.form.field.Text} input The input text
		 */
		setQueryParamsOnBlur: function(input)
		{
			this._setQueryParams(input.getName(), input.getValue());
		},
		
		/**
		 * Sets 'query-parameters' element to current node when pressing ENTER or ESC key.
		 * @param {Ext.form.field.Text} input The input text
		 * @param {Ext.event.Event} e The event object
		 */
		setQueryParamsOnSpecialKey: function(input, e)
		{
			if (e.getKey() == e.ENTER)
		    {
				e.preventDefault();
				e.stopPropagation();
				this._setQueryParams(input.getName(), input.getValue());
		    }
		    else if (e.getKey() == e.ESC)
		    {
				e.preventDefault();
				e.stopPropagation();
				input.setValue(this._currentNode.title || "");
		    }
		},
		
		/**
		 * Sets 'query-parameters' element to current node.
		 * @param {String} name The name of the field.
		 * @param {String} value The value to set.
		 * @private
		 */
		_setQueryParams: function(name, value)
		{
			var queryNode = this._currentNode;
		    if (queryNode != null && name != null)
		    {
		    	// FIXME we do a defer to avoid an infinite loop with the event 'onblur'
		    	Ext.defer(this._setQueryParams2, 0.1, this, [name, value, queryNode]);
		    }
		},
		
		/**
		 * Effectively sets 'query-parameters' element to current node. Called by {@link #_setQueryParams}.
		 * @param {String} name The name of the field.
		 * @param {String} value The value to set.
		 * @param {HTMLElement} queryNode The node to set.
		 * @private
		 */
		_setQueryParams2: function(name, value, queryNode)
		{
		    // FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
		    tinyMCE.activeEditor.focus();
	        var paramName = name.substring(12, name.length);
	        var attributeName = 'param-' + paramName;
	        
	        if (value == '')
	        {
	            if (queryNode.getAttribute(attributeName) != null)
	            {
	            	queryNode.removeAttribute(attributeName);
			        tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
				}
	        }
	        else
	        {
	        	if (queryNode.getAttribute(attributeName) != value)
	        	{
	            	queryNode.setAttribute(attributeName, value);
			        tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
	        	}
	        }
		},
		
		/**
		 * Enable/disable controller when a query is selected.
		 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller
		 * @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
		 * @param {HTMLElement} node The current selected node. Can be null.
		 */
		queryEditorButtonListener: function(controller, field, node)
		{
			var imgTag = (field != null && node != null) ? field.getEditor().dom.getParent(field.getEditor().selection.getNode(), 'img[datainclusion=query]') : null;
		    if (imgTag)
		    {
		        if (imgTag.getAttribute('queryid') != null)
		        {
		            // Get the selected query Id and parameter values.
		            var queryId = imgTag.getAttribute('queryid');
		            var paramValues = {};
		            for (var i = 0; i < imgTag.attributes.length; i++)
		            {
		                var attribute = imgTag.attributes[i].name;
		                if (attribute.substr(0, 6) == 'param-')
		                {
		                    var name = attribute.substring(6, attribute.length);
		                    var value = imgTag.getAttribute(attribute);
		                    paramValues[name] = value;
		                }
		            }
		            
		            // Load the query panel.
		            this._loadQueryPanel(queryId, paramValues);
		        }
		    }
		    this._currentNode = imgTag;
		},
		
		/**
		 * Loads the query panel.
		 * @param {String} queryId The id of the query to load.
		 * @param {Object} paramValues The values to set to the parameters of the query.
		 * @private
		 */
		_loadQueryPanel: function(queryId, paramValues)
		{
			if (queryId)
		    {
		        // Remove all the elements in the panel.
		        this._clearPanels();
		        
		        // Get the data for this query.
		        if (!this._queryData[queryId])
		        {
		        	this._getQueryData(queryId, paramValues);
		        }
		        else
		        {
		        	this._loadQueryPanelAfterQueryDataIsLoaded(queryId, paramValues);
		        }
		    }
		},
		
		/**
		 * Loads the query panel, after we are sure queryData is defined.
		 * @param {String} queryId The id of the query to load.
		 * @param {Object} paramValues The values to set to the parameters of the query.
		 * @private
		 */
		_loadQueryPanelAfterQueryDataIsLoaded: function(queryId, paramValues)
		{
			var queryData = this._queryData[queryId]
			
            if (Ext.Object.isEmpty(queryData))
            {
                this._queryParamsPanel.add({
                    xtype: 'component',
                    html: "<b>{{i18n PLUGINS_EXTERNAL_DATA_CONTENT_EDITION_DELETED_QUERY_TITLE}}</b><br/>{{i18n PLUGINS_EXTERNAL_DATA_CONTENT_EDITION_DELETED_QUERY_MSG}}",
                    cls: "datainclusion-message-left"
                });
            }
            else
            {
    			// Name and description.
    	        this._queryDetailsPanel.add({
    	        	xtype: 'component',
    	            html: "<b>{{i18n PLUGINS_EXTERNAL_DATA_UI_HELPER_QUERY_NAME}}</b> : " + queryData['name'],
    	            cls: "datainclusion-message-left",
    	            anchor: '100%'
    	        });
    	        this._queryDetailsPanel.add({
    	        	xtype: 'component',
    	            html: "<b>{{i18n PLUGINS_EXTERNAL_DATA_UI_HELPER_QUERY_DESCRIPTION}}</b> : " + queryData['description'],
    	            cls: "datainclusion-message-left",
    	            anchor: '100%'
    	        });
    	        
    	        // Parameters.
    	        var parameters = queryData['parameters'];
    	        if (Ext.Object.isEmpty(parameters))
    	        {
    	            this._queryParamsPanel.add({
    	            	xtype: 'component',
                        html: "{{i18n PLUGINS_EXTERNAL_DATA_QUERY_NO_PARAMETER}}",
                        cls: "datainclusion-message"
                    });
    	        }
    	        
    	        var columnCt;
    	        
    	        // Add an input field for each parameter.
    	        var index = 0;
    	        for (var paramName in parameters)
    	        {
    	        	if (index % 3 == 0)
    	        	{
    	        		columnCt = Ext.create('Ext.Container', { margin: '0 5 0 0', flex: 1, items: []});
    	        		this._queryParamsPanel.add(columnCt);
    	        	}
    	        	var paramLabel = parameters[paramName];
    	        	var field = this._addInputField(paramName, paramLabel);
    	        	field = columnCt.add(field);
    	            if (paramValues != null && paramValues[paramName] != null)
    	            {
    	                var value = paramValues[paramName];
    	                field.setValue(value);
    	            }
    	            else
    	            {
    	                field.setValue('');
    	            }
    	            index++;
    	        }
            }
		},
		
		/**
		 * Clears the panel of the old input fields.
		 * @private
		 */
		_clearPanels: function()
		{
			var item;
		    while (item = this._queryDetailsPanel.items.first())
		    {
		        this._queryDetailsPanel.remove(item, true);
		    }
		    while (item = this._queryParamsPanel.items.first())
		    {
		        this._queryParamsPanel.remove(item, true);
		    }
		},
		
		/**
		 * Gets a query parameter.
		 * Loads the parameters of a given query.
		 * @param {String} queryId The id of the query.
		 * @param {Object} paramValues The values to set to the parameters of the query.
		 * @return {Object} An object containing the data of the query.
		 * @private
		 */
		_getQueryData: function(queryId, paramValues)
		{
			Ametys.cms.externaldata.QueryDAO.getQueryProperties(
	        	[queryId, Ametys.getAppParameter('siteName')], 
	        	this._getQueryDataCb, 
	        	{scope: this, arguments: [queryId, paramValues]}
	        );
		},
		
		/**
		 * Callback function after retrieving the query properties.
		 * Then resumes the loading of the query panel, since the query params are loaded.
		 * @param {Object} response The response of the server
		 * @param {Array} args The passed arguments
		 * @private
		 */
		_getQueryDataCb: function(response, args)
		{
			var queryId = args[0];
			var paramValues = args[1];
			this._queryData[queryId] = response;
			
			this._loadQueryPanelAfterQueryDataIsLoaded(queryId, paramValues);
		},
		
		/**
		 * Adds an input field to the parameter panel.
		 * @param {String} name The name of the field.
		 * @param {String} label The label of the field.
		 * @return {Ext.form.field.Text} The textfield that was added.
		 * @private
		 */
		_addInputField: function(name, label)
		{
			var elementConf = 
		    {
		        inputType: 'text',
		        xtype: 'textfield',
		        
		        hideLabel: false,
		        fieldLabel: label,
		        name: 'query-param-' + name,
		        
		        enableKeyEvents : true,
		        
		        width: this.width != null ? this.width : 'auto',
		        disabled: this.disabled == "true",
		        
		        listeners: this._listeners
		    };
			
			return elementConf;
		}
	},
	
	createUI: function(size, colspan)
	{
	    for (var key in this.getInitialConfig())
	    {
	        if (/^on(.*)$/.test(key))
	        {
	            this.self._listeners[RegExp.$1] = Ext.bind(eval(this.getInitialConfig()[key]), this.self);
	        }
	    }
	    
	    var tooltipImg;
	    if (this.getInitialConfig()['icon-large'] != null)
	    {
	        tooltipImg = Ametys.CONTEXT_PATH + this.getInitialConfig()['icon-large']
	    }
	    else if (this.getInitialConfig()['icon-medium'] != null)
	    {
	        tooltipImg = Ametys.CONTEXT_PATH + this.getInitialConfig()['icon-medium']
	    }
	    else if (this.getInitialConfig()['icon-small'] != null)
	    {
	        tooltipImg = Ametys.CONTEXT_PATH + this.getInitialConfig()['icon-small']
	    }
	    
	    this.self.width = this.getInitialConfig()['width'];
	    this.self.disabled = this.getInitialConfig()['disabled'];
	    
	    this.self._queryDetailsPanel = Ext.create('Ext.Container', {
	    	itemId: 'query-details',
	        width: 270,
	        layout: 'anchor',
	        border: false,
	        items: []
	    });
	    
	    this.self._queryParamsPanel = Ext.create('Ext.Container', {
	        itemId: 'query-parameters',
	        flex: 1,
	        layout: {
	            type: 'hbox',
	            align: 'stretch',
	            pack: 'start'
	        },
	        border: false,
	        defaultType: 'textfield',
	        labelWidth: this.getInitialConfig()['label-width'] != null ? Number(this.getInitialConfig()['label-width']) : 60
	    });
	    
	    var element = Ext.create('Ext.Container', {
	        layout: {
	        	type: 'hbox',
	        	align: 'stretch'
	        },
	        border: false,
	        items: [this.self._queryDetailsPanel, this.self._queryParamsPanel]
	    });
	    
	    return element;
	},
	
    setAdditionalDescription: function(additionalDescription)
    {
        // Does not need additional description, because it does not have elements when hidden and disabled.
    }
	
});