/*
 *  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.
 */

/**
 * Singleton class defining the actions related to extraction tools.
 * @private
 */
Ext.define('Ametys.plugins.extraction.ExtractionActions', {
    singleton: true,
    
    /**
     * Opens the extraction execution tool
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    openExtractionExecutionTool: function(controller)
    {
        var focusedTool = Ametys.tool.ToolsManager.getFocusedTool();

        if (!this._doesToolMatches(focusedTool, 'uitool-extraction-execution', definitionFilePath))
        {
            var target = controller.getMatchingTargets()[0];
            var definitionFilePath = target.getParameters().path;
            var definitionFileName = target.getParameters().name;
        
            var descriptionTarget = target.getSubtarget(Ametys.message.MessageTarget.CONTENT);
            var description = descriptionTarget ? descriptionTarget.getParameters().content : undefined;
            var descriptionId = description ? description.getId() : undefined;
            
            var author = target.getParameters().auhtor;
            var canRead = target.getParameters().canRead;
            var canWrite = target.getParameters().canWrite;
            var canDelete = target.getParameters().canDelete;
            var canAssignRights = target.getParameters().canAssignRights;
            
            var toolParams = {
                id: definitionFilePath,
                name: definitionFileName,
                descriptionId: descriptionId,
                author: author,
                canRead: canRead,
                canWrite: canWrite,
                canDelete: canDelete,
                canAssignRights: canAssignRights
            }
            
            if (this._doesToolMatches(focusedTool, 'uitool-extraction-details', definitionFilePath) && focusedTool.isDirty())
            {
                Ametys.form.SaveHelper.promptBeforeQuit("{{i18n PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_SAVE_BOX_TITLE}}",
                                                        "{{i18n PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_SAVE_BOX_MESSAGE}}",
                                                        null,
                                                        function(save)
                                                        {
                                                            if (save === true)
                                                            {
                                                                focusedTool.saveExtraction.call(focusedTool, function(success)
                                                                {
                                                                    Ametys.tool.ToolsManager.openTool('uitool-extraction-execution', toolParams);
                                                                });
                                                            }
                                                            else if (save === false)
                                                            {
                                                                Ametys.tool.ToolsManager.openTool('uitool-extraction-execution', toolParams);
                                                            }
                                                            // otherwise user cancelled operation => do nothing
                                                        });
            }
            else
            {
                Ametys.tool.ToolsManager.openTool('uitool-extraction-execution', toolParams);
            }
        }
    },
    
    /**
     * Opens the extraction edition tool
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    openExtractionDetailsTool: function(controller)
    {
        var focusedTool = Ametys.tool.ToolsManager.getFocusedTool();
        
        if (!this._doesToolMatches(focusedTool, 'uitool-extraction-details', definitionFilePath))
        {
            var target = controller.getMatchingTargets()[0];
            var definitionFilePath = target.getParameters().path;
            var definitionFileName = target.getParameters().name;
        
            var descriptionTarget = target.getSubtarget(Ametys.message.MessageTarget.CONTENT);
            var description = descriptionTarget ? descriptionTarget.getParameters().content : undefined;
            var descriptionId = description ? description.getId() : undefined;
            
            var author = target.getParameters().auhtor;
            var canRead = target.getParameters().canRead;
            var canWrite = target.getParameters().canWrite;
            var canDelete = target.getParameters().canDelete;
            var canAssignRights = target.getParameters().canAssignRights;
            
            Ametys.tool.ToolsManager.openTool('uitool-extraction-details', {
                id: definitionFilePath,
                name: definitionFileName,
                descriptionId: descriptionId,
                author: author,
                canRead: canRead,
                canWrite: canWrite,
                canDelete: canDelete,
                canAssignRights: canAssignRights
            });    
        }
    },
    
    /**
     * @private
     * Check if the given tool matches the given name and file path
     * @param {Ametys.tool.Tool} tool the tool
     * @param {String} toolName the name to check
     * @param {String} definitionFilePath the file path to check
     * @return {Boolean} true if the given tool matches, false otherwise
     */
    _doesToolMatches: function(tool, toolName, definitionFilePath)
    {
        return (tool
            && Ext.String.startsWith(tool.getId(), toolName)
            && Ext.String.endsWith(tool.getId(), definitionFilePath)
        );
    },
    
    /**
     * Delete the given extraction file
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the extraction deletion. This controller has to use org.ametys.plugins.extraction.edition.EditExtractionClientSideElement class
     */
    deleteExtractionDefinition: function(controller)
    {
        var target = controller.getMatchingTargets()[0];
        var targetParameters = target.getParameters();
        
        var message = Ext.String.format("{{i18n PLUGINS_EXTRACTION_DELETE_EXTRACTION_CONFIRM_DIALOG_MSG}}", targetParameters.path);
        Ametys.Msg.confirm("{{i18n PLUGINS_EXTRACTION_DELETE_EXTRACTION_CONFIRM_DIALOG_TITLE}}", 
                message, 
                Ext.bind(this._doDeleteExtractionDefinition, this, [controller, targetParameters], 1), 
                this
        );
    },
    
    /**
     * Delete an extraction definition file
     * @param {String} btn which button was pressed
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the extraction deletion. This controller has to use org.ametys.plugins.extraction.edition.EditExtractionClientSideElement class
     * @param {Object} targetParameters The target parameters
     * @param {String} targetParameters.definitionFilePath The extraction's definitions file path
     * @param {String} targetParameters.definitionFileName The extraction's definitions file name
     * @param {String} [parameters.descriptionId] The identifier of the extraction's description
     * @param {Object} targetParameters.author The extraction'author.
     * @param {String} targetParameters.author.login The login of the extraction's author
     * @param {String} targetParameters.author.populationId The population of the extraction's author
     * @param {String} targetParameters.canRead true if the current user can read the extraction
     * @param {String} targetParameters.canWrite true if the current user can write the extraction
     * @param {String} targetParameters.canDelete true if the current user can delete the extraction
     * @param {String} targetParameters.canAssignRights true if the current user can edit rights of the extraction
     */
    _doDeleteExtractionDefinition: function(btn, controller, targetParameters)
    {
        if (btn == 'yes')
        {
            controller.serverCall('deleteExtraction', [targetParameters.path], Ext.bind(this._doDeleteExtractionDefinitionCb, this, [targetParameters], 1), { ignoreCallbackOnError: false });
        }
    },
    
    /**
     * @private
     * Callback called when the extraction has been removed
     * @param {boolean} success <code>true</code> if extraction deleting succeed, <code>false</code> otherwise
     * @param {Object} targetParameters The target parameters
     * @param {String} targetParameters.definitionFilePath The extraction's definitions file path
     * @param {String} targetParameters.definitionFileName The extraction's definitions file name
     * @param {String} [parameters.descriptionId] The identifier of the extraction's description
     * @param {Object} targetParameters.author The extraction'author.
     * @param {String} targetParameters.author.login The login of the extraction's author
     * @param {String} targetParameters.author.populationId The population of the extraction's author
     * @param {String} targetParameters.canRead true if the current user can read the extraction
     * @param {String} targetParameters.canWrite true if the current user can write the extraction
     * @param {String} targetParameters.canDelete true if the current user can delete the extraction
     * @param {String} targetParameters.canAssignRights true if the current user can edit rights of the extraction
     */
    _doDeleteExtractionDefinitionCb: function(success, targetParameters)
    {
        if (success)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.DELETED,
                targets: {
                    id: Ametys.message.MessageTarget.EXTRACTION_DEFINITION_FILE,
                    parameters: targetParameters
                }
            });
        }
        else
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_EXTRACTION_DELETE_EXTRACTION_ERROR_DIALOG_TITLE}}",
                msg: "{{i18n PLUGINS_EXTRACTION_DELETE_EXTRACTION_ERROR_DIALOG_MSG}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
        }
    },
    
    /**
     * Save the extraction of selected definition file
     */
    saveExtractionEdition: function()
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool && Ext.isFunction(tool.saveExtraction))
        {
            tool.saveExtraction();
        }
    },
    
    /**
     * Cancel extraction's edition of the given definition file
     */
    cancelExtractionEdition: function()
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool && Ext.isFunction(tool.cancelModifications))
        {
            tool.cancelModifications();
        }
    },
    
    /**
     * Download the selected extraction's result files
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    downloadResults: function(controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length == 1 && targets[0].getId() == Ametys.message.MessageTarget.EXTRACTION_RESULT_FILE)
        {
            var downloadUrl = targets[0].getParameters().downloadUrl;
            this.downloadFile(downloadUrl);
        }
        else
        {
            var files = [];
            for (var i = 0; i < targets.length; i++)
            {
                files.push(targets[i].getParameters().path)
            }
            
            this.downloadFiles(files);
        }
    },
    
    /**
     * Download the given extraction's result file
     * @param {String} downloadUrl The download URL of the file
     */
    downloadFile: function(downloadUrl)
    {
        window.open(Ametys.getPluginDirectPrefix('extraction') + '/result/download/' + downloadUrl);
    },
    
    /**
     * Download the given extraction's result files
     * @param {String[]} files Files to download
     */
    downloadFiles: function (files)
    {
        var url = Ametys.getPluginDirectPrefix('extraction') + "/results/download.zip";
        var args = { file: [] };

        for (var i = 0; i < files.length; i++)
        {
            args.file.push(files[i]);
        }
        
        Ametys.openWindow(url, args);
    },
    
    /**
     * Delete the selected result folders and result files
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    deleteResults: function(controller)
    {
        var targets = controller.getMatchingTargets();
        
        if (targets.length > 0)
        {
            Ametys.Msg.confirm("{{i18n PLUGINS_EXTRACTION_DELETE_RESULTS_TITLE}}", 
                    "{{i18n PLUGINS_EXTRACTION_DELETE_RESULTS_CONFIRM}}", 
                    doDelete,
                    this);
            
            function doDelete(answer) {
                if (answer == 'yes')
                {
                    var paths = targets.map(function(t) {return t.getParameters().path;});
                    controller.serverCall(
                            'deleteResults', [paths], this._deleteResultsCb,
                            {
                                arguments: {targets: targets},
                                errorMessage: {
                                    msg: "{{i18n PLUGINS_EXTRACTION_DELETE_RESULTS_ERROR}}", 
                                    category: Ext.getClassName(this) + '.deleteResults'
                                }
                            }
                    );
                }
            }
        }
    },
    
    /**
     * @private
     * Callback called when the result folders/files have been removed
     * @param {Object} response The response object
     * @param {String[]} response.deleted The paths that were deleted
     * @param {String[]} response.errors The paths that could not be deleted due to I/O exception
     * @param {String[]} response.not-exist  The paths that could not be deleted because they do not exist
     * @param {Object} args The arguments
     * @param {Ametys.ribbon.element.ui.ButtonController[]} args.targets The matching targets
     */
    _deleteResultsCb: function(response, args)
    {
        var allTargets = args.targets;
        var deletedTargets = response.deleted.map(function(path) {
            return Ext.Array.findBy(allTargets, function(item) {
                return item.getParameters().path == path;
            });
        });
        if (deletedTargets.length)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.DELETED,
                targets: deletedTargets
            });
        }
        
        var errors = response.errors,
            notExists = response['not-exist'],
            allNotDeleted = Ext.Array.merge(errors, notExists);
        if (allNotDeleted.length)
        {
            var allNotDeletedHtml = allNotDeleted.map(function(x) {return '<li>' + x + '</li>';}).join('');
            var msg = Ext.String.format("{{i18n PLUGINS_EXTRACTION_DELETE_RESULTS_ERROR_DIALOG_MSG}}", allNotDeletedHtml);
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_EXTRACTION_DELETE_RESULTS_ERROR_DIALOG_TITLE}}",
                msg: msg,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
        }
    },
    
    /**
     * Create a new query extraction component below the given node
     * @param {String} nodeId Id of the parent node of the new component
     */
    createQueryComponent: function(nodeId)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool && Ext.isFunction(tool.createNode))
        {
            tool.createNode('query');
        }
    },
    
    /**
     * Create a new thesaurus extraction component below the selected node
     */
    createThesaurusComponent: function()
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool && Ext.isFunction(tool.createNode))
        {
            tool.createNode('thesaurus');
        }
    },
    
    /**
     * Create a new count extraction component below the given node
     * @param {String} nodeId Id of the parent node of the new component
     */
    createCountComponent: function(nodeId)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool && Ext.isFunction(tool.createNode))
        {
            tool.createNode('count');
        }
    },
    
    /**
     * Create a new mapping-query extraction component below the given node
     * @param {String} nodeId Id of the parent node of the new component
     */
    createMappingQueryComponent: function(nodeId)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool && Ext.isFunction(tool.createNode))
        {
            tool.createNode('mapping-query');
        }
    },
    
    /**
     * Call edition tool to edit the selected node
     */
    editNode: function()
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool && Ext.isFunction(tool.editSelectedNode))
        {
            tool.editSelectedNode();
        }
    },
    
    /**
     * Delete the selected extraction node
     */
    deleteNode: function()
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool && Ext.isFunction(tool.deleteSelectedNode))
        {
            tool.deleteSelectedNode();
        }
    }
    
});