/*
 *  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 provides a widget to define a sort order based on available metadata.
 */
Ext.define('Ametys.cms.form.widget.SelectMetadataToSortBy', {
    extend: 'Ametys.form.AbstractQueryableComboBox',
    
    /**
     * @cfg {String} [metadataSetName=main] The desired metadataset name
     */
    metadataSetName: 'main',
    
    /**
     * @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
     */
    /**
     * @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}
     */
    
    valueField: 'name',
    displayField: 'fullLabel',
    
    /**
     * @private
     * @property {String} iconSortPlugin The plugin having the sort icons
     */
    iconSortPlugin: 'cms',
    /**
     * @private
     * @property {String} iconSortASC The page in the resources dir of the #iconSortPlugin plugin for the ASC sort image
     */
    iconSortASC: 'img/widgets/ascending.png',
    /**
     * @private
     * @property {String} iconSortDESC The page in the resources dir of the #iconSortPlugin plugin for the DESC sort image
     */
    iconSortDESC: 'img/widgets/descending.png',
    
    initComponent: function()
    {
        this.cls = 'x-form-selectmetadatasort-widget';
        
        // true by default
        this.displaySortIcon = this.displaySortIcon != false && this.displaySortIcon != 'false';
        
        this.iconSorts = {
            'ASC': Ametys.getPluginResourcesPrefix(this.iconSortPlugin) + '/' + this.iconSortASC,
            'DESC': Ametys.getPluginResourcesPrefix(this.iconSortPlugin) + '/' + this.iconSortDESC
        };
        
        this._sorts = {};
        
        // 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.multipleSort != false && this.multipleSort != 'false';
        
        this._contentTypesFieldName = this.contentTypesField || null;
        this._metadataSetFieldName = this.metadataSetField || null;
        
        this.form.onRelativeFieldsChange([this._contentTypesFieldName, this._metadataSetFieldName], this, this._relativeFieldChange);
        
        this.callParent(arguments);
    },
    
    initEvents: function()
    {
        this.callParent(arguments);
        
        // Click listener on the combobox to deals with clickable entries.
        this.combobox.mon(this.combobox.itemList, 'click', this._onComboboxItemListClick, this);
    },
    
    /**
     * @private
     * Event when the combobox itemlist is clicked to open the content if required
     * @param {Event} evt The click event
     * @param {Ext.Element} el The item list
     * @param {Object} o Options. Emtpy.
     */
    _onComboboxItemListClick: function(evt, el, o)
    {
        // Handle clickable entry, in order to open the corresponding content.
        var itemEl = evt.getTarget('.x-tagfield-item'),
            clickValid = itemEl ? evt.getTarget('.clickable') : false,
            record, name, sort;
            
        if (clickValid)
        {
            record = this.combobox.getRecordByListItemNode(itemEl);
            if (record)
            {
                name = record.get('name');
                sort = this._sorts[name] || 'ASC';
                sort = sort == 'ASC' ? 'DESC' : 'ASC'; // invert sort
                
                this._sorts[name] = sort;
                record.set('sort', sort);
            }
        }
    },
    
    getLabelTpl: function()
    {
        var labelTpl = [],
            sort;
        
        if (this.displaySortIcon == true)
        {
            labelTpl.push('<tpl if="values.sort == \'ASC\'"><img class="clickable" width="16" height="16" src="' + this.iconSorts.ASC + '"/></tpl>');
            labelTpl.push('<tpl if="values.sort == \'DESC\'"><img class="clickable" width="16" height="16" src="' + this.iconSorts.DESC + '{smallIcon}"/></tpl>');
            labelTpl.push('<span class="clickable">{[values.text]}</span>');
        }
        else
        {
            labelTpl.push('{[values.text]}');
        }
     
        return labelTpl;
    },
    
    getTipTpl: function()
    {
        var tipTpl = ['<div class="metadata-sort-tooltip">'];
        tipTpl.push('<b>{[values.text]} ({[values.name]})</b><br/>');
        tipTpl.push("<u>{{i18n PLUGINS_CMS_WIDGET_SELECTMETADATATOSORTBY_TOOLTIP_FULLLABEL}}</u> : {[values.fullLabel]}<br/>");
        tipTpl.push('</div>');
        
        return tipTpl;
    },
    
    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: {
                    onlySortable: true,
                    withLastValidation: true,
                    withCreationDate: true,
                    withFullLabel: 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'},
                {name: 'sort', calculate: function(data) {
                    var name = data.name;
                    if (!(name in me._sorts))
                    {
                        me._sorts[name] = 'ASC';
                    }
                    return me._sorts[name];
                }}
            ],
            
            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.
     * @private
     */
    _onStoreLoad: function(store, records)
    {
        var value = Ext.Array.from(this.getValuesAsObject()),
            store = this.combobox.getStore();
        
        // filter out record that are not in the store anymore
        value = Ext.Array.filter(value, function(entry) {
            return store.find('name', entry.name) != -1;
         });
        
        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];
        
        var params = operation.getParams() || {};
        operation.setParams(Ext.apply(params, {
            ids: contentTypesField ? contentTypesField.getValue() : null,
            viewName: metadataSetField ? metadataSetField.getValue() : this.metadataSetName
        }));
    },
    
    /**
     * Listener called when the value of a relative field changes
     */
    _relativeFieldChange: function()
    {
        this.combobox.getStore().load();
    },
    
    setValue: function (value)
    {
        // retrieves the value object
        value = value || null;
        if (value)
        {
            if (Ext.isString(value))
            {
                value = Ext.JSON.decode(value);
            }
            
            if (Ext.isObject(value))
            {
                value = Ext.Array.from(value);
            }
            // value should an array at this point
            if (!Ext.isArray(value))
            {
                value = null;
            }
        }
        
        if (value)
        {
            var sort;
            var names = Ext.Array.map(value, function(entry) {
                sort = entry.sort;
                
                if (Ext.String.endsWith(sort, '_LC'))
                {
                    sort = sort.slice(0, -3); // remove the last 3 characters, ie. the '_LC' part.
                }
                
                this._sorts[entry.name] = sort;
                
                return entry.name;
            }, this);
            
            names = this.multiple ? names : names[0];
            this.combobox.setValue(names);
        }
        else
        {
            this.combobox.setValue(null);
        }
    },
    
    getValue: function()
    {
        return Ext.encode(this.getValuesAsObject());
    },
    
    /**
     * Returns the current value of the widget as an object.
     * @return {Object/Object[]} Each object represents an entry. Object keys are: 'name', the metadata name and 'sort', the sort type ('ASC' or 'DESC').
     */
    getValuesAsObject: function()
    {
        var value = Ext.Array.from(this.combobox.getValue()),
            store = this.combobox.getStore(),
            sort, record;
        
        var valuesAsObject = Ext.Array.map(value, function(name) {
            
            sort = this._sorts[name];
            
            record = store.findRecord('name', name);
            if (record && record.get('type') == 'STRING')
            {
                // lowercase for string sorts
                sort += '_LC';
            }
            
            return {
                name: name,
                sort: sort
            };
        }, this);
        
        return this.multiple ? valuesAsObject : valuesAsObject[0];
    }
});