/*
 *  Copyright 2018 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 allows to see items from an external datasource, in order to import them.
 */
Ext.define('Ametys.plugins.odfpilotage.tool.PilotageSearchTool', {
    extend: 'Ametys.plugins.cms.search.AbstractSearchTool',

    statics: {
        /**
         * Open a pilotage log in the 'uitool-archived-logs' with no limit.
         * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
         */
        seeLog: function(controller)
        {
            var target = controller.getMatchingTargets()[0];
            var log = target.getParameters().log;
            var parameters = {
                id: log,
                title: log,
                path: log,
                limit: 0
            };
            Ametys.tool.ToolsManager.openTool('uitool-pilotage-archived-logs', parameters);
        },
        /**
         * Download the selected pilotage report.
         * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
         */
        downloadReport: function(controller)
        {
            var target = controller.getMatchingTargets()[0];
            this._downloadReport(target.getParameters().report);
        },
        /**
         * Download the given pilotage report.
         * @param {String} report The report to download
         * @private
         */
        _downloadReport: function(report)
        {
            Ametys.openWindow(Ametys.getPluginDirectPrefix('odf-pilotage') + '/pilotage/download/' + report);
        },
        /**
         * Delete the selected pilotage reports.
         * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
         */
        deleteReports: function(controller)
        {
            Ametys.Msg.confirm(
                "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_REPORT_LABEL}}", 
                "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_REPORT_CONFIRM}}", 
                Ext.bind(this._doDeleteReports, this, [controller], 1), 
                this
            );
        },
        /**
         * Get the response of the dialog and delete the pilotage reports if needed.
         * @param {String} answer "yes" if there is a confirmation.
        * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
         * @private
         */
        _doDeleteReports: function(answer, controller)
        {
            if (answer == 'yes')
            {
                var reports = [];
                var matchingTargets = controller.getMatchingTargets();
                matchingTargets.forEach(
                    target => reports.push(target.getParameters().report)
                );
                
                Ametys.data.ServerComm.callMethod({
                    role: "org.ametys.plugins.odfpilotage.helper.ReportHelper",
                    methodName: "deleteReports",
                    parameters: [reports],
                    callback: {
                        handler: this._doDeleteReportsCb,
                        scope: this,
                        arguments: {
                            targets: matchingTargets
                        }
                    },
                    refreshing: true
                });
            }
        },
        /**
         * Callback of the reports deletion.
         * @param {Object} response the server response
         * @param {String[]} response.deletedReports the deleted reports
         * @param {String[]} response.undeletedReports the undeleted reports
         * @param {Object} args the additional arguments
         * @param {Ametys.message.MessageTarget[]} args.targets the targets
         * @private
         */
        _doDeleteReportsCb: function(response, args)
        {
            var deletedReports = response['deletedReports'];
            if (deletedReports != null)
            {
                var targets = args.targets;
                var deletedReportTargets = [];
                
                for (var i=0; i < deletedReports.length; i++)
                {
                    for (var j=0; j < targets.length; j++)
                    {
                        if (targets[j].getParameters().id == deletedReports[i].id)
                        {
                            deletedReportTargets.push(targets[j]);
                        }
                    }
                }
                
                // Fires deleted event
                Ext.create("Ametys.message.Message", {
                    type: Ametys.message.Message.DELETED,
                    targets: deletedReportTargets
                });
            }
            
            if (response['undeletedReports'] != null)
            {
                Ametys.Msg.show({
                       title: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_REPORT_LABEL}}", 
                       msg: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_REPORT_ERROR}}",
                       buttons: Ext.Msg.OK,
                       icon: Ext.MessageBox.ERROR
                });
            }
            
            if (Ext.isFunction(args.callback))
            {
                args.callback.call(args.scope, response);
            }
        },
        /**
         * Delete the selected log file.
         * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
         */
        deleteLog: function(controller)
        {
            var target = controller.getMatchingTargets()[0];
            var log = target.getParameters().log;
            
            if (log)
            {
                Ametys.Msg.confirm(
                    "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_LOG_LABEL}}", 
                    Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_LOG_CONFIRM}}", log), 
                    Ext.bind(this._doDeleteLog, this, [log], 1), 
                    this
                );
            }
            else
            {
                Ametys.Msg.alert(
                    "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_LOG_LABEL}}",
                    Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_LOG_EMPTY}}", target.getParameters().report)
                );
            }
        },
        /**
         * Delete the given log file.
         * @param {String} answer "yes" if there is a confirmation.
         * @param {String} log The log file name
         * @private
         */
        _doDeleteLog: function(answer, log)
        {
            if (answer == 'yes')
            {
                Ametys.data.ServerComm.callMethod({
                    role: "org.ametys.plugins.odfpilotage.manager.PilotageLogFileManager",
                    methodName: "deleteLog",
                    parameters: [log],
                    errorMessage: {
                        msg: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DELETE_LOG_ERROR}}",
                        category: Ext.getClassName(this)
                    },
                    refreshing: true
                });
            }
        },
        /**
         * Display the log file name or "None" if there is no log file.
         * @param {String} value The log file name
         * @private
         */
        _renderLogfile: function(value)
        {
            if (!value)
            {
                return "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_NONE}}";
            }
            
            return value;
        },
        
        /**
         * Display the report type or nothing if value is empty.
         * @param {Object} value The data value
         * @private
         */
        _renderType: function(value)
        {
            if (value)
            {
                return value.label != null ? value.label : value.value;
            }
            
            return "";
        },
        
        /**
         * Display the target as glyph or nothing if value is empty.
         * @param {String} value The output format as glyph and title
         * @private
         */
        _renderTarget: function(value)
        {
            if (value == 'PROGRAM')
            {
                return '<span class="a-grid-glyph odficon-blackboard" title="{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_TARGET_PROGRAM}}"></span>';
            }
            else if (value == 'ORGUNIT')
            {
                return '<span class="a-grid-glyph odficon-orgunit" title="{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_TARGET_ORGUNIT}}"></span>';
            }
            
            return "";
        },
        
        /**
         * Display the output format as glyph or nothing if value is empty.
         * @param {String} value The output format as glyph and title
         * @private
         */
        _renderOutputFormat: function(value)
        {
            if (value == 'doc')
            {
                return '<span class="a-grid-glyph ametysicon-file-extension-doc"></span> {{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_EXPORT_HELPER_OUTPUT_FORMAT_DOC}}';
            }
            else if (value == 'xls')
            {
                return '<span class="a-grid-glyph ametysicon-file-extension-xls"></span> {{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_EXPORT_HELPER_OUTPUT_FORMAT_XLS}}';
            }
            else if (value == 'pdf')
            {
                return '<span class="a-grid-glyph ametysicon-file-extension-pdf"></span> {{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_EXPORT_HELPER_OUTPUT_FORMAT_PDF}}';
            }
            else if (value == 'csv')
            {
                return '<span class="a-grid-glyph ametysicon-file-extension-csv"></span> {{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_EXPORT_HELPER_OUTPUT_FORMAT_CSV}}';
            }
            
            return "";
        },
        
        /**
         * Display the JSON as a prettify string, closed by default.
         * @param {Object} value The JSON to display
         * @private
         */
        _renderJSON: function(value)
        {
            return "<code>" + Ext.JSON.prettyEncode(value, 0, null, -1) + "</code>";
        }
    },

    constructor: function(config)
    {
        this.callParent(arguments);
        Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onMessageDeleted, this);
    },

    /**
     * @protected
     * Get the config to be used to create the result grid.
     * @param {Ext.data.Store} store The store to use for the grid
     * @return {Object} The config object
     */
    _getResultGridCfg: function(store)
    {
        var dockedItems = [];
        if (this.enablePagination)
        {
            dockedItems.push(this._getPaginationToolbarCfg(store));
        }
        
        return { 
            store: store,
            
            region: 'center',
            split: true,
            border: false,
            
            stateful: true,
            stateId: this.getId() + "$grid",
            
            selModel : {
                mode: 'MULTI'
            },
            
            columns: [], // columns will be set later
            
            plugins: [{
                ptype: 'multisort',
                maxNumberOfSortFields: 3
            }],
            
            features: [{
                ftype: 'grouping',
                groupHeaderTpl: [
                    '{columnName}: {name:this.formatName}',
                    {
                        formatName: function(name) {
                            return Ext.String.trim(name.toString());
                        }
                    }
                ]
            }],
            
            viewConfig: {
                loadingText: "{{i18n plugin.cms:UITOOL_SEARCH_WAITING_MESSAGE}}"
            },

            dockedItems: dockedItems,
            
            listeners: {
                'selectionchange': this.sendCurrentSelection, 
                'itemdblclick': this._downloadReport,
                scope: this
            }
        };
    },

    _getStoreCfg: function()
    {
        return {
            remoteSort: true,
            proxy: {
                type: 'ametys',
                plugin: this._getProxyPlugin(),
                url: this._getProxyUrl(),
                cancelOutdatedRequest: true,
                reader: this._getReaderCfg()
             },
             
             sortOnLoad: true,

             listeners: {
                 'beforeload': {fn: this._onBeforeLoad, scope: this},
                 'load': {fn: this._onLoad, scope: this}
             }
        };
    },

    _getReaderCfg: function()
    {
        return {
            type: 'json',
            rootProperty: 'items'
        };
    },

    getMBSelectionInteraction: function()
    {
        return Ametys.tool.Tool.MB_TYPE_ACTIVE;
    },

    sendCurrentSelection: function()
    {
        var selection = this.grid.getSelectionModel().getSelection();
        
        var targets = [];
        Ext.Array.forEach(selection, function(row) {
            targets.push({
                id: Ametys.message.MessageTarget.PILOTAGE_REPORT,
                parameters: {
                    report: row.get('reportfile'),
                    log: row.get('logfile')
                }
            });
        }, this);
        
        Ext.create('Ametys.message.Message', {
            type: Ametys.message.Message.SELECTION_CHANGED,
            targets: targets
        });
    },
    
    _retrieveCriteriaAndColumns: function(force)
    {
        this.serverCall(
            'getSearchModelCriteriaConfiguration',
            [],
            Ext.bind(this._getModelCb, this), 
            {
                errorMessage: { msg: "{{i18n plugin.cms:UITOOL_SEARCH_ERROR}}", category: Ext.getClassName(this) }
            }
        );
    },
    
    /**
     * @protected
     * Callback function after retrieving from server the search criteria and columns
     * @param {Object} result The server result
     */
    _getModelCb: function(result)
    {
        let searchModel = {
            criteria: {
                criteria: {
                    elements: {
                        "filename": {
                            id: "reportfile",
                            label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_CRITERIA_FILENAME}}",
                            type: "STRING"
                        },
                        "reportType": {
                            id: "reportType",
                            label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_CRITERIA_FILE_TYPE}}",
                            type: "STRING",
                            widget: "edition.combobox",
                            enumeration: result.reportTypes
                        },
                        "target": {
                            id: "target",
                            label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_CRITERIA_TARGET}}",
                            type: "STRING",
                            widget: "edition.combobox",
                            enumeration: result.targets
                        },
                        "catalog": {
                            id: "catalog",
                            label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_CRITERIA_CATALOG}}",
                            type: "STRING",
                            widget: "edition.select-catalog",
                            enumeration: result.catalogs
                        },
                        "lastModifiedAfter": {
                            id: "lastModifiedAfter",
                            label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_CRITERIA_LASTMODIFIED_AFTER}}",
                            type: "DATETIME",
                            widget: "edition.date"
                        },
                        "lastModifiedBefore": {
                            id: "lastModifiedBefore",
                            label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_CRITERIA_LASTMODIFIED_BEFORE}}",
                            type: "DATETIME",
                            widget: "edition.date"
                        }
                    },
                    role:"fieldset"
                }
            },
            columns: [{
                path: "reportfile",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_REPORTFILE}}",
                sortable: true,
                type: "STRING",
                width: 250
            },{
                path: "type",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_TYPE}}",
                sortable: false,
                type: "STRING",
                width: 150,
                renderer: "Ametys.plugins.odfpilotage.tool.PilotageSearchTool._renderType"
            },{
                path: "generationDate",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_GENERATION_DATE}}",
                sortable: false,
                type: "DATE",
                width: 100
            },{
                path: "catalog",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_CATALOG}}",
                sortable: false,
                type: "STRING",
                width: 120,
                renderer: "Ametys.plugins.odf.search.ODFContentSearchTool.renderCatalog"
            },{
                path: "lang",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_LANG}}",
                sortable: false,
                editable: false,
                type: "STRING",
                width: 80,
                renderer: "Ametys.plugins.cms.search.SearchGridHelper.renderLanguage",
                converter: "Ametys.plugins.cms.search.SearchGridHelper.convertLanguage"
            },{
                path: "target",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_TARGET}}",
                sortable: false,
                type: "STRING",
                width: 60,
                renderer: "Ametys.plugins.odfpilotage.tool.PilotageSearchTool._renderTarget"
            },{
                path: "outputFormat",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_OUTPUT_FORMAT}}",
                sortable: false,
                type: "STRING",
                width: 80,
                renderer: "Ametys.plugins.odfpilotage.tool.PilotageSearchTool._renderOutputFormat"
            },{
                path: "context",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_CONTEXT}}",
                sortable: false,
                type: "CONTENT",
                width: 200,
                converter: "Ametys.plugins.cms.search.SearchGridHelper.convertContent"
            },{
                path: "manifest",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_MANIFEST}}",
                sortable: false,
                type: "STRING",
                width: 200,
                renderer: "Ametys.plugins.odfpilotage.tool.PilotageSearchTool._renderJSON"
            },{
                path: "lastModified",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_DATE}}",
                sortable: true,
                type: "DATETIME",
                width: 150
            },{
                path: "length",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_SIZE}}",
                sortable: true,
                type: "DOUBLE",
                width: 120,
                renderer: "Ext.util.Format.fileSize"
            },{
                path: "logfile",
                label: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_COLUMN_LOGFILE}}",
                sortable: false,
                type: "STRING",
                width: 250,
                renderer: "Ametys.plugins.odfpilotage.tool.PilotageSearchTool._renderLogfile"
            }],
            searchUrlPlugin: this._getProxyPlugin(),
            searchUrl: this._getProxyUrl(),
            pageSize: 50
        };

        let toolParams = this.getParams().toolParams || {};
        toolParams.sort = [{ property: "lastModified", direction: "DESC"}];
        this._configureSearchTool(searchModel['criteria'], searchModel, toolParams);
    },

    /**
     * @protected
     * @template
     * Gets the plugin name for the proxy of the store
     * @return {String} the plugin name for the proxy of the store
     */
    _getProxyPlugin: function()
    {
        return 'odf-pilotage';
    },
    
    /**
     * @protected
     * @template
     * Gets the URL for the proxy of the store
     * @return {String} the URL for the proxy of the store
     */
    _getProxyUrl: function()
    {
        return 'pilotage/list.json';
    },
    
    /**
     * Function called before loading the store
     * @param {Ext.data.Store} store The store
     * @param {Ext.data.operation.Operation} operation The object that will be passed to the Proxy to load the store
     * @private
     */
    _onBeforeLoad: function(store, operation)
    {
        if (this.grid && !this._updatingModel && (!(this.form instanceof Ametys.form.ConfigurableFormPanel) ||  this.form.isFormReady()))
        {
            this.grid.getView().unmask();
            
            if (!this.form.isValid())
            {
                this._stopSearch();
                return false;
            }
            
            operation.setParams( Ext.apply(operation.getParams() || {}, {
                values: this.form.getJsonValues()
            }));
            
            this._error = null;
        }
        else
        {
            // avoid use less requests at startup (applyState...)
            return false;
        }
    },
    
    /**
     * Function called after loading results
     * @param {Ext.data.Store} store The store
     * @param {Ext.data.Model[]} records An array of records
     * @param {Boolean} successful True if the operation was successful.
     * @param {Ext.data.Operation} operation The operation that triggered this load.
     * @private
     */
    _onLoad: function (store, records, successful, operation)
    {
        if (operation.aborted)
        {
            // the load has been canceled. Do nothing.
            return;
        }
        
        // Hack to process groups locally even if remoteSort is enabled.
        store.getData().setAutoGroup(true);
        
        this._setGridDisabled(false);
        
        if (!successful)
        {
            Ametys.log.ErrorDialog.display({
                title: "{{i18n plugin.cms:UITOOL_SEARCH_ERROR_TITLE}}",
                text: "{{i18n plugin.cms:UITOOL_SEARCH_ERROR}}",
                details: "",
                category: "Ametys.plugins.odfpilotage.tool.PilotageSearchTool"
            });
            return;
        }
        
        if (this._error)
        {
            Ametys.log.ErrorDialog.display({
                title: "{{i18n plugin.cms:UITOOL_SEARCH_ERROR_QUERY_TITLE}}",
                text: this._error,
                details: "",
                category: "Ametys.plugins.odfpilotage.tool.PilotageSearchTool"
            });
        }
        
        if (records.length == 0)
        {
            this.grid.getView().mask("{{i18n plugin.cms:UITOOL_CONTENTEDITIONGRID_NO_RESULT}}", 'ametys-mask-unloading');
        }
    },

    /**
     * Called when a node is double-clicked in the grid.
     * @param {Ext.tree.View} view the tree view.
     * @param {Ext.data.Model} record the double-clicked node
     * @private
     */
    _downloadReport: function(view, record)
    {
        this.statics()._downloadReport(record.data.reportfile);
    },
    
    /**
     * Listener on deletion message.
     * @param {Ametys.message.Message} message The deletion message.
     * @private
     */
    _onMessageDeleted: function(message)
    {
        var targets = message.getTargets(Ametys.message.MessageTarget.PILOTAGE_REPORT);
        let records = targets.map(target => this.store.findExact("reportfile", target.getParameters().report));
        this.store.remove(records);
    }
});

Ext.define('Ametys.plugins.odfpilotage.PilotageMessageTarget', {
    override: 'Ametys.message.MessageTarget',
    
    statics:
    {
        /**
         * @member Ametys.message.MessageTarget
         * @readonly
         * @property {String} PILOTAGE_REPORT The target id is a report file. Parameters are:
         * @property {String} PILOTAGE_REPORT.report The complete path to the report
         * @property {String} PILOTAGE_REPORT.log The complete path to the log
         */
        PILOTAGE_REPORT: 'pilotage-report'
    }
});