/*
 *  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.
 */
 
/**
 * Class for managing conditions
 */
Ext.define('Ametys.plugins.workflow.actions.WorkflowConditionAction', {
    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 {String} _actionId id of current action parent
    */
    
    /**
    * @private
    * @property {String} _nodeId id of current condition node
    */
    
    /**
    * @private
    * @property {Object} _paramValues map of the condition arguments and their values 
    */
    
    /**
    * @private
    * @property {Ametys.window.DialogBox} _conditionBox the creation / edition dialog box for conditions
    */

    /**
    * @private
    * @property {Ametys.form.ConfigurableFormPanel} _formParams the configurable form for condition's other arguments
    */
    
    /**
     * Add a new operator "AND"
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    addOperatorALL: function(controller)
    {
        var target = Ametys.message.MessageTargetHelper.findTarget(controller.getMatchingTargets());
        var targetOperator = target ? target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_CONDITIONS_OPERATOR}) : null;
        if (!targetOperator)
        {
            return;
        }
        var targetParameters = targetOperator.getParameters(),
            workflowName = targetParameters.workflowId,
            nodeId = targetParameters.nodeId,
            stepId = targetParameters.stepId
            actionId = targetParameters.actionId;
        Ametys.plugins.workflow.dao.WorkflowConditionDAO.addOperator([workflowName, parseInt(stepId), parseInt(actionId), nodeId, "AND", nodeId.startsWith('step')]); 
    },
    
    /**
     * Add a new operator "OR"
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    addOperatorANY: function(controller)
    {
        var target = Ametys.message.MessageTargetHelper.findTarget(controller.getMatchingTargets());
        var targetAction = target ? target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_ACTION}) : null;
        if (!targetAction)
        {
            return;
        }
        var workflowName = targetAction.getParameters().workflowId;
        var stepId = targetAction.getParameters().stepId;
        var actionId = targetAction.getParameters().id;
        var targetResult = target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_RESULT});
        var targetCondition = target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_CONDITIONS_OPERATOR});
        var isResultCondition = targetResult != null || (targetCondition != null && targetCondition.getParameters().nodeId.startsWith("step"));
        var nodeId = (targetCondition != null) 
            ? targetCondition.getParameters().nodeId 
            : targetResult != null
                ? targetResult.getParameters().nodeId 
                : null; 
        
        Ametys.plugins.workflow.dao.WorkflowConditionDAO.addOperator([workflowName, parseInt(stepId), parseInt(actionId), nodeId, "OR", isResultCondition]); 
    },
    
    /**
     * Add a condition
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    addCondition: function(controller)
    {
        var target = Ametys.message.MessageTargetHelper.findTarget(controller.getMatchingTargets());
        var targetAction = target ? target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_ACTION}) : null;
        if (!targetAction)
        {
            return; 
        }
        var targetResult = target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_RESULT});
        var targetCondition = target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_CONDITIONS_OPERATOR});
        
        var isResultCondition = targetResult != null;
        this._nodeId = (targetCondition != null) 
            ? targetCondition.getParameters().nodeId 
            : isResultCondition 
                ? targetResult.getParameters().nodeId 
                : null; 
        
        this._actionId = targetAction.getParameters().id;
        this._stepId = targetAction.getParameters().stepId;
        this._workflowName = targetAction.getParameters().workflowId;
        this._mode = "new";
        this._paramValues = {};
        if (!this._formParams)
        {
            Ametys.plugins.workflow.dao.WorkflowConditionDAO.getConditionsModel([], Ext.bind(this._initDialogBox, this));
        }
        else
        {
            this._formParams.reset();
            this._conditionBox.setTitle("{{i18n PLUGINS_WORKFLOW_ADD_CONDITION_DIALOG_TITLE}}");
            this._conditionBox.show();
        }
    },
    
    /**
     * Initialize and open the dialog box
     * @param {Object} response the server response
     * @param {Object} response.parameters.elements the fields to configure
     */
    _initDialogBox: function(response)
    {
        var cfpConfig = {
            hideDisabledFields: true,
            tabPosition: 'top',
            layout: 'fit',
            itemsLayout: 'fit',
            tabItemsLayout: 'anchor',
            scrollable: false,
            spacingCls: false,
            labelAlign: 'top',
            defaultFieldConfig: {
                labelSeparator: '',
                labelWidth: 120,
                labelStyle: "font-weight:bold",
                width: 500,
                cls: 'ametys',
                anchor: '100%'
            },
        };
    
        this._formParams = Ext.create('Ametys.form.ConfigurableFormPanel', cfpConfig);
        this._formParams.configure(response.parameters.elements);
        this._conditionBox = Ext.create('Ametys.window.DialogBox',  {
            title : this._mode == "new" 
                ? "{{i18n PLUGINS_WORKFLOW_ADD_CONDITION_DIALOG_TITLE}}"
                : "{{i18n PLUGINS_WORKFLOW_EDIT_CONDITION_DIALOG_TITLE}}",
            iconCls: "ametysicon-code-misc-binary",
            
            layout: 'anchor',
            items : [
                this._formParams
            ],
            
            closeAction: 'hide',
            
            referenceHolder: true,
            defaultButton: 'validate',
            
            buttons : [
                {
                    reference: 'validate',
                    itemId:'validateCondition',
                    text: "{{i18n PLUGINS_WORKFLOW_CREATE_DIALOG_OK_BTN}}",
                    handler: Ext.bind(this._ok, this)
                },
                {
                    text: "{{i18n PLUGINS_WORKFLOW_CREATE_DIALOG_CANCEL_BTN}}",
                    handler: Ext.bind(this._hideDialogBox, this)
                }
            ]
        });
        
        if (this._mode == "new")
        {
            this._formParams.setValues(); // setValues must always be called for configurable form panel in order to complete its initialization
            this._conditionBox.show();
        }
        else
        {
            Ametys.plugins.workflow.dao.WorkflowConditionDAO.getConditionParametersValues([this._workflowName, parseInt(this._actionId), this._nodeId], Ext.bind(this._setValues, this)); 
        }
    },
    
    /**
     * @private
     * Send the changes to server
     */
    _ok: function ()
    {
        this._paramValues = this._formParams.getJsonValues();
        var invalids = this._formParams.getInvalidFields();
        if (invalids.length)
        {
            return;
        }
        for (var argName in this._paramValues)
        {
            if (this._paramValues[argName] == "")
            {
                delete this._paramValues[argName];
            }
        }
        
        this._mode == "new"
            ? Ametys.plugins.workflow.dao.WorkflowConditionDAO.addCondition([this._workflowName, parseInt(this._stepId), parseInt(this._actionId), this._nodeId, this._paramValues], this._hideDialogBox, {scope: this})
            : Ametys.plugins.workflow.dao.WorkflowConditionDAO.editCondition([this._workflowName, parseInt(this._stepId), parseInt(this._actionId), this._nodeId, this._paramValues], this._hideDialogBox, {scope: this});
    },
    
    /**
     * Hide the dialog box
     */
    _hideDialogBox: function ()
    {
        this._conditionBox.hide();
    },
    
    /**
     * Delete selected operator
     * @param {Ametys.message.MessageTarget} target The operator target
     */
    deleteOperator: function(target)
    {
        var targetParameters = target.getParameters();
        this._workflowName = targetParameters.workflowId;
        this._nodeId = targetParameters.nodeId;
        this._actionId = targetParameters.actionId;
        this._stepId = targetParameters.stepId;
        
        Ametys.plugins.workflow.dao.WorkflowConditionDAO.hasChildConditions([this._workflowName, parseInt(this._actionId), this._nodeId], Ext.bind(this._deleteOperatorCB, this, [target], 1))
    },
    
    /**
      * @private
      * Callback of deleteOperator, send confirmation message for removal
      * @param {Boolean} hasChildren, if operator to delete has children
      * @param {Ametys.message.MessageTarget} target the condition operator to remove
      */
    _deleteOperatorCB: function(hasChildren, target)
    {
        var targetParameters = target.getParameters(),
            type = targetParameters.type,
            typeLabel = type == "AND"? "{{i18n PLUGIN_WORKFLOW_TRANSITION_CONDITIONS_TYPE_AND}}" : "{{i18n PLUGIN_WORKFLOW_TRANSITION_CONDITIONS_TYPE_OR}}",
            msg = hasChildren 
                ? Ext.String.format("{{i18n PLUGINS_WORKFLOW_DELETE_OPERATOR_WITH_CHILDREN_CONFIRM}}", typeLabel)
                : Ext.String.format("{{i18n PLUGINS_WORKFLOW_DELETE_OPERATOR_CONFIRM}}", typeLabel)

        Ametys.Msg.confirm("{{i18n PLUGINS_WORKFLOW_DELETE_OPERATOR_LABEL}}",
            msg,
            Ext.bind(this._doDeleteOperator, this),
            this
        );
    },
    
    /**
     * @private
     * Proceed to the operator removal
     * @param {String} btn The pressed button. Can only be 'yes'/'no'
     */
    _doDeleteOperator: function(btn)
    {
        if (btn == 'yes')
        {
            Ametys.plugins.workflow.dao.WorkflowConditionDAO.deleteOperator([this._workflowName, parseInt(this._stepId), parseInt(this._actionId), this._nodeId]); 
        }  
    },
    
    /**
     * Edit selected condition
     * @param {Ametys.message.MessageTarget} target The condition target
     */
    editCondition: function(target)
    {
        this._mode = "edit";
        var targetParameters = target.getParameters();
        this._workflowName = targetParameters.workflowId,
        this._actionId = targetParameters.actionId;
        this._stepId = targetParameters.stepId;
        this._nodeId = targetParameters.nodeId;
        if (!this._formParams)
        {
            Ametys.plugins.workflow.dao.WorkflowConditionDAO.getConditionsModel([], Ext.bind(this._initDialogBox, this));
        }
        else
        {
            Ametys.plugins.workflow.dao.WorkflowConditionDAO.getConditionParametersValues([this._workflowName, parseInt(this._actionId), this._nodeId], Ext.bind(this._setValues, this)); 
        }
        
    },
    
    /**
     * @private
     * Set formParams with current values
     * @param {Object} response the server response
     * @param {Object} response.parametersValues the values to set the fields with
     */
    _setValues: function(response)
    {
        this._formParams.setValues({"values": response.parametersValues});
        this._conditionBox.setTitle("{{i18n PLUGINS_WORKFLOW_EDIT_CONDITION_DIALOG_TITLE}}")
        this._conditionBox.show();
    },
    
    /**
     * Delete selected condition
     * @param {Ametys.message.MessageTarget} target The condition target
     */
    deleteCondition: function(target)
    {
        var targetParameters = target.getParameters();
        this._workflowName = targetParameters.workflowId;
        this._nodeId = targetParameters.nodeId,
        this._actionId = targetParameters.actionId;
        this._stepId = targetParameters.stepId;
        
        Ametys.plugins.workflow.dao.WorkflowConditionDAO.getConditionLabel([this._workflowName,  parseInt(this._actionId), this._nodeId], Ext.bind(this._deleteConditionCB, this)); 
    },
    
    /**
      * @private
      * Callback of deleteCondition, send confirmation message for deletion
      * @param {Object} label condition to remove's label
      */
    _deleteConditionCB: function(label)
    {
        var msg = Ext.String.format("{{i18n PLUGINS_WORKFLOW_DELETE_CONDITION_CONFIRM}}", label);
        
        Ametys.Msg.confirm("{{i18n PLUGINS_WORKFLOW_DELETE_CONDITION_LABEL}}",
                msg,
                Ext.bind(this._doRemove, this),
                this
        );
    },
    
    /**
     * @private
     * Proceed to the condition deletion
     * @param {String} btn The pressed button. Can only be 'yes'/'no'
     */
    _doRemove: function(btn)
    {
        if (btn == 'yes')
        {
            Ametys.plugins.workflow.dao.WorkflowConditionDAO.deleteCondition([this._workflowName, parseInt(this._stepId), parseInt(this._actionId), this._nodeId]); 
        }   
    }
});