/*
 *  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 defining the editor tool for workflows
 */
Ext.define('Ametys.plugins.workflow.tools.WorkflowEditorTool', {
    extend: "Ametys.tool.Tool",
    
    statics:
    {
        /**
         * @readonly
         * @property {String} WORKFLOW_SAVED Event sent when the changes on a workflow have been saved 
         */
        WORKFLOW_SAVED: "workflowSaved",
    },
    
    displayWorkflowDetails: true,

    constructor: function(config)
    {
        this.callParent(arguments);
        Ametys.message.MessageBus.on(Ametys.message.Message.SELECTION_CHANGED, this._onSelectionChanged, this);
        Ametys.message.MessageBus.on(Ametys.message.Message.CREATED, this._onMessageCreatedOrModified, this);
        Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onMessageCreatedOrModified, this);
        Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onMessageDeleted, this);
        Ametys.message.MessageBus.on(Ametys.plugins.workflow.tools.WorkflowEditorTool.WORKFLOW_SAVED, this._onWorkflowSaved, this);
    },

    getMBSelectionInteraction: function() 
    {
        return Ametys.tool.Tool.MB_TYPE_ACTIVE;
    },
    
    setParams: function (params)
    {
        this.callParent(arguments);
        
        this._workflowName = params.id;
        Ametys.plugins.workflow.dao.WorkflowsDAO.getWorkflowRootProperties(
            [this._workflowName],
            Ext.bind(this._setParamCb, this)
        );
    },

    /**
     * @private
     * Callback function of setParams
     * @param {Object} response The server response
     * @param {String} response.label title of the workflow
     */
    _setParamCb: function (response)
    {
        var data = response.getConfig();
        if (response.error && (response.error == "workflow-unknown" || response.error == "cant-read"))
        {
            this.close();
        }
        else
        {
            this.setTitle(data.label);
            this._tree.initRootNodeParameter(this._workflowName, data.label, data.hasChanges);
            this.showOutOfDate();
        }
    },
    
    refresh: function()
    {
        this.showRefreshing();
        this._tree.getStore().load({
            scope: this,
            callback: function() {
                this._tree.expandAll();
                this.showRefreshed();
                this._tree.getSelectionModel().select(0);
            }
        });
    },

    sendCurrentSelection: function()
    {
        var selection = this._tree.getSelectionModel().getSelection();
        if (selection.length > 0)
        {
            var currentRecord = selection[0]; // multiselection is not supported
            var realTarget =[];
                
            if (currentRecord.isRoot())
            {
                realTarget = this._getMessageRootTargetConfiguration(currentRecord);
            }
            else if (currentRecord.getData().elementType == "step")
            {
                var workflowNode = this._tree.getStore().getNodeById(currentRecord.get('parentId'));
                realTarget = this._getMessageRootTargetConfiguration(workflowNode);
                realTarget.subtargets = this._getMessageStepTargetConfiguration(currentRecord);
            }
            else if (currentRecord.getData().elementType == "action")
            {
                var stepNode = this._tree.getStore().getNodeById(currentRecord.get('parentId'));
                var workflowNode = this._tree.getStore().getNodeById(stepNode.get('parentId'));
                
                realTarget = this._getMessageRootTargetConfiguration(workflowNode);
                var subtarget = this._getMessageStepTargetConfiguration(stepNode);
                subtarget.subtargets = this._getMessageActionTargetConfiguration(currentRecord, stepNode);
                realTarget.subtargets = subtarget;
            }
        }
        
        Ext.create('Ametys.message.Message', {
            type: Ametys.message.Message.SELECTION_CHANGED,
            targets: realTarget,
            parameters: {}
        });
    },

    /**
     * @private
     * Get the target configuration object for root record
     * @param {Ext.data.Model} record The tree root record to convert to its Ametys.message.MessageTarget configuration
     * @return {Object} The configuration to create a Ametys.message.MessageTarget. 
     */
    _getMessageRootTargetConfiguration: function (record)
    {
        return {
            id: Ametys.message.MessageTarget.WORKFLOW_OBJECT,
            parameters: {
                id: this._workflowName
            }
        };
    },
    
    /**
     * @private
     * Get the target configuration object for given step record
     * @param {Ext.data.Model} record The tree step record to convert to its Ametys.message.MessageTarget configuration
     * @return {Object} The configuration to create a Ametys.message.MessageTarget.
     */
    _getMessageStepTargetConfiguration: function (record)
    {
        return {
            id: Ametys.message.MessageTarget.WORKFLOW_STEP,
            parameters: {
                id: record.get("elementId"),
                label: record.get("label"),
                workflowId: this._workflowName
            },
        };
    },
    /**
     * @private
     * Get the target configuration object for given action record
     * @param {Ext.data.Model} record The tree action record to convert to its Ametys.message.MessageTarget configuration
     * @return {Object} The configuration to create a Ametys.message.MessageTarget. 
     */
    _getMessageActionTargetConfiguration: function (record, stepNode)
    {
        return {
            id: Ametys.message.MessageTarget.WORKFLOW_ACTION,
            parameters: {
                id: record.get('elementId'),
                label: record.get("label"),
                stepId: stepNode.get('elementId'),
                workflowId: this._workflowName
            }
        };
    },
    
    /**
     * Listener on selection messages, update tree selection
     * @param {Ametys.message.Message} message The selection message.
     * @private
     */
    _onSelectionChanged: function (message)
    {
        var target = message.getTarget(Ametys.message.MessageTarget.WORKFLOW_OBJECT);
        
        if (target != null)
        {
            if (target.getParameters().id == this._workflowName)
            {
                var targetStep = target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_STEP});
                var nodeId = "root";
                if (targetStep != null)
                {
                    var stepId = targetStep.getParameters().id;
                    nodeId = stepId =="step0" ? stepId : "step" + stepId; 
                    var targetAction = targetStep.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_ACTION});
                    if (targetAction != null)
                    {
                        nodeId = nodeId + "-action" + targetAction.getParameters().id;
                    }
                }
                this._tree.onWorkflowElementSelected(nodeId);
            }
        }
    },
    
    /**
     * Listener on created and modified messages, select the new element
     * @param {Ametys.message.Message} message The selection message.
     * @private
     */
    _onMessageCreatedOrModified: function(message)
    {
        var targets = message.getTargets(function(target) {
            return target.getId() == Ametys.message.MessageTarget.WORKFLOW_OBJECT
        });
        
        if (targets.length)
        {
            if (targets[0].getParameters().id == this._workflowName)
            {
                this.setDirty(true);
                if (!this._tree.getRootNode().get("hasChanges") && targets[0].getParameters().hasChanges)
                {
                    this._tree.getRootNode().set('hasChanges', true);
                }
                var targetStep = targets[0].getSubtarget(function(target) {
                    return target.getId() == Ametys.message.MessageTarget.WORKFLOW_STEP
                });
                if (targetStep != null)
                {
                    var parentId = "root"
                    var stepId = targetStep.getParameters().id;
                    var createdId = stepId.toString().includes("step")? stepId : "step" + stepId; 
                    var targetAction = targetStep.getSubtarget(function(target) {
                        return target.getId() == Ametys.message.MessageTarget.WORKFLOW_ACTION
                    });
                    if (targetAction != null)
                    {
                        parentId = createdId;
                        createdId = createdId + "-action" + targetAction.getParameters().id;
                    }
                    this._tree.onWorkflowElementModified(createdId, parentId, message.getType() == "created"); 
                }
                else
                {
                    this.showOutOfDate();
                }
            }
        }
    },
    
    /**
     * Listener on workflow saved messages, set the tool clean
     * @param {Ametys.message.Message} message The selection message.
     * @private
     */
    _onWorkflowSaved: function(message)
    {
        this._tree.getRootNode().set('hasChanges', false);
        this.setDirty(false);
    },
    
    /**
     * Listener on deleted messages, set the tool dirty
     * @param {Ametys.message.Message} message The selection message.
     * @private
     */
    _onMessageDeleted: function(message)
    {
        var targets = message.getTargets();
        if (targets.length)
        {
            if (targets[0].getParameters().id == this._workflowName || targets[0].getParameters().id ==this._workflowName)
            {
                if (!this._tree.getRootNode().get("hasChanges"))
                {
                    this.setDirty(true);
                    this._tree.getRootNode().set('hasChanges', true);
                }
            }
        }
    },
    
    createPanel: function()
    {
        this._tree = Ext.create("Ametys.plugins.workflow.trees.WorkflowEditorTree", { 
            rootVisible: true,
            stateful: true,         
            stateId: this.self.getName() + "$tree&" + this._workflowName ,     
            scrollable: true,
            allowEdition: true,
            cls: 'uitool-workflow-editor',
            columns: [
                  {
                      xtype: 'treecolumn', 
                      header: "{{i18n PLUGINS_WORKFLOW_UITOOL_WORKFLOW_EDITOR_COLUMN_LABEL}}",
                      flex: 0.6,
                      sortable: true, 
                      dataIndex: 'label', 
                      editor: {
                          xtype: 'textfield',
                          allowBlank: false,
                          selectOnFocus: true
                      },
                      renderer: Ametys.plugins.workflow.trees.WorkflowEditorTree.renderLabels
                  },
                  {
                      header: "{{i18n PLUGINS_WORKFLOW_UITOOL_WORKFLOW_EDITOR_COLUMN_ID}}", 
                      sortable: true, 
                      flex : 0.1,
                      hidden: true,
                      dataIndex: 'elementId', 
                      align: 'left',
                  },
                  {
                      header: "{{i18n PLUGINS_WORKFLOW_UITOOL_WORKFLOW_EDITOR_COLUMN_FINAL_STEP}}", 
                      sortable: false, 
                      flex : 0.3,
                      multiple: true, 
                      dataIndex: 'targetedStep', 
                      align: 'left',
                      renderer: Ametys.plugins.workflow.trees.WorkflowEditorTree.renderTargets
                  }
            ],
            
            listeners: {                
                selectionchange: this.sendCurrentSelection,
                itemdblclick: function(view, record)
                {
                    var data = record.getData();
                    if (record.isRoot())
                    {
                        Ametys.tool.ToolsManager.openTool("uitool-workflow-preview", {workflowId: this._workflowName, elementType: "workflow"});
                    }
                    else if (data.elementType == "action")
                    {
                        var stepNode = this._tree.getStore().getNodeById(data.parentId);
                        Ametys.tool.ToolsManager.openTool("uitool-workflow-preview", {
                            workflowId: this._workflowName,
                            elementType: "action", 
                            stepId: stepNode.getData().elementId, 
                            stepLabel: stepNode.getData().label, 
                            actionId: data.elementId, 
                            actionLabel: data.label
                        });
                    }
                    else if (data.elementType == "step")
                    {
                        Ametys.tool.ToolsManager.openTool("uitool-workflow-preview", {workflowId: this._workflowName, elementType: "step", stepId: data.elementId, stepLabel: data.label});
                    }
                },
                scope: this
            }
        });
        
        return this._tree;
    }
    
 });