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

/**
 * This tool display the list of all existing workflows
 */
 Ext.define('Ametys.plugins.workflow.tools.WorkflowsSearchTool', {
     extend: "Ametys.tool.Tool",

    displayWorkflowOverflow: true,

    /**
    * @private
    * @property {String} _workflowName id of currently selected workflow
    */
   
    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.plugins.workflow.tools.WorkflowEditorTool.WORKFLOW_SAVED, this.showOutOfDate, this);
    },
    
    getMBSelectionInteraction: function()
    {
        return Ametys.tool.Tool.MB_TYPE_ACTIVE;
    },
    
    sendCurrentSelection : function()
    {
        var selection = this._panel.getSelectionModel().getSelection();
        if(selection.length > 0){
            var currentRecord = selection[0].getData();
            var target = {
                id: Ametys.message.MessageTarget.WORKFLOW_OBJECT,
                parameters: { 
                    id: currentRecord.id,
                }
            };
        }
        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.SELECTION_CHANGED,
            targets: target
        });
    },
    
    createPanel: function()
    {
        this._panel = Ext.create('Ext.grid.Panel', {
            cls: 'workflow-search-tool',
            stateful: true,
            stateId: this.self.getName() + "$workflowgrid",
            store: this._createStore(), 
            columns: [
                {
                    dataIndex: "title",
                    text: "{{i18n plugin.workflow:PLUGINS_WORKFLOW_COLUM_TITLE_LABEL}}",
                    sortable: true,
                    width: 250, 
                    renderer: this._renderTitles
                },{
                    dataIndex: "id",
                    text: "{{i18n plugin.workflow:PLUGINS_WORKFLOW_COLUM_ID_LABEL}}",
                    sortable: true,
                    hidden: true,
                    width: 150
                }
            ],
            viewConfig: {
                getRowClass: Ext.bind(this._getRowClass, this)
            }
        });
        this._panel.on('selectionchange', this.sendCurrentSelection, this);
        this._panel.on('itemdblclick', this._openWorkflowEditorTool, this);
        
        return this._panel;
    },
    
    /**
     * Render the workflow title so it would show if workflow has unsaved changes
     * @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 title
     */
    _renderTitles: function(value, metaData, record)
    {
        return '<span class="a-grid-glyph ametysicon-workflow"></span>' + record.getData().title;
    },
    
    /**
     * @private
     * Determine a row CSS class depending upon the record
     * @param {Ext.data.Model} record The record
     * @return {String} The CSS classname to apply
     */
    _getRowClass: function(record)
    {
        return record.getData().hasChanges ? "row-modified" : "";
    },

    setParams: function (params)
    {
        this.callParent(arguments);
        this.showOutOfDate();
    },
    
    /**
     * Open an editor tool for selected workflow
     * @param {Object} record : record of selected row
     * @private
     */
    _openWorkflowEditorTool: function(view, record)
    {
        var data = record.getData();
        Ametys.tool.ToolsManager.openTool("uitool-workflow-editor", {id: data.id, title: data.title});
        Ametys.tool.ToolsManager.openTool("uitool-workflow-preview", {workflowId: data.id, elementType: "workflow"});
    },
    
    /**
     * Create the grid's store
     * @returns {Object} the search grid's store
     * @private 
     */
    _createStore: function()
    {
        var store = Ext.create('Ext.data.Store', {
            model: Ametys.plugins.workflow.WorkflowGridModel,
            sorters: [{
                property: 'type',
                direction: 'ASC'
            },
            {
                property: 'title',
                direction: 'ASC'
            }, 
            {
                property:'id',
                direction: 'ASC'
            }],
            proxy: {
                type: 'ametys',
                role: 'org.ametys.plugins.workflow.dao.WorkflowsDAO',
                methodName: 'getWorkflowsList',
                methodArguments: [],
                cancelOutdatedRequest: true,
                reader: this._getReaderCfg()
             },
             sortOnLoad: true
        })
        return store;
    },
    
    /**
     * The Proxy reader's config
     * @private 
     */
    _getReaderCfg: function()
    {
        return {
            type: 'json',
            rootProperty: 'workflows'
        };
    },
    
    refresh: function ()
    {
        this.showRefreshing();
        this._panel.getStore().load({callback: this._refreshCb, scope: this});
    },
    
    /**
     * Function invoked after loading the store
     * @private
     */
    _refreshCb: function ()
    {
        var rows = this._panel.getStore().getData().items;
        var hasChanged = false;
        for (var i = 0; i < rows.length; i++)
        {
            if (rows[i].getData().hasChanges)
            {
                hasChanged = true;
            }
        }
        this.setDirty(hasChanged);
        
        var selection = this._panel.getSelectionModel().getSelection();
        var record = this._panel.getStore().getById(this._workflowName);
        if (record)
        {
            if (selection.length > 0 && record == selection[0])
            {
                // same selection
                this.showRefreshed();
                return;
            }
            this._panel.getSelectionModel().select(record);
        }
        this.showRefreshed();
    },
    
    /**
     * 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)
        {
            var selection = this._panel.getSelectionModel().getSelection();
           
            this._workflowName = target.getParameters().id;
            var record = this._panel.getStore().getById(this._workflowName);
            if (record)
            {
                if (selection.length > 0 && record == selection[0])
                {
                    // same selection
                    return;
                }
                this._panel.getSelectionModel().select(record);
            }
        }
    },
    
    /**
     * 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)
        {
            this._workflowName = targets[0].getParameters().id
            this.showOutOfDate();
        }
    }
 });
 
 /**
  * Define the model for the workflow grid
  */
 Ext.define('Ametys.plugins.workflow.WorkflowGridModel', {
    extend: 'Ext.data.Model',
    
    fields: [
        {name: 'id', type: 'string'},
        {name: 'title', type: 'string'},
        {name: 'hasChanges', type: 'boolean'}
    ]
});
 
 /** Class defining target message names for workflows */
 Ext.define("Ametys.message.WorkflowMessageTarget",
 {
     override: "Ametys.message.MessageTarget",
     
     statics: 
     {
         /**
          * @member Ametys.message.MessageTarget
          * @readonly
          * @property {String} WORKFLOW_OBJECT The target type is a workflow. The expected parameters are:  
          * @property {String} WORKFLOW_OBJECT.id The id of the workflow
          * @property {String} WORKFLOW_OBJECT.label The label of the workflow
          * @property {String} WORKFLOW_OBJECT.hasChanges true if the workflow has unsaved changes
          * @property {String} WORKFLOW_OBJECT.isNew true if the workflow has never been saved
          */
         WORKFLOW_OBJECT: "workflow-object",

         /**
          * @member Ametys.message.MessageTarget
          * @readonly
          * @property {String} WORKFLOW_STEP The target type is a workflow step. The expected parameters are:  
          * @property {String} WORKFLOW_STEP.id The id of the step
          * @property {String} WORKFLOW_STEP.label The label of the step
          * @property {String} WORKFLOW_STEP.workflowId id of the related workflow
          */
         WORKFLOW_STEP: "workflow-step",
         
         /**
          * @member Ametys.message.MessageTarget
          * @readonly
          * @property {String} WORKFLOW_ACTION The target type is a workflow action. The expected parameters are:  
          * @property {String} WORKFLOW_ACTION.id The id of the action
          * @property {String} WORKFLOW_ACTION.label The label of the action
          * @property {String} WORKFLOW_ACTION.stepId The id of the parent step
          * @property {String} WORKFLOW_ACTION.workflowId id of the related workflow
          */
         WORKFLOW_ACTION: "workflow-action",
         
         /**
          * @member Ametys.message.MessageTarget
          * @readonly
          * @property {String} WORKFLOW_PROPERTY The target type is a workflow meta. The expected parameters are: 
          * @property {String} WORKFLOW_PROPERTY.workflowId The id of the parent workflow
          * @property {String} WORKFLOW_PROPERTY.stepId The id of the parent step
          * @property {String} WORKFLOW_PROPERTY.actionId the parent action id, can be null if direct parent is a step
          * @property {String} WORKFLOW_PROPERTY.name the property's name 
          * @property {String} WORKFLOW_PROPERTY.value the property's value 
          */
         WORKFLOW_PROPERTY: "workflow-property",
         
         /**
          * @member Ametys.message.MessageTarget
          * @readonly
          * @property {String} WORKFLOW_FUNCTION The target type is a workflow meta. The expected parameters are: 
          * @property {String} WORKFLOW_FUNCTION.workflowId The id of the parent workflow
          * @property {String} WORKFLOW_FUNCTION.stepId The id of the parent step
          * @property {String} WORKFLOW_FUNCTION.actionId the parent action id, can be null if direct parent is a step
          * @property {String} WORKFLOW_FUNCTION.id the function's extension id
          * @property {String} WORKFLOW_FUNCTION.type the function's type
          * @property {Number} WORKFLOW_FUNCTION.index the function's index in its list
          * @property {Boolean} WORKFLOW_FUNCTION.isLast if the function's is at the bottom of its list
          */
         WORKFLOW_FUNCTION: "workflow-function",

        /**
          * @member Ametys.message.MessageTarget
          * @readonly
          * @property {String} WORKFLOW_CONDITIONS_OPERATOR The target type is a workflow conditions. The expected parameters are: 
          * @property {String} WORKFLOW_CONDITIONS_OPERATOR.workflowId The id of the parent workflow
          * @property {String} WORKFLOW_CONDITIONS_OPERATOR.stepId The id of the parent step
          * @property {String} WORKFLOW_CONDITIONS_OPERATOR.actionId the parent action 
          * @property {String} WORKFLOW_CONDITIONS_OPERATOR.type the conditions's type 
          * @property {String} WORKFLOW_CONDITIONS_OPERATOR.nodeId the conditions's node id 
          */
         WORKFLOW_CONDITIONS_OPERATOR: "workflow-conditions-operator",
         
         /**
          * @member Ametys.message.MessageTarget
          * @readonly
          * @property {String} WORKFLOW_CONDITION The target type is a workflow conditions. The expected parameters are: 
          * @property {String} WORKFLOW_CONDITION.workflowId The id of the parent workflow
          * @property {String} WORKFLOW_CONDITION.stepId The id of the parent step
          * @property {String} WORKFLOW_CONDITION.actionId the parent action id
          * @property {String} WORKFLOW_CONDITION.nodeId the condition's node id 
          * @property {String} WORKFLOW_CONDITION.conditionId the condition's extension id 
          */
         WORKFLOW_CONDITION: "workflow-condition",
         
         /**
          * @member Ametys.message.MessageTarget
          * @readonly
          * @property {String} WORKFLOW_RESULT The target type is a workflow result. The expected parameters are: 
          * @property {String} WORKFLOW_RESULT.workflowId The id of the parent workflow
          * @property {String} WORKFLOW_RESULT.actionId the parent action id
          * @property {String} WORKFLOW_RESULT.stepId The id of the parent step
          * @property {String} WORKFLOW_RESULT.nodeId the result's node id 
          * @property {String} WORKFLOW_RESULT.nodeLabel the result's node label
          * @property {String} WORKFLOW_RESULT.isConditional true if the result is conditional
          */
         WORKFLOW_RESULT: "workflow-result"
     }
 });