/*
 *  Copyright 2023 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 is an abstract class allowing to search some items based on AbstractSearchTool, it allows facets.
 */
Ext.define('Ametys.plugins.cms.search.AbstractFacetedSearchTool', {
    extend: "Ametys.plugins.cms.search.AbstractSearchTool",
    
    getBottomPanelItems: function()
    {
        var items = this.callParent(arguments); // array with one item: result grid. We will add the facet panel (on first index of the items array)
        this.facetPanel = this._createFacetPanel();
        items.splice(0, 0, this.facetPanel); // insert facetPanel at the 0-index position, removing 0 items
        return items;
    },
    
    /**
     * @protected
     * Create the tree panel for the facets
     * @return {Ext.tree.Panel} The created tree panel
     */
    _createFacetPanel: function ()
    {
        this._createFacetModel();
        
        var facetStore = Ext.create('Ext.data.TreeStore', {
            model: this._facetModelName,
            autoLoad: false,
            autoDestroy: true,
            
//          root: {
//              expanded: false
//          },
            
            proxy: {
                type: 'memory',
                reader: {
                    type: 'json'
                }
            },
            
//            filters: [
//                function(node) {
//                    return node.get('type') != 'facet' || node.get('count') > 0;
//                }
//            ],
            sorters: [{
                sorterFn: function(n1, n2) {
                    if (n1.get('type') == 'facet' && n1.get('type') == 'facet')
                    {
                        let v1 = Ext.data.SortTypes.asNonAccentedUCString(n1.get('label') || n1.get('value'));
                        let v2 = Ext.data.SortTypes.asNonAccentedUCString(n2.get('label') || n2.get('value'));
                        
                        return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
                    }
                    
                    return 0;
                }
            }]
        });
        
        var facetPanel = Ext.create('Ext.tree.Panel', {
            title: "{{i18n PLUGINS_CMS_UITOOL_SEARCH_FACET_PANEL}}",
            
            region: 'west',
            width: 200,
            
            collapsible: true,
            
            border: false,
            split: true,
            maxWidth: 500,
            rootVisible: false,
            itemId: 'facet-tree',
            cls: 'search-tool-facet-tree',
            layout: 'fit',
            viewConfig: {
                markDirty: false
            },
            store: facetStore,
            listeners: {
                'checkchange': this._onCheckFacet,
                scope: this
            }
        });

        // All the following block is juste to remove border on the place holder without any bug
        // We do create an interceptor
        facetPanel.__getPlaceholder = facetPanel.getPlaceholder;
        facetPanel.getPlaceholder = function() {
            var result = facetPanel.__getPlaceholder();
            // Modify the initial result
            result.on('render', function(ph) { ph.setBorder(false); }, null, { single: true });
            
            // Reset the interceptor after first use
            facetPanel.getPlaceholder = facetPanel.__getPlaceholder;
            
            return result;
        }

        // Disable row selection.
        facetPanel.getSelectionModel().on('beforeselect', function () {return false;});
        
        return facetPanel;
    },
    
    /**
     * Creates the model for the facet store.
     * @private
     */
    _createFacetModel: function()
    {
        fields = [
                    {name: 'text', mapping: 'label', type: 'string'},
                    {name: 'label', type: 'string'},
                    {name: 'name'},
                    {name: 'value'},
                    {name: 'count', type: 'int'},
                    {name: 'type'}
        ];
        
        if (!this._facetModelName)
        {
            this._facetModelName = this.getId() + '-SearchFacet';
            
            if (!Ext.data.schema.Schema.get('default').hasEntity(this._facetModelName)) 
            {
                Ext.define(this._facetModelName, {
                    extend: 'Ext.data.TreeModel',
                    schema: 'default',
                    fields: fields,
                    
                    listeners: {
                        beforeappend: {fn: function(parentNode, node, eOpts)
                        {
                            var type = node.get('type');
                            
                            if (type == 'criterion')
                            {
                                node.set('leaf', false);
                                node.set('cls', 'criterion');
                            }
                            else if (type == 'facet')
                            {
                                var value = node.get('value');
                                var label = node.get('label') || value;
                                var count = node.get('count');
                                
                                node.set('text', label + ' (' + count + ')');
                                node.set('leaf', true);
                                node.set('checked', false);
                                node.set('cls', 'facet');
                                
                                if (count === 0)
                                {
                                    return false;
                                }
                            }
                        }, scope: this}
                    }
                });
            }
            else
            {
                //Ext.data.schema.Schema.get('default').getEntity(this._facetModelName).replaceFields(fields, true);
                //FIXME remove else statement if line above useless
            }
        }
    },
    
    /**
     * @private
     * Listener when node's checked property changes
     * Relaunch the search
     * @param {Ext.data.NodeInterface} node The node who's checked property was changed
     * @param {Boolean} checked The node's new checked state
     */
    _onCheckFacet: function(node, checked)
    {
        if (node.get('type') == 'facet')
        {
            this._launchSearch({faceting: true});
        }
    },
    
    /**
     * @inheritdoc
     * @param {Object/Ext.button.Button} [params] Additional parameters, or the button which was clicked if this function was bound to a button
     * @param {Boolean} [params.faceting] true if the search was launch from facet tree.
     * @param {Function} [callback] Callback function to execute after search
     * @param {Object} [scope] The scope for callback function
     */
    _launchSearch: function(params, callback, scope)
    {
        params = params || {};
        this._faceting = Ext.isBoolean(params.faceting) ? params.faceting : false;
        if (!this._faceting)
        {
            this.facetPanel.getStore().clearFilter(true);
        }
        this.callParent([callback, scope]);
    },
    
    /**
     * Updates the facet tree panel
     * @param {Object} facets The facets
     * @private
     */
    _updateFacetPanel: function(facets)
    {
        Ext.suspendLayouts();

        try
        {
            var store = this.facetPanel.getStore();
            store.clearFilter(true);
            
            var root = this.facetPanel.getRootNode();
            Ext.Array.forEach(root.childNodes, function(criterionNode) {
                var name = criterionNode.get('name');
                
                var facetToFind = Ext.Array.findBy(facets, function(facet) {return facet.name == name;}) || {};
                var facetValues = facetToFind.children || [];
                
                this._updateFacetValues(criterionNode, facetValues);
            }, this);
            
            // Hide facet with count = 0
            store.filterBy(function(record) {
                    return record.get('type') != 'facet' || record.get('count') > 0;
            });
        }
        finally
        {
            Ext.resumeLayouts(true);
        }
    },
    
    /**
     * @private
     * Updates facet
     * @param {Ext.data.NodeInterface} criterionNode The node holding the facet criterion
     * @param {Object} facetValues The values 
     */
    _updateFacetValues: function(criterionNode, facetValues)
    {
        Ext.Array.forEach(criterionNode.childNodes, function(facetNode) {
            var value = facetNode.get('value');
            var label = facetNode.get('label') || value;
            
            var facet = Ext.Array.findBy(facetValues, function(facetValue){return facetValue.value == value;}) || {};
            
            facetNode.set({
                'count': facet.count, 
                'text': label + ' (' + facet.count + ')'
            });
        }, this);
    },
    
    /**
     * Get the facet values.
     * Call this method to provide the facet params to the search
     * @return {Object} The facet values
     */
    getFacetValues: function ()
    {
        var facetValues = {};
        
        if (this.facetPanel)
        {
            var checkedFacets = this.facetPanel.getChecked();
            for (var i = 0; i < checkedFacets.length; i++)
            {
                var criterionName = checkedFacets[i].parentNode.get('name');
                var value = checkedFacets[i].get('value');
                
                if (facetValues[criterionName] == null)
                {
                    facetValues[criterionName] = [];
                }
                
                facetValues[criterionName].push(value);
            }
        }
        
        return facetValues;
    },
    
});