/*
 *  Copyright 2016 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 select a metadata.
 */
Ext.define('Ametys.cms.form.widget.SelectMetadata', {
    extend: 'Ametys.form.AbstractQueryableComboBox',
    
    /**
     * @cfg {String} [metadataSetName=main] The desired metadataset name
     */
    metadataSetName: 'main',
    
    /**
     * @cfg {String} [acceptedTypes] The accepted metadata types (comma separated). 
     * 		You can suffix types with "[ENUMERATED]" to only have enumerated of the given type (For example: STRING[ENUMERATED],LONG[ENUMERATED])
     * 		You can suffix types with "[NOT-ENUMERATED]" to only have not enumerated of the given type 
     * 		Can be null to allow every types.
     */
    
    /**
     * @cfg {String|String[]} [contentTypes] The list of allowed content types, comma separated. If {@link #cfg-contentTypesField} is used, this will be ignored.
     */
    
    /**
     * @cfg {String} [contentTypesField] The relative path the content types
     *      field, to allow the list of metadata to be updated given the
     *      value of the content types field. To force the content types, use {@link #cfg-contentTypes} instead.
     */
    /**
     * @private
     * @property {String} _contentTypesFieldName The property related to {@link #cfg-contentTypesField}
     */
    /**
     * @cfg {String} [metadataSetField] The relative path the content field, to
     *      allow the list of metadata to be updated given the value of the
     *      metadata set field
     */
    /**
     * @private
     * @property {String} _metadataSetFieldName The property related to {@link #cfg-metadataSetField}
     */
    
    /**
     * @cfg {Boolean} [includeSubRepeaters=true] true to include the sub metadata of repeater metadata as well
     */
    
    /**
     * @cfg {String/Boolean} allowNoneEntry Set to 'true' to insert the 'None' entry in the list
     */
    allowNoneEntry: false,
    
    /**
     * @cfg {String/Boolean} withLastModified Set to 'true' to include the last modified date into the list of metadata
     */
    withLastModified: false,
    
    /**
     * @cfg {String/Boolean} withLastValidation Set to 'true' to include the last validation date into the list of metadata
     */
    withLastValidation: false,
    
    /**
     * @cfg {String/Boolean} withResources Set to 'true' to include the resources as a content type
     */
    withResources: false,
    
    valueField: 'name',
    displayField: 'fullLabel',
    
    initComponent: function()
    {
        // workaround to handle multiple site on the widget side (but not on the storage side because the stored value is a JSON string)
        // true by default
        this.multiple = this.multiple != false && this.multiple != 'false';
        
        this.contentTypes = Ext.isArray(this.contentTypes) ? this.contentTypes : (this.contentTypes ? this.contentTypes.split(',') : null);
        this.acceptedTypes = Ext.isArray(this.acceptedTypes) ? this.acceptedTypes : (this.acceptedTypes ? this.acceptedTypes.split(',') : null);
        this._contentTypesFieldName = this.contentTypesField || null;
        this._metadataSetFieldName = this.metadataSetField || null;
        this._includeSubRepeaters = this.includeSubRepeaters != false && this.includeSubRepeaters != "false"; // true by default
        
        this.form.onRelativeFieldsChange([this._contentTypesFieldName, this._metadataSetFieldName], this, this._relativeFieldChange);
        
        if (!Ext.isEmpty(this.contentTypes))
        {
	        this.form.executeFormReady(this._relativeFieldChange, this);
        }
        
        this.callParent(arguments);
    },
    
    getComboBoxConfig: function()
    {
        var cfg = this.callParent(arguments);
        cfg.queryMode = 'local';
        return cfg;
    },
    
    getStore: function()
    {
        var me = this;
        return Ext.create('Ext.data.Store', {
            proxy: {
                type: 'ametys',
                plugin: 'cms',
                url: 'common-attributes.json',
                reader: {
                    type: 'json',
                    rootProperty: 'attributes'
                },
                extraParams: {
                    withFullLabel: true,
                    includeSubRepeaters: this.includeSubRepeaters || this.includeSubRepeaters == 'true',
                    withLastModified: this.withLastModified || this.allowNoneEntry == 'true',
                    withLastValidation: this.withLastValidation || this.allowNoneEntry == 'true',
                    withResources: this.withResources || this.withResources == 'true'
                }
            },
            fields: [
                {name: 'id', mapping: 'name'},
                {name: 'name', mapping: 'name'},
                {name: 'text', mapping: 'label', type: 'string'},
                {name: 'fullLabel', mapping: 'fullLabel', type: 'string'},
                {name: 'type', mapping: 'type'}
            ],
            
            sortOnLoad: true,
            sorters: [{property: 'fullLabel', direction:'ASC'}],
            
            listeners: {
                beforeload: {fn: this._onStoreBeforeLoad, scope: this},
                load: {fn: this._onStoreLoad, scope: this}
            }
        });
    },
    
    /**
     * Set the value after the store load
     * @param {Ext.data.Store} store The store.
     * @param {Ext.data.Model[]} records The loaded records.
     * @param {Boolean} successful True if the operation was successful.
     * @param {Ext.data.operation.Operation} The operation object used by proxy
     * @private
     */
    _onStoreLoad: function(store, records, successful, operation)
    {
        if (operation.aborted)
        {
            // the load has been canceled. Do nothing.
            return;
        }
        
        var value = Ext.Array.from(this.getValue()),
            store = this.combobox.getStore();
        
        if (records && records.length > 0)
        {
        	if (this.allowNoneEntry || this.allowNoneEntry == 'true')
        	{
        		// insert the "none" entry as the first entry in the store.
                store.insert(0, {
                    name: '',
                    text: "{{i18n WIDGET_SELECTTYPEDMETADATA_FILTER_NONE}}",
                    fullLabel: "{{i18n WIDGET_SELECTTYPEDMETADATA_FILTER_NONE}}"
                });
        	}
            
        	// filter out record that are not in the store anymore
            value = Ext.Array.filter(value, function(entry) {
                return store.getById(entry) != null
            });
            
            this.setValue(value);
        }
    },
    
    /**
     * Set the request parameters before loading the store.
     * @param {Ext.data.Store} store The store.
     * @param {Ext.data.operation.Operation} operation The Ext.data.Operation object that will be passed to the Proxy to load the Store.
     * @private
     */
    _onStoreBeforeLoad: function(store, operation)
    {
        var relativeFields = this.form.getRelativeFields([this._contentTypesFieldName, this._metadataSetFieldName], this),
            contentTypesField = relativeFields[0],
            metadataSetField = relativeFields[1];
        
        if ((contentTypesField && contentTypesField.getValue() == null) || (metadataSetField && metadataSetField.getValue() == null))
        {
        	return false; // cancel the load
        }
        
        var params = operation.getParams() || {};
        operation.setParams(Ext.apply(params, {
            ids: contentTypesField ? contentTypesField.getValue() : this.contentTypes,
            viewName: metadataSetField ? metadataSetField.getValue() : this.metadataSetName,
            acceptedTypes: this.acceptedTypes
        }));
    },
    
    /**
     * Listener called when the value of a relative field changes
     */
    _relativeFieldChange: function()
    {
        if (this.combobox)
        {
            this.combobox.getStore().load();
        }
    }
    
});