/*
 *  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 treePanel for WorkflowEditorTool
 */
Ext.define('Ametys.plugins.workflow.trees.WorkflowEditorTree', {
    extend: 'Ext.tree.Panel',
    
    statics: {
        /**
         * Workflow label renderer
         * @param {Object} value The data value
         * @param {Object} metaData A collection of metadata about the current cell
         * @param {Ext.data.Model} record The record
         * @return {String} The html representation of the targets
         */
        renderLabels: function(value, metaData, record)
        {
            var data = record.getData();
            var label = data.label;
            if (!record.isRoot())
            {
                label += ' ('+ data.elementId + ')';
            }
            return label;
        },
        
        /**
         * Workflow target renderer
         * @param {Object} value The data value
         * @param {Object} metaData A collection of metadata about the current cell
         * @param {Ext.data.Model} record The record
         * @return {String} The html representation of the targets
         */
        renderTargets: function(value, metaData, record)
        {
            var data = record.getData();
            var html = "";
            for (var key in data.targetedStepNames)
            {
                html += '<img src="' + data.targetedStepIcons[key] +  '" class="a-grid-icon a-grid-icon-workflow"/> ' + data.targetedStepNames[key] + ' ('+ key + ')<br/>';
            };
            return html;
        }
    },
    
    constructor: function(config)
    {
        config.store = this._createStore(config);
        var plugins = config.plugins;
        config.plugins = Ext.isArray(plugins) ? plugins : (plugins == null ? [] : [plugins]);
        if (config.allowEdition)
        {
            config.plugins.push({
                ptype: 'cellediting',
                clicksToEdit: 1,
                editAfterSelect: true,
                listeners: {
                    'beforeedit': this._onBeforeEdit,
                    'edit': this._onEdit,
                    scope: this
                }
            });
        }
        this.callParent(arguments);
    },
    
    /**
     * Init root node
     * @param {String} label title of the workflow
     */
    initRootNodeParameter: function (workflowName, label, hasChanges)
    {
        this._workflowName = workflowName;
        this.setRootNode({
            type: 'root',
            text: label,
            label: label,
            hasChanges: hasChanges,
            iconCls: 'a-tree-glyph ametysicon-workflow',
            expanded: false
        });
        this.getSelectionModel().select(0);
    },

    /**
     * Creates the workflow editor tree store
     * @param {Object} config The configuration
     * @return {Ext.data.Store} The workflow store
     * @private
     */
    _createStore: function(config)
    {
        var store = Ext.create('Ext.data.TreeStore', {
            model: 'Ametys.plugins.workflow.models.WorkflowTreeModel',
            sorters: [
                {property: 'text', direction:'ASC'}
            ],
            
            proxy: {
                type: 'ametys',
                role: 'org.ametys.plugins.workflow.dao.WorkflowStepDAO',
                methodName: 'getStepNodes',
                methodArguments: ["nodeId", "workflowName"],
                reader: {
                    type: 'json',
                    rootProperty: 'steps'
                }
            },
            listeners: {
                'beforeload': {fn: this._onBeforeLoad, scope: this},
                'load': {fn: this._initCache, scope: this}
            },
            autoLoad: false,
            root: {
                id: 'root',
                expanded: false
            }
        });
        return store;
    },

    /**
     * Function called before loading the store
     * @param {Ext.data.Store} store The store
     * @param {Ext.data.operation.Operation} operation The object that will be passed to the Proxy to load the store
     * @private
     */
    _onBeforeLoad: function(store, operation)
    {
        operation.setParams(Ext.apply(operation.getParams() || {}, {
            nodeId: operation.node.getId(),
            workflowName: this._workflowName
        }));
    },
    
    /**
     * @private
     * Initialize the workflow cache
     * @param {Ext.tree.Panel} tree the current tree
     * @param {Object} records the content of the tree store
     */
    _initCache: function(tree, records)
    {
        var steps = {};
        var transitions = {};
        for (var i in records)
        {
            var record = records[i].data;
            if (record.elementType == "step")
            {
                steps[record.elementId] = record.label;
            }
            else if (record.elementType == "action")
            {
                transitions[record.elementId] = record.label;
            }
            
        }
    },
    
    /**
     * @private
     * Listener called before cell editing 
     * @param {Ext.grid.plugin.CellEditing} editor The cell editor
     * @param {Object} context An editing context event with the following properties:
     * @param {Ext.data.Model} context.record The record being edited.
     */
    _onBeforeEdit: function(editor, context)
    {
        var record = context.record;
        return record && !record.isRoot() && record.getData().id != "step0" && record.canWrite;
    },
    
    /**
     * @private
     * Listener called after cell editing
     * @param {Ext.grid.plugin.CellEditing} editor The cell editor
     * @param {Object} context An editing context with the following properties:
     * @param {Ext.data.Model}         context.record The record being edited.
     * @param {Mixed}                  context.value The field's current value.
     * @param {Mixed}                  context.originalValue The original value before being edited.
     */
    _onEdit: function(editor, context)
    {
        var record = context.record,
            newName = context.value,
            oldName = context.originalValue;
        
        if (newName != oldName)
        {
            var elementId = parseInt(record.getData().elementId);
            var elementType = record.getData().elementType;
            if (elementType == "step")
            {
                Ametys.plugins.workflow.dao.WorkflowStepDAO.editStepLabel(
                    [this._workflowName, parseInt(elementId), newName],
                    Ext.bind(renameCb, this)
                );
            }
            else
            {
                var stepId = record.parentNode.getData().elementId;
                Ametys.plugins.workflow.dao.WorkflowTransitionDAO.editTransitionLabel(
                    [this._workflowName, parseInt(stepId), parseInt(elementId), newName],
                    Ext.bind(renameCb, this)
                );
            }
            
            function renameCb(response)
            {
                if (!response || !response.workflowName)
                {
                    // edit failed
                    record.beginEdit();
                    record.set('text', oldName);
                    record.endEdit();
                    record.commit();
                }
            }
        }
    },
    
    /**
     * Listener on WorkflowElementSelected
     * @param {Ametys.message.MessageTarget} target The message target
     * @param {Function} cb The callback
     */
    onWorkflowElementSelected: function(nodeId)
    {
        var tree = this,
            store = tree.getStore(),
            selModel = tree.getSelectionModel(),
            selection = selModel.getSelection(),
            record = store.getById(nodeId);
        
        if (record)
        {
            if (selection.length > 0 && record == selection[0])
            {
                // same selection
                return;
            }
            selModel.select(record);
            this.getView().focusNode(record);
            //tree is expanded at initiation record should never be null
        }
    },
    
    /**
     * Listener on workflow element created or modified, reload the tree and select new element on edition mode
     * @param {String} editedId id of the edited node
     * @param {String} parentNodeId id of the edited node's parent
     * @param {Boolean} cellEditing true to open edited node in cell edition
     */
    onWorkflowElementModified: function(editedId, parentNodeId, cellEditing)
    {
        var tree = this;
        var selModel = tree.getSelectionModel();
        var store = tree.getStore();
        var parentNode = store.getById(parentNodeId);
        
        store.load({
            scope: tree,
            callback: function () 
            {
                this.expandAll(selectNewNode, tree);
            }
        });
        function selectNewNode()
        {
            if(parentNode == null)
            {
                parentNode = store.getRootNode();
            }
            var path = parentNode.getPath();
            tree.expandPath(path, {
                field: "id", 
                separator: "/", 
                callback: function (successful, parentNode) {
                    if (successful)
                    {
                        var node = store.getById(editedId);
                        selModel.select(node);
                        if (cellEditing && tree.editingPlugin)
                        {
                            tree.editingPlugin.startEdit(node, 0);
                        }
                    }
                }
            })
        }
    }
    
});