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

/**
 * The workflow DAO
 */
Ext.define('Ametys.plugins.workflow.dao.WorkflowsDAO', {
    singleton: true,
    
    constructor: function()
    {
        /**
         * @callable
         * @member Ametys.plugins.workflow.dao.WorkflowsDAO
         * @method getWorkflowRootProperties
         * Get workflow properties for WorkflowEditorTree root node
         * This calls the method 'getWorkflowRootProperties' of the server DAO 'WorkflowsDAO'.
         * @param {Object[]} parameters The parameters to transmit to the server method
         * @param {Function} callback The function to call when the java process is over. Use options.scope for the scope. 
         * @param {Object} callback.arguments Other arguments specified in option.arguments                 
         * @param {Object} [options] Advanced options for the call.
         * @param {Boolean/String/Object} [options.errorMessage] Display an error message. See Ametys.data.ServerComm#callMethod errorMessage.
         * @param {Boolean/String/Object} [options.waitMessage] Display a waiting message. See Ametys.data.ServerComm#callMethod waitMessage.
         * @param {Number} [options.scope] This parameter is the scope used to call the callback. Moreover is the given class is a mixin of Ametys.data.ServerCaller, its methods Ametys.data.ServerCaller#beforeServerCall and Ametys.data.ServerCaller#afterServerCall will be used so see their documentation to look for additional options (such a refreshing on Ametys.ribbon.element.ui.ButtonController#beforeServerCall).
         * @param {Number} [options.priority] The message priority. See Ametys.data.ServerComm#callMethod for more information on the priority. PRIORITY_SYNCHRONOUS cannot be used here.
         * @param {String} [options.cancelCode] Cancel similar unachieved read operations. See Ametys.data.ServerComm#callMethod cancelCode.
         * @param {Object} [options.arguments] Additional arguments set in the callback.arguments parameter.                  
         * @param {Boolean} [options.ignoreCallbackOnError] If the server throws an exception, should the callback beeing called with a null parameter. See Ametys.data.ServerComm#callMethod ignoreOnError.
         */
        this.addCallables(
            {
                role: "org.ametys.plugins.workflow.dao.WorkflowsDAO",
                methodName: "getWorkflowRootProperties",
                convertor: this._convertWorkflowProperties,
                waitMessage: false,
                errorMessage: {
                    msg: "{{i18n PLUGINS_WORKFLOW_WORKFLOWS_DAO_ERROR_TITLE}}",
                    category: Ext.getClassName(this)
                }
            }
        );
        
        /**
         * @callable
         * @member Ametys.plugins.workflow.dao.WorkflowsDAO
         * @method getWorkflowInfos 
         * Get labels and unavailables names for current workflow
         * This calls the method 'getWorkflowsDuplicateInfos' of the server DAO 'WorkflowsDAO'.
         * @param {Object[]} parameters The parameters to transmit to the server method
         * @param {Function} callback The function to call when the java process is over. Use options.scope for the scope. 
         * @param {Object} callback.arguments Other arguments specified in option.arguments                 
         * @param {Object} [options] Advanced options for the call.
         * @param {Boolean/String/Object} [options.errorMessage] Display an error message. See Ametys.data.ServerComm#callMethod errorMessage.
         * @param {Boolean/String/Object} [options.waitMessage] Display a waiting message. See Ametys.data.ServerComm#callMethod waitMessage.
         * @param {Number} [options.scope] This parameter is the scope used to call the callback. Moreover is the given class is a mixin of Ametys.data.ServerCaller, its methods Ametys.data.ServerCaller#beforeServerCall and Ametys.data.ServerCaller#afterServerCall will be used so see their documentation to look for additional options (such a refreshing on Ametys.ribbon.element.ui.ButtonController#beforeServerCall).
         * @param {Number} [options.priority] The message priority. See Ametys.data.ServerComm#callMethod for more information on the priority. PRIORITY_SYNCHRONOUS cannot be used here.
         * @param {String} [options.cancelCode] Cancel similar unachieved read operations. See Ametys.data.ServerComm#callMethod cancelCode.
         * @param {Object} [options.arguments] Additional arguments set in the callback.arguments parameter.                  
         * @param {Boolean} [options.ignoreCallbackOnError] If the server throws an exception, should the callback beeing called with a null parameter. See Ametys.data.ServerComm#callMethod ignoreOnError.
         */
        this.addCallables(
            {
                role: "org.ametys.plugins.workflow.dao.WorkflowsDAO",
                methodName: "getWorkflowInfos",
                callback: {
                    handler: Ext.emptyFn
                },
                waitMessage: false,
                errorMessage: {
                    msg: "{{i18n PLUGINS_WORKFLOW_WORKFLOWS_DAO_ERROR_TITLE}}",
                    category: Ext.getClassName(this)
                }
            }
        );
        
        /**
         * @callable
         * @member Ametys.plugins.workflow.dao.WorkflowsDAO
         * @method createWorkflow 
         * Create a new workflow
         * This calls the method 'createWorkflow' of the server DAO 'WorkflowsDAO'.
         * @param {Object[]} parameters The parameters to transmit to the server method
         * @param {Function} callback The function to call when the java process is over. Use options.scope for the scope. 
         * @param {Object} callback.arguments Other arguments specified in option.arguments                 
         * @param {Object} [options] Advanced options for the call.
         * @param {Boolean/String/Object} [options.errorMessage] Display an error message. See Ametys.data.ServerComm#callMethod errorMessage.
         * @param {Boolean/String/Object} [options.waitMessage] Display a waiting message. See Ametys.data.ServerComm#callMethod waitMessage.
         * @param {Number} [options.scope] This parameter is the scope used to call the callback. Moreover is the given class is a mixin of Ametys.data.ServerCaller, its methods Ametys.data.ServerCaller#beforeServerCall and Ametys.data.ServerCaller#afterServerCall will be used so see their documentation to look for additional options (such a refreshing on Ametys.ribbon.element.ui.ButtonController#beforeServerCall).
         * @param {Number} [options.priority] The message priority. See Ametys.data.ServerComm#callMethod for more information on the priority. PRIORITY_SYNCHRONOUS cannot be used here.
         * @param {String} [options.cancelCode] Cancel similar unachieved read operations. See Ametys.data.ServerComm#callMethod cancelCode.
         * @param {Object} [options.arguments] Additional arguments set in the callback.arguments parameter.                  
         * @param {Boolean} [options.ignoreCallbackOnError] If the server throws an exception, should the callback beeing called with a null parameter. See Ametys.data.ServerComm#callMethod ignoreOnError.
         */
        this.addCallables(
            {
                role: "org.ametys.plugins.workflow.dao.WorkflowsDAO",
                methodName: "createWorkflow",
                callback: {
                    handler: this._createWorkflowCB
                },
                waitMessage: false,
                errorMessage: {
                    msg: "{{i18n PLUGINS_WORKFLOW_WORKFLOWS_DAO_ERROR_TITLE}}",
                    category: Ext.getClassName(this)
                }
            }
        );
        
        /**
         * @callable
         * @member Ametys.plugins.workflow.dao.WorkflowsDAO
         * @method renameWorkflow 
         * Rename a new workflow
         * This calls the method 'renameWorkflow' of the server DAO 'WorkflowsDAO'.
         * @param {Object[]} parameters The parameters to transmit to the server method
         * @param {Function} callback The function to call when the java process is over. Use options.scope for the scope. 
         * @param {Object} callback.arguments Other arguments specified in option.arguments                 
         * @param {Object} [options] Advanced options for the call.
         * @param {Boolean/String/Object} [options.errorMessage] Display an error message. See Ametys.data.ServerComm#callMethod errorMessage.
         * @param {Boolean/String/Object} [options.waitMessage] Display a waiting message. See Ametys.data.ServerComm#callMethod waitMessage.
         * @param {Number} [options.scope] This parameter is the scope used to call the callback. Moreover is the given class is a mixin of Ametys.data.ServerCaller, its methods Ametys.data.ServerCaller#beforeServerCall and Ametys.data.ServerCaller#afterServerCall will be used so see their documentation to look for additional options (such a refreshing on Ametys.ribbon.element.ui.ButtonController#beforeServerCall).
         * @param {Number} [options.priority] The message priority. See Ametys.data.ServerComm#callMethod for more information on the priority. PRIORITY_SYNCHRONOUS cannot be used here.
         * @param {String} [options.cancelCode] Cancel similar unachieved read operations. See Ametys.data.ServerComm#callMethod cancelCode.
         * @param {Object} [options.arguments] Additional arguments set in the callback.arguments parameter.                  
         * @param {Boolean} [options.ignoreCallbackOnError] If the server throws an exception, should the callback beeing called with a null parameter. See Ametys.data.ServerComm#callMethod ignoreOnError.
         */
        this.addCallables(
            {
                role: "org.ametys.plugins.workflow.dao.WorkflowsDAO",
                methodName: "renameWorkflow",
                callback: {
                    handler: this._renameWorkflowCB
                },
                waitMessage: false,
                errorMessage: {
                    msg: "{{i18n PLUGINS_WORKFLOW_WORKFLOWS_DAO_ERROR_TITLE}}",
                    category: Ext.getClassName(this)
                }
            }
        );
        
        /**
         * @callable
         * @member Ametys.plugins.workflow.dao.WorkflowsDAO
         * @method duplicateWorkflow 
         * Duplicate a workflow
         * This calls the method 'duplicateWorkflow' of the server DAO 'WorkflowsDAO'.
         * @param {Object[]} parameters The parameters to transmit to the server method
         * @param {Function} callback The function to call when the java process is over. Use options.scope for the scope. 
         * @param {Object} callback.arguments Other arguments specified in option.arguments                 
         * @param {Object} [options] Advanced options for the call.
         * @param {Boolean/String/Object} [options.errorMessage] Display an error message. See Ametys.data.ServerComm#callMethod errorMessage.
         * @param {Boolean/String/Object} [options.waitMessage] Display a waiting message. See Ametys.data.ServerComm#callMethod waitMessage.
         * @param {Number} [options.scope] This parameter is the scope used to call the callback. Moreover is the given class is a mixin of Ametys.data.ServerCaller, its methods Ametys.data.ServerCaller#beforeServerCall and Ametys.data.ServerCaller#afterServerCall will be used so see their documentation to look for additional options (such a refreshing on Ametys.ribbon.element.ui.ButtonController#beforeServerCall).
         * @param {Number} [options.priority] The message priority. See Ametys.data.ServerComm#callMethod for more information on the priority. PRIORITY_SYNCHRONOUS cannot be used here.
         * @param {String} [options.cancelCode] Cancel similar unachieved read operations. See Ametys.data.ServerComm#callMethod cancelCode.
         * @param {Object} [options.arguments] Additional arguments set in the callback.arguments parameter.                  
         * @param {Boolean} [options.ignoreCallbackOnError] If the server throws an exception, should the callback beeing called with a null parameter. See Ametys.data.ServerComm#callMethod ignoreOnError.
         */
        this.addCallables(
            {
                role: "org.ametys.plugins.workflow.dao.WorkflowsDAO",
                methodName: "duplicateWorkflow",
                callback: {
                    handler: this._duplicateWorkflowCB
                },
                waitMessage: false,
                errorMessage: {
                    msg: "{{i18n PLUGINS_WORKFLOW_WORKFLOWS_DAO_ERROR_TITLE}}",
                    category: Ext.getClassName(this)
                }
            }
        );
        
        /**
         * @callable
         * @member Ametys.plugins.workflow.dao.WorkflowsDAO
         * @method saveChanges 
         * Overwrite the xml workflow file with changes
         * This calls the method 'saveChanges' of the server DAO 'WorkflowsDAO'.
         * @param {Object[]} parameters The parameters to transmit to the server method
         * @param {Function} callback The function to call when the java process is over. Use options.scope for the scope. 
         * @param {Object} callback.arguments Other arguments specified in option.arguments                 
         * @param {Object} [options] Advanced options for the call.
         * @param {Boolean/String/Object} [options.errorMessage] Display an error message. See Ametys.data.ServerComm#callMethod errorMessage.
         * @param {Boolean/String/Object} [options.waitMessage] Display a waiting message. See Ametys.data.ServerComm#callMethod waitMessage.
         * @param {Number} [options.scope] This parameter is the scope used to call the callback. Moreover is the given class is a mixin of Ametys.data.ServerCaller, its methods Ametys.data.ServerCaller#beforeServerCall and Ametys.data.ServerCaller#afterServerCall will be used so see their documentation to look for additional options (such a refreshing on Ametys.ribbon.element.ui.ButtonController#beforeServerCall).
         * @param {Number} [options.priority] The message priority. See Ametys.data.ServerComm#callMethod for more information on the priority. PRIORITY_SYNCHRONOUS cannot be used here.
         * @param {String} [options.cancelCode] Cancel similar unachieved read operations. See Ametys.data.ServerComm#callMethod cancelCode.
         * @param {Object} [options.arguments] Additional arguments set in the callback.arguments parameter.                  
         * @param {Boolean} [options.ignoreCallbackOnError] If the server throws an exception, should the callback beeing called with a null parameter. See Ametys.data.ServerComm#callMethod ignoreOnError.
         */
        this.addCallables(
            {
                role: "org.ametys.plugins.workflow.dao.WorkflowsDAO",
                methodName: "saveChanges",
                callback: {
                    handler: this._saveChangesCB
                },
                waitMessage: false,
                errorMessage: {
                    msg: "{{i18n PLUGINS_WORKFLOW_WORKFLOWS_DAO_ERROR_TITLE}}",
                    category: Ext.getClassName(this)
                }
            }
        );
        
        /**
         * @callable
         * @member Ametys.plugins.workflow.dao.WorkflowsDAO
         * @method reinit 
         * Restore the last version of xml workflow file
         * This calls the method 'reinit' of the server DAO 'WorkflowsDAO'.
         * @param {Object[]} parameters The parameters to transmit to the server method
         * @param {Function} callback The function to call when the java process is over. Use options.scope for the scope. 
         * @param {Object} callback.arguments Other arguments specified in option.arguments                 
         * @param {Object} [options] Advanced options for the call.
         * @param {Boolean/String/Object} [options.errorMessage] Display an error message. See Ametys.data.ServerComm#callMethod errorMessage.
         * @param {Boolean/String/Object} [options.waitMessage] Display a waiting message. See Ametys.data.ServerComm#callMethod waitMessage.
         * @param {Number} [options.scope] This parameter is the scope used to call the callback. Moreover is the given class is a mixin of Ametys.data.ServerCaller, its methods Ametys.data.ServerCaller#beforeServerCall and Ametys.data.ServerCaller#afterServerCall will be used so see their documentation to look for additional options (such a refreshing on Ametys.ribbon.element.ui.ButtonController#beforeServerCall).
         * @param {Number} [options.priority] The message priority. See Ametys.data.ServerComm#callMethod for more information on the priority. PRIORITY_SYNCHRONOUS cannot be used here.
         * @param {String} [options.cancelCode] Cancel similar unachieved read operations. See Ametys.data.ServerComm#callMethod cancelCode.
         * @param {Object} [options.arguments] Additional arguments set in the callback.arguments parameter.                  
         * @param {Boolean} [options.ignoreCallbackOnError] If the server throws an exception, should the callback beeing called with a null parameter. See Ametys.data.ServerComm#callMethod ignoreOnError.
         */
        this.addCallables(
            {
                role: "org.ametys.plugins.workflow.dao.WorkflowsDAO",
                methodName: "reinit",
                callback: {
                    handler: this._reinitCB
                },
                waitMessage: false,
                errorMessage: {
                    msg: "{{i18n PLUGINS_WORKFLOW_WORKFLOWS_DAO_ERROR_TITLE}}",
                    category: Ext.getClassName(this)
                }
            }
        );
    },
    
    /**
     * Callback function called after {@link #reinit} has been processed.
     * @param {Object} response The text response provided by the {@link Ametys.data.ServerComm}
     * @private
     */
    _reinitCB: function(response)
    {
        if(!response.message)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.MODIFIED,
                targets: {
                    id: Ametys.message.MessageTarget.WORKFLOW_OBJECT,
                    parameters: {
                        id: response.workflowId
                    }
                }
            });
            
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_WORKFLOW_REINIT_TITLE}}",
                msg: "{{i18n PLUGINS_WORKFLOW_REINIT_MSG}}",
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.INFO
            });
        }
        else
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_WORKFLOW_REINIT_ERROR_TITLE}}",
                msg: "{{i18n PLUGINS_WORKFLOW_REINIT_MSG_ERROR_NO_SAVE}}",
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.ERROR
            });
        }
    },
    
    /**
     * Callback function called after {@link #saveChanges} has been processed.
     * @param {Object} response The text response provided by the {@link Ametys.data.ServerComm}
     * @private
     */
    _saveChangesCB: function(response)
    {
        if(!response.message)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.plugins.workflow.tools.WorkflowEditorTool.WORKFLOW_SAVED,
                targets: {
                    id: Ametys.message.MessageTarget.WORKFLOW_OBJECT,
                    parameters: {
                        id: response.workflowId
                    }
                }
            });
            
            Ametys.Msg.confirm("{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_TITLE}}",
                "{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_MSG}}",
                function(btn)
                {
                    if (btn == 'yes')
                    {
                        Ametys.reload();
                    }  
                },
                this
            );
        }
        else
        {
            var msg ="";
            var invalids = "";
            if (response.invalidTransitions)
            {
                invalids = "<ul>";
                for (let action of response.invalidTransitions)
                {
                    invalids += "<li>" + action + "</li>";
                }
                invalids += "</ul>";
            }
            if (response.message == "file-not-found")
            {
                msg = "{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_MSG_ERROR_FILE_NOT_FOUND}}"
            }
            else if (response.message == "sax-error")
            {
                msg = "{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_MSG_ERROR_SAX_CATALOG}}"
            }
            else if (response.message == "empty-initials-actions")
            {
                msg = "{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_MSG_ERROR_EMPTY_INITIALS_ACTIONS}}"
            }
            else if (response.message == "empty-condition-operator")
            {
                msg = Ext.String.format("{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_MSG_ERROR_EMPTY_CONDITION_OPERATOR}}", invalids);
            }
            else if (response.message == "empty-conditionnal-result")
            {
                msg = Ext.String.format("{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_MSG_ERROR_EMPTY_CONDITIONNAL_RESULT}}", invalids);
            }
            else if (response.message == "empty-result-operator")
            {
                msg = Ext.String.format("{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_MSG_ERROR_EMPTY_RESULT_OPERATOR}}", invalids);
            }

            Ametys.Msg.show({
                title: "{{i18n PLUGINS_WORKFLOW_SAVE_CHANGES_ERROR_TITLE}}",
                msg: msg,
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.ERROR
            });
        }
    },
    
    /**
     * Callback function called after {@link #createWorkflow} has been processed.
     * @param {Object} response The text response provided by the {@link Ametys.data.ServerComm}
     * @private
     */
    _createWorkflowCB: function(response)
    {
        if (response.message && response.message == 'duplicate-id')
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_WORKFLOW_CREATE_ERROR_TITLE}}",
                msg: "{{i18n PLUGINS_WORKFLOW_CREATE_WORKFLOW_DIALOG_ID_ERROR}}",
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.ERROR
            });
        }
        else
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.CREATED,
                targets: {
                    id: Ametys.message.MessageTarget.WORKFLOW_OBJECT,
                    parameters: {
                        id: response.workflowId
                    }
                }
            });
        }
    },
    
    /**
     * Callback function called after {@link #renameWorkflow} has been processed.
     * @param {Object} response The text response provided by the {@link Ametys.data.ServerComm}
     * @private
     */
    _renameWorkflowCB: function(response)
    {
        
        Ext.create('Ametys.message.Message', {
            type: Ametys.message.Message.MODIFIED,
            targets: {
                id: Ametys.message.MessageTarget.WORKFLOW_OBJECT,
                parameters: {
                    id: response.workflowId
                }
            }
        });
    },
    
    /**
     * Callback function called after {@link #duplicateWorkflow} has been processed.
     * @param {Object} response The text response provided by the {@link Ametys.data.ServerComm}
     * @private
     */
    _duplicateWorkflowCB: function(response)
    {
        if (response.message)
        {
            var msg = "";
            if (response.message == 'duplicate-id')
            {
                msg = "{{i18n PLUGINS_WORKFLOW_CREATE_WORKFLOW_DIALOG_ID_ERROR}}";
            }
            else if (response.message == 'no-save')
            {
                msg = "{{i18n PLUGINS_WORKFLOW_CREATE_WORKFLOW_DIALOG_NO_SAVE_ERROR}}";
            }
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_WORKFLOW_CREATE_ERROR_TITLE}}",
                msg: msg,
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.ERROR
            });
        }
        else
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.CREATED,
                targets: {
                    id: Ametys.message.MessageTarget.WORKFLOW_OBJECT,
                    parameters: {
                        id: response.workflowId
                    }
                }
            });
        }
    },
    
    /**
     * @private
     * Convert function called after #getWorkflowRootProperties is processed
     * @param {Object} workflowProperties The server response
     */
    _convertWorkflowProperties: function (workflowProperties)
    {
        return Ext.create ('Ametys.plugins.workflow.messages.Workflow', workflowProperties);
    }
});