/*
 *  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.
 */
 
 /**
 * Actions on workflow steps
 */
Ext.define('Ametys.plugins.workflow.actions.WorkflowStepAction', {
    singleton: true,
    
    /**
    * @private
    * @property {String} _mode 'new' or 'edit' 
    */
    
    /**
    * @private
    * @property {String} _workflowName id of the workflow
    */
    
    /**
    * @private
    * @property {String} _stepId id of current step parent
    */
   
    /**
    * @private
    * @property {Number[]} _unavailableIds array of unavailable ids for steps
    */
   
    /**
    * @private
    * @property {Ametys.window.DialogBox} _dialogBox the edition dialog box for steps
    */
    
    /**
     * Add a new step to workflow
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    add: function(controller)
    {
        var target = Ametys.message.MessageTargetHelper.findTarget(controller.getMatchingTargets(), Ametys.message.MessageTarget.WORKFLOW_OBJECT);
        if (!target)
        {
            return;
        }
        
        this._workflowName = target.getParameters().id;
        this._mode = "new";
        
        Ametys.plugins.workflow.dao.WorkflowStepDAO.getStepInfos([this._workflowName, null], Ext.bind(this._getStepInfosCB, this));
    },
    
    /**
     * Get step infos before opening the edition dialog box
     * @param {Ametys.message.MessageTarget} target The step target
     */
    edit: function(target)
        {
        var targetParameters = target.getParameters();
        this._stepId = targetParameters.id;
        this._workflowName = targetParameters.workflowId;
        this._mode = "edit";
        
        Ametys.plugins.workflow.dao.WorkflowStepDAO.getStepInfos([this._workflowName, parseInt(this._stepId)], Ext.bind(this._getStepInfosCB, this));
    },
    
    /**
      * @private
      * Callback of getStepInfos, init dialog box and fill form with current values
      * @param {Object} response the step form init values 
      */   
    _getStepInfosCB(response)
    {
        if (!this._dialogBox)
        {
            this._dialogBox = this._initDialogBox();
        }
        else
        {
            this._dialogBox.setTitle(this._mode == "new" ? "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_TITLE}}" : "{{i18n PLUGINS_WORKFLOW_EDIT_STEP_DIALOG_TITLE}}");
        }
        this._initFieldValues(response);
    },
    
    /**
     * @private
     * Init the dialog box
     * @param form the form
     * @returns {Ametys.window.DialogBox} the dialog box
     */
    _initDialogBox: function(form)
    {
        return Ext.create('Ametys.window.DialogBox',  {
            title : this._mode == "new" ? "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_TITLE}}" : "{{i18n PLUGINS_WORKFLOW_EDIT_STEP_DIALOG_TITLE}}",
            iconCls: "ametysicon-code-html-input-checkbox-off",
            width:400,
            layout: 'anchor',
            selectDefaultFocus: true,
            defaultFocus: 'label',
            defaults:
            {
                msgTarget: "side",
                cls: 'ametys',
                padding: 5,
                anchor: '100%',
                labelAlign: "top",
                labelSeparator: "",
                labelStyle: "font-weight:bold",
            },
            items : [
                {
                    name: 'label',
                    itemId: 'label',
                    xtype:'multilingualstring',
                    fieldLabel: "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_LABEL}} *",
                    ametysDescription: "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_LABEL_DESC}}",
                    allowBlank: false
                },
                {
                    name: 'stepId',
                    itemId: 'stepId',
                    xtype: 'numberfield',
                    fieldLabel: "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_ID}} *",
                    ametysDescription: "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_ID_DESC}}",
                    allowBlank: false,
                    allowDecimals: false,
                    validator: Ext.bind(this._idValidator, this)
                }
            ],
            
            closeAction: 'hide',
            
            referenceHolder: true,
            defaultButton: 'validate',
            
            buttons : [
                {
                    reference: 'validate',
                    text: "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_OK_BTN}}",
                    handler: Ext.bind(this._ok, this)
                },
                {
                    text: "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_CANCEL_BTN}}",
                    handler: Ext.bind(this._hideDialogBox, this)
                }
            ]
        });
    },
    
    _idValidator: function(stepId)
    {
        return this._unavailableIds.includes(parseInt(stepId)) 
            ? "{{i18n PLUGINS_WORKFLOW_CREATE_STEP_DIALOG_ID_ERROR}}" 
            : true;
    },
    
    /**
     * @private
     * Init dialog box fields with  server values
     * @param {Object} response the server response with the step values
     * @param {String[]} response.ids array of ids used for others steps in this workflow 
     * @param {String} response.id the step's current id
     * @param {String} response.labels the step's current labels
     */
    _initFieldValues: function(response)
    {
        var i18nLabel = response.labels;
        var stepId = response.id;
        this._unavailableIds = response.ids;
        this._dialogBox.getComponent('label').setValue(!Ext.isEmpty(i18nLabel) ? i18nLabel : '');
        this._dialogBox.getComponent('stepId').setValue(stepId);
        this._dialogBox.show();
    },
    
    /**
     * @private
     * Save step changes 
     */
    _ok: function ()
    {
        if (this._hasInvalid(this._dialogBox))
        {
            return;
        }
        var stepId = this._dialogBox.getComponent('stepId').getValue();
        var label = this._dialogBox.getComponent('label').getValue();
        
        if (this._mode == "new")
        {
            Ametys.plugins.workflow.dao.WorkflowStepDAO.createStep([this._workflowName, stepId, label], Ext.bind(this._hideDialogBox, this));
        }
        else
        {
            Ametys.plugins.workflow.dao.WorkflowStepDAO.editStep([this._workflowName, parseInt(this._stepId), stepId, label], Ext.bind(this._hideDialogBox, this)); 
        }
    },
    
    /**
     * @private
     * Return true if a field is invalid
     * {Ametys.window.DialogBox} the dialog box
     */
    _hasInvalid: function(box)
    {
        var fields = box.query("[isFormField]");
        var hasInvalid = false;
        for (let field of fields)
        {
            if (!field.isValid())
            {
                hasInvalid = true;
            }
        }
        return hasInvalid;
    },
    
    /**
     * @private
     * Hide the dialog box
     * @param {Object} response the server response
     * @param {String} response.message an error message if defined
     */
    _hideDialogBox: function (response)
    {
        if (!response || !response.message)
        {
            this._dialogBox.hide();
        }
    },
    
    /**
     * Open confirm box to delete step
     * @param {Ametys.message.MessageTarget} target The step target
     */
    delete: function(target)
    {
        var stepId = target.getParameters().id;
        var stepLabel = target.getParameters().label;
        
        Ametys.Msg.confirm("{{i18n PLUGINS_WORKFLOW_DELETE_STEP_LABEL}}",
                Ext.String.format("{{i18n PLUGINS_WORKFLOW_DELETE_STEP_CONFIRM}}", stepLabel, stepId),
                Ext.bind(this._doDelete, this, [target], 1),
                this
        );
    },
    
    /**
     * @private
     * Delete the step 
     * @param {String} btn The pressed button. Can only be 'yes'/'no'
     * @param {Ametys.message.MessageTarget} target The step target to remove.
     */
    _doDelete: function(btn, target)
    {
        if (btn == 'yes')
        {
            var targetParameters = target.getParameters();
            this._stepId = targetParameters.id;
            this._workflowName = targetParameters.workflowId;
            
            Ametys.plugins.workflow.dao.WorkflowStepDAO.deleteStep([this._workflowName, parseInt(this._stepId)]);
        }   
    }
});