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

/**
 * CostModeling tool 
 * @private
 */
Ext.define('Ametys.plugins.odf.pilotage.tool.CostModelingTool', {
    extend: 'Ametys.plugins.odf.tree.AbstractODFTreeGridTool',

    statics: {
        /**
         * Copy the value in the given target column.
         * @param {String} targetColumnDataIndex The data index of the target column.
         * @param {String} targetColumnStateId The state id of the target column.
         * @param {String} contentId The id of the content.
         * @param {String} title The title of the content.
         * @param {Number} targetCurrentValue The current value in the targeted cell.
         * @param {Object} valueToCopy The value to copy.
         * @static
         */
        copyPreviousData: function(targetColumnDataIndex, targetColumnStateId, contentId, title, targetCurrentValue, valueToCopy)
        {
            // If the new value to copy differs from the previous value in the targeted cell, copy it
            if (targetCurrentValue != valueToCopy)
            {
                var tool = Ametys.tool.ToolsManager.getTool('uitool-simulator');
                var store = tool._treePanel.getStore();
                
                var record = store.findRecord("contentId", contentId);
                record.set(targetColumnDataIndex, valueToCopy);
                
                tool._afterEdit(record, targetColumnStateId, contentId, title, valueToCopy.toFixed());
            }
        }
    },
    
    /**
     * @property {Object} _overriddenData 
     * @private
     */

	constructor: function(config)
	{
		this._overriddenData = {};
	    this.callParent(arguments);
	},
	
    sendCurrentSelection: function()
    {
        // The tool does not react to selection
    },
	
    _getPlugins: function()
    {
        return [
            this._getEditPlugin()
        ];
    },
    

	
	/**
	 * Get all data overridden by the user
	 * @return overridden data
	 */
	_getOverriddenData: function()
	{
		return this._overriddenData;
	},

	_createTree: function()
	{
		return Ext.create('Ametys.plugins.odf.pilotage.tool.CostModelingTreeGridPanel', this._getTreeConfig());
	},

	
    _getRootNodeInfo: function()
    {
        return Ext.apply(this.callParent(arguments), {
            catalog: this.getParams().catalog || this._treePanel.getCatalog(),
            lang: this.getParams().lang || this._treePanel.getLang(),
            overriddenData: this._getOverriddenData()
        });
    },
	
	_getTreeConfig: function()
	{
        var treeCfg = this.callParent(arguments);
        return Ext.apply(treeCfg, {
            activeIndicators: ["odf-indicator-code", "odf-indicator-shared-status", "odf-indicator-courselist-type", "odf-indicator-stepholder"],
            natures: this.getInitialConfig()["enseignement-natures"]
        });
	},
	
	/**
	 * @protected
	 * Update the store and refresh the tool
	 */
	_customRefresh: function()
	{
		this.showRefreshing();
		var contentsToRefresh = [];
		var rootContentId;
		
		// Fill a map gathering all contents to refresh with their path
		for (var key in this._treePanel.store.getData().map) {
			var value = this._treePanel.store.getData().map[key];
			if (value.isRoot())
			{
				// The root node
				rootContentId = value.data.contentId;
			}
			// The path of the content
			var path = value.getPath("name").substring(1)
			// The ID of the content
			var contentId = value.data.contentId;
			// Each content is stored with his path
			contentsToRefresh.push({namePath: path, contentId: contentId, path: value.getPath("contentId", ";").substring(1).split(";")});
		}
		
		Ametys.data.ServerComm.callMethod({
			role: this.getInitialConfig()["serverRole"] || "org.ametys.plugins.odfpilotage.helper.CostComputationTreeHelper",
			methodName: "refresh",
			parameters: [contentsToRefresh, rootContentId, this.getParams().catalog, this.getParams().lang, this._getOverriddenData()],
			callback: {
				handler: this._customRefreshCb,
				scope: this
			}
		});
	},
    
    /**
     * @protected
     * Callback function called after #_customRefresh is processed.
     * Save new values of each record in the store
     * @param {Object} refreshedData a map containing all new values of the opened contents
     */
    _customRefreshCb: function(refreshedData)
    {
        // To avoid useless calls to renderers
        this._treePanel.store.suspendEvents();
        
        for (var key in refreshedData)
        {
            var data = refreshedData[key];
            
            // Retrieve the record of the current content
            var record = this._getRecord(key);
            
            // Effectives
            record.set("effectives", data.effectives);
            record.set("effectivesGlobal", data.effectives);
            record.set("effectivesLocal", data.effectives);
            record.set("effectivesType", data.effectives);
            
            // Groups
            record.set("groups", data.groups);
            record.set("groupsDisplay", data.groups);
            record.set("groupType", data.groups);
            
            // Current year and Last year data
            record.set("previousData", data.previousData);
            record.set("currentYearEffectives", data.previousData);
            record.set("currentYearGroups", data.previousData);
            record.set("precedingYearEffectives", data.previousData);
            record.set("precedingYearGroups", data.previousData);
            
            // Volume of hours
            record.set("volumesOfHours", data.volumesOfHours);
            for (var nature of Object.keys(this.getInitialConfig()["enseignement-natures"]))
            {
                record.set(nature, data.volumesOfHours);
            }
            
            // EqTD
            record.set("eqTDglobal", data.eqTD);
            record.set("eqTDprorated", data.eqTD);
            record.set("eqTDlocal", data.eqTD);
            
            // H/E ratio
            record.set("heRatio", data.heRatio);
            
            record.commit();
        }
        
        // Launch all renderers at the end
        this._treePanel.store.resumeEvents();
        this._treePanel.lockedGrid.getView().refresh();
        this._treePanel.normalGrid.getView().refresh()
        
        this.showRefreshed();
        this._treePanel.getDockedComponent("costModelingHint").setVisible(false);
    },
    
	/**
	 * @protected
	 * Retrieve the record of a content by a path
	 * @param {string} path the path of the content
	 * @return {Object} the record
	 */
	_getRecord: function(path)
	{
		for (var key in this._treePanel.store.getData().map)
		{
			var value = this._treePanel.store.getData().map[key];
			if (value.getPath("name").substring(1) == path)
			{
				return value;
			}
		}
	},
	
    /**
     * @private
     * Create the plugin instance to edit the grid
     * @return {Ext.grid.plugin.CellEditing} The edit plugin
     */
    _getEditPlugin: function()
    {
        return Ext.create('Ext.grid.plugin.CellEditing', {
            id: "edit",
            clicksToEdit: 1,
            editAfterSelect: false,

            moveEditorOnEnter: true, 
        
            listeners: {
              'beforeedit': Ext.bind(this._beforeEdit, this),
              'edit': Ext.bind(this._edit, this),
              'validateedit': Ext.bind(this._validateEdit, this)
            }
        });
    },	
    
	/**
	 * Return true if current record is a CoursePart
	 * @param {Object} record the record to check
	 */
	isCoursePart: function(record)
	{
		var contenttypes = record.data.contenttypesIds;
		return contenttypes.includes('org.ametys.plugins.odf.Content.coursePart')
	},
	
    /**
     * Check right before edition
     * @param {Ext.grid.plugin.CellEditing} editor The editor plugin
     * @param {Object} e An edit event
     * @private
     */    
    _beforeEdit: function(editor, e)
    {
        var contenttypes = e.record.data.contenttypesIds;
        var columnId = e.column.stateId;
        
        // Editable if the user click on the groups or volume of hours of a course part
        if (this.isCoursePart(e.record))
        {
            var enseignementNature = this.getInitialConfig()["enseignement-natures"][columnId];
            return columnId == 'groups' || enseignementNature !== undefined && e.record.data.volumesOfHours[enseignementNature.id] !== undefined;
        }
        
        // Editable if the user click on the global effective column of a program, subprogram, step or course
        if (contenttypes.includes('org.ametys.plugins.odf.Content.course')
            || contenttypes.includes('org.ametys.plugins.odf.Content.container')
            || contenttypes.includes('org.ametys.plugins.odf.Content.subProgram')
            || contenttypes.includes('org.ametys.plugins.odf.Content.program')
        )
        {
            return columnId == 'effectivesGlobal';
        }
        
        return false;
    },
	
    /**
     * When an edition ends, cancel the change if the value is not a conform value
     * @param {Ext.grid.plugin.CellEditing} editor The editor plugin
     * @param {Object} e An edit event 
     * @private
     */
    _edit: function(editor, e)
    {
        if (e.record.data[e.field] < 0 || (!Object.keys(this.getInitialConfig()["enseignement-natures"]).includes(e.field) && !Number.isInteger(e.record.data[e.field])))
        {
        	e.record.set(e.field, e.record.modified[e.field]);
        }
    },

    /**
     * Save overridden data by the user and check if the entered value is a positive number
     * @param {Ext.grid.plugin.CellEditing} editor The editor plugin
     * @param {Object} context The editing context
     * @private
     */
    _validateEdit: function (editor, context)
    {
        var columnId = context.column.stateId;
        var value = context.value;
        var contentId = context.record.data.contentId;
        if (value != undefined && context.originalValue != value && value >= 0)
        {
            var isVolumeOfHours = Object.keys(this.getInitialConfig()["enseignement-natures"]).includes(columnId);
            if ((!isVolumeOfHours && Number.isInteger(value)) || isVolumeOfHours)
            {
                var title = context.record.data.title;
                if (isVolumeOfHours)
                {
                    this._afterEdit(context.record, 'nbHours', contentId, title, value.toFixed(2));
                }
                else
                {
                	this._afterEdit(context.record, columnId, contentId, title, value.toString());
                }
            }
        }
    },
    
    /**
     * Do after edit actions like setting dirty to true and adding an edited hint
     * @param {Object} record the record being edited
     * @param {String} columnId The id of the column
     * @param {String} contentId The id of the content
     * @param {String} title The title of the content
     * @param {String} value The value to set in overriddenData
     */
    _afterEdit: function(record, columnId, contentId, title, value)
    {
        this._treePanel.getDockedComponent("costModelingHint").setVisible(true);
        this.setDirty(true);
        
        if (!this._overriddenData[contentId])
        {
            this._overriddenData[contentId] = {};
            this._overriddenData[contentId]['title'] = title;
        }
        
        this._overriddenData[contentId][columnId] = value;
    },
	
	/**
	 * Get node from contentId
	 * @param {String} contentId id content
	 */
	getCurrentNode: function(contentId)
	{
		return this._treePanel.getStore().getData().items.filter(i=>i.data.contentId == contentId);
	},
	
	/**
	 * Get parent node in tree for content with current id
	 * @param {Object} currentNode node to get parent from
	 */
	getParentNode: function(currentNode)
	{
    	return this._treePanel.getStore().getNodeById(currentNode.getData().parentId);
	}
});