/*
 *  Copyright 2017 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 provides a widget to edit a string in multiple locales.<br>
 * 
 * This widget is the default widget registered for fields of type Ametys.form.WidgetManager#TYPE_MULTILINGUAL_STRING.<br>
 * It does NOT handle multiple values.<br>
 * 
 */
Ext.define('Ametys.form.widget.MultilingualString', {
	extend : 'Ametys.form.AbstractFieldsWrapper',
	
	alias: "widget.multilingualstring",
	
	/**
	 * @cfg {String} buttonIconCls The CSS class for the button icon
	 */
	buttonIconCls: 'ametysicon-translation',
	/**
	 * @cfg {String} buttonTooltipText The button tooltip text
	 */	
	buttonTooltipText : "{{i18n PLUGINS_CORE_UI_WIDGET_MULTILINGUAL_EDIT_LANG_BUTTON_TOOLTIP}}",
	
    /**
     * @cfg {String} defaultLanguage The default language 
     */
    defaultLanguage: Ametys.LANGUAGE_CODE,
    
	initComponent: function() 
	{
		var me = this;
		
		let maxHeight = Ametys.form.WidgetManager.getWidgetMaxHeight(this.getInitialConfig());
				
	    // Textfield field.
		this.textfield = Ext.create('Ext.form.field.Text', {
            flex: 1,
            enableKeyEvents: true,
            readOnly: this.getInitialConfig('readOnly'),
            maxHeight: maxHeight,
            listeners: {
                keyup: Ext.bind(this._updateValueOnKeyUp, this),
                change: Ext.bind(this._updateValueOnKeyUp, this)
            }
        });

        // Edit button
		this.editButton = Ext.create('Ext.button.Button', { 
            iconCls: this.buttonIconCls,
            tooltip: this.buttonTooltipText,
            maxHeight: maxHeight,
            handler : this._editLanguages,
            scope : this
        });
		
		this.items = [ this.textfield, this.editButton ];			

		this.callParent(arguments);
	},	
    
    constructor: function (config)
    {
        this.callParent(arguments);
        
        if (!this.allowBlank)
        {
	        this.on('change', this._updateWarning, this);
        }
    },
    
	/**
	 * @private
     * Function to edit all available languages
	 */
	_editLanguages: function ()
	{
        this.loadAvailableLanguages(this._openDialog, this);
	},
    
    /**
     * Open the dialog for editing the given languages
     * @param  {Object[]} languages Array of the available languages
     */
    _openDialog: function(languages)
    {
        this.triggerDialogBoxOpened = true;
        
        Ametys.helper.EditMultilingualString.open({
            title: this.getFieldLabel(),
            ownerField: this,
            values: this.getValue(),
            allowBlank: this.getInitialConfig('allowBlank'),
            languages: languages,
            itemConfig: this._getItemsConfig(),
            readOnly: this.getInitialConfig('readOnly'),
            callback: Ext.bind(this._editLanguagesCb, this)
        });
    },
    
    /**
     * Load available languages for edition
     * @param {Function} callback The callback function to call after loading. Excepted parameters are :
     * @param {Object[]} callback.languages Array of the available languages. Excepted properties for each language are: 'name' for the language code and 'label' for the label
     * @param {Object} scope The
     */
    loadAvailableLanguages: function(callback, scope)
    {
        callback.call(scope || this, []);  
    },
    
    /**
     * @private
     * Get the configuration options to transmit to dialog box items
     * @return {Object} the the configuration options for each language items
     */
    _getItemsConfig: function()
    {
        return {
            regex: this.getInitialConfig('regex'),
            regexText: this.getInitialConfig('regexText'),
            minLength: this.getInitialConfig('minLength'),
            maxLength: this.getInitialConfig('maxLength'),
        }
    },
    
    /**
     * @private
     * Callback function invoked after editing languages' values
     * @param values The values for each language
     */
    _editLanguagesCb: function (values)
    {
        if (values != null && !this.getInitialConfig('readOnly'))
        {
            this.setValue(values);
        }
        
        this.triggerDialogBoxOpened = false;
        this.focus();
    },
   
	isEqual: function (value1, value2)
	{   	    
      	if (value1 != null && value2 != null)
      	{
      		return Ext.Object.equals(value1, value2);      	
      	} 
      	else if (value1 == null && value2 == null) 
      	{
      		return true;	
      	} 
      	else 
      	{
      		return false;
      	}   	      	
	}, 	
	
	getSubmitValue: function ()
    {
        var value = this.getValue();
        return value ? Ext.encode(this.getValue()) : null;
    },
    
    /**
     * @private
     * Update warning message
     * A warning is active if the field is mandatory but does not contain value for default language
     */
    _updateWarning: function()
    {
        if (!this.allowBlank)
        {
            var value = this.getValue();
            if (value && Ext.isObject(value) && !Ext.Object.isEmpty(value) && Ext.isEmpty(value[this.defaultLanguage]))
            {
                this.markWarning("{{i18n PLUGINS_CORE_UI_WIDGET_MULTILINGUAL_MANDATORY_DEFAULT_LANG_EMPTY_WARN}}");  
            }
            else
            {
                this.clearWarning();
            }
        }
    },
    
    getErrors: function (value)
    {
        var me = this,
            errors = [];
        
        Ext.Object.eachValue(value, function (v) {
            errors = Ext.Array.merge(me._getErrors(v), errors);
        });
        
        if (!me.allowBlank && (!value || Ext.Object.isEmpty(value)))
        {
            errors.push(me.blankText);
        }
        
        return errors;
    },
    
    /**
     * @private
     * Get errors for each single language value
     * @param {String} value The value to validate
     * @return {String[]} error messages
     */
    _getErrors: function (value) 
    {
        var me = this,
            errors = [],
            validator = me.validator,
            regex = me.regex,
            trimmed, isBlank;

        if (Ext.isFunction(validator)) 
        {
            var msg = validator.call(me, value);
            if (msg !== true) {
                errors.push(msg);
            }
        }
        
        trimmed = me.allowOnlyWhitespace ? value : Ext.String.trim(value);
        isBlank = trimmed.length == 0 || (value === me.emptyText && me.valueContainsPlaceholder);
        
        if (!isBlank && value.length < me.minLength) {
            errors.push(Ext.String.format(me.minLengthText, me.minLength));
        }

        if (value.length > me.maxLength) {
            errors.push(Ext.String.format(me.maxLengthText, me.maxLength));
        }
        
        if (regex && !regex.test(value)) {
            errors.push(me.regexText || me.invalidText);
        }

        return errors;
    },
    
    getValue: function ()
    {
        var value = this.callParent(arguments);
        
        if ((!value || !Ext.isObject(value)) && this.textfield.getValue())
        {
            value = {};
            value[this.defaultLanguage] = this.textfield.getValue();
        }
        
        return value;
    },
	
	/**
     * Sets a data value into the field and updates the display field
     * @param {Object} value The value to set. Keys are locales.
     */
	setValue: function (value) 
	{	
        if (value && !Ext.isObject(value))
        {
            value = Ext.JSON.decode(value);
        }
        
		this.callParent([value]);
		
        this._updateDefaultValue(value);
	},
    
    /**
     * @private
     * Listener when the value of the main textfield has changed.
     * Update the global value of the field
     */
    _updateValueOnKeyUp: function()
    {
        var value = Ext.clone(this.value) || {};
        
        var mainValue = this.textfield.getValue();
        if (!Ext.isEmpty(mainValue))
        {
            value[this.defaultLanguage] = mainValue;
        }
        else if (value[this.defaultLanguage])
        {
            delete value[this.defaultLanguage]; // remove value for main language
        }
        
        this.setValue(value);
    },
    
    /**
     * @private
     * Update the displayed default value
     * @param {Object} value The field's value
     */
    _updateDefaultValue: function(value)
    {
        if (value && Ext.isObject(value) && !Ext.Object.isEmpty(value) && value[this.defaultLanguage])
        {
            this.textfield.setValue(value[this.defaultLanguage]);
        }
        else
        {
            this.textfield.setValue();
        }
    }
});