/*
 *  Copyright 2025 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 class provides a TreePanel for projects resources, it contains a combobox for selecting a project 
 * and the store load the selected project's resources
 */
Ext.define('Ametys.plugins.workspaces.project.resources.ProjectResourcesTree', {
	extend: 'Ametys.explorer.tree.ExplorerTree',
	
	cls: 'project-resource-tree',
	animate: true,
	scrollable: true,
	
	
	/**
     * Initialize the tree
     * @param {Function} [initCb] function to call after initialization process
     * @param {String} projectName name of project related to current selected resource, can be null if no resource is selected
     */
    initialize: function (initCb, projectName)
    {
		this._projectName = null;
		// Load available projects
		this._projectsCombo.getStore().load({callback: Ext.bind(this._loadProjectsCb, this, [initCb, projectName], true)});
    },
	
	/**
	 * @private 
	 * Function called after loading of project store
	 * @param {Function} [initCb] function to call after initialization process
	 * @param {String} projectName name of project related to current selected resource, can be null if no resource is selected
	 */
    _loadProjectsCb: function (records, operation, success, initCb, projectName)
    {
		if (records.length == 0 || projectName && this._projectsCombo.getStore().find("name", projectName) == -1)
		{
			this._showNoAccessPanel(projectName ? "{{i18n PLUGINS_WORKSPACES_PROJECT_RESOURCE_NO_ACCESS}}" : "{{i18n PLUGINS_WORKSPACES_PROJECT_RESOURCE_NO_PROJECT}}");
			
			if (typeof initCb == 'function')
			{
				initCb(null);	
			}
			return;
		}
		
		this._hideNoAccessPanel();
    	if (projectName)
    	{
    		this._projectsCombo.setValue(projectName);
        	this._projectName = projectName;
    	}
    	else
    	{
	        var selectByDefault = this._projectsCombo.getStore().getData().items[0];
	        if (selectByDefault)
	        {
	        	this._projectsCombo.setValue(selectByDefault);
	        	this._projectName = selectByDefault.getData().name
	        }
    	}
        this._getRootNodeConfiguration(initCb, this._projectName);
    },
	
    /**
	 * @private
	 * Get the root node configuration
	 * @param {Function} [initCb] function to call after initialization process
	 * @param {String} projectName name of project related to current selected resource, can be null if no resource is selected
	 */
	_getRootNodeConfiguration: function (initCb, projectName)
	{
		Ametys.data.ServerComm.callMethod({
			role: "org.ametys.plugins.workspaces.documents.WorkspaceExplorerResourceDAO",
			methodName: "getRootNodeInfo",
			parameters: [projectName],
            callback: {
            	scope: this,
            	handler: this._getRootNodeConfigurationCb,
                ignoreOnError: false,
                arguments: {
                    callback: initCb
                }
            },
            errorMessage: {
				msg: "{{i18n PLUGINS_WORKSPACES_UITOOL_PROJECT_RESSOURCES_ERROR}}",
				category: this.self.getName()
			}
		});
	},
	
	/**
	 * @private
	 * Callback function invoked after retrieving the content's attachment root node
	 * @param {Object} response The root properties
	 * @param {Object[]} args the callback arguments
	 * @param {Function} args.callback the callback function to call after initialization process
	 */
	_getRootNodeConfigurationCb: function (response, args)
	{
		this.setRootNodes([Ext.apply(response, {
			expanded: true,
			allowDrag: false,
			allowDrop: false,
			editable : false,
			isModifiable: false,
			canCreateChild: false,
			iconCls: 'a-tree-glyph ametysicon-folder249',
			path: '/dummy/documents',
			type: 'collection',
			text: Ext.String.format("{{i18n PLUGINS_WORKSPACES_PROJECT_RESOURCE_ROOT_NODE}}", response.title),
		})], args.callback);
	},
	
	/**
	 * Get the dock items
	 * @param {Object} config The initial tree panel configuration
	 * @return {Object[]} The dock items configuration
	 */
	getDockItems: function (config)
	{
		var dockItems = this.callParent(arguments);

		// Panel when no access
		dockItems.push({
            dock: 'top',
            hidden: false,
            itemId: 'noaccess',
            ui: 'tool-hintmessage',
            text: "{{i18n PLUGINS_WORKSPACES_PROJECT_RESOURCE_NO_PROJECT}}",
			xtype: 'button'
		});
				
		// Add project combobox
		this._projectsCombo = Ext.create('Ext.form.field.ComboBox', Ext.apply(this._getProjectsComboConfig(), {
			flex: .6, 
			style: { marginRight: '6px' }
		}));
		
		this._projectsCombo.on('select', Ext.bind(this._onSelectProject, this));
		
		var projectToolbar = Ext.create('Ext.toolbar.Toolbar', {
			dock: config.dock || 'top',
			xtype: 'toolbar',
			layout: {
		        type: 'hbox',
		        align: 'stretch'
		    },
			
		    border: false,
			defaults : {
				cls: 'ametys',
				labelWidth: 55,
				labelSeparator: ''
			},
			
			items: [this._projectsCombo]
		});
		
		// Insert projects combox at first position
		dockItems = Ext.Array.insert(dockItems, 0, [projectToolbar]);
		
		return dockItems;
	},
	
	/**
	 * Hide the panel showing there is no result.
	 * @private
	 */
	_hideNoAccessPanel: function ()
	{
		var noAccessPanel = this.getDockedItems('#noaccess')[0];
		if (noAccessPanel) 
		{
			noAccessPanel.hide();
			this._projectsCombo.setDisabled(false);
			// Enable all inputs and buttons of toolbar
			this.getDockedItems('container[dock="top"]')[1]
				.items
				.filterBy((item, key) => item.xtype == 'button' || item.xtype == 'textfield')
				.each(item => item.setDisabled(false));
		}
	},
	
	/**
	 * Set the tree in no access mode
	 * @private
	 */
	_showNoAccessPanel: function (msg)
	{
		var noAccessPanel = this.getDockedItems('#noaccess')[0];
		if (noAccessPanel) 
		{
			noAccessPanel.setText(msg);
			noAccessPanel.show();
			this._projectsCombo.setDisabled(true);
			// Disable all inputs and buttons of toolbar
			this.getDockedItems('container[dock="top"]')[1]
				.items
				.filterBy((item, key) => item.xtype == 'button' || item.xtype == 'textfield')
				.each(item => item.setDisabled(true));
		}
	},
	
	/**
	 * @private 
	 * Function called when a project is selected
	 * refresh the filter and resources
	 */
	_onSelectProject: function (combo, record)
	{
		var value = combo.getValue();
		if (this._projectName == value)
		{
			// No change
			return;
		}
		
		this._projectName = value;
		this._clearSearchFilter();
		 
		// Reload tree with current project
		this._getRootNodeConfiguration(null, this._projectName);
	},
	
	_clearSearchFilter: function(btn)
	{
		this.clearFilter();
		
		//Container has changed place after project combobox insertion
		this.getDockedItems('container[dock="top"]')[1].down('#search-filter-input').reset();
		
		this._hideNoResultPanel();
	},
	
	/**
	 * @private 
	 * Create the project combobox
	 */
	_getProjectsComboConfig: function ()
	{
		var store = Ext.create('Ext.data.Store', {
			model: 'Ametys.plugins.workspaces.project.model.Project',
			
	        proxy: {
	        	type: 'ametys',
				role: 'org.ametys.plugins.workspaces.documents.WorkspaceExplorerResourceDAO',
				methodName: 'getUserProjects2JSON',
				methodArguments: [],
	        	reader: {
	        		type: 'json',
					rootProperty: 'projects'
	        	}
	        },
			sorters: [{property: 'title', direction: 'ASC' }]
		});
		
		return {
			xtype: 'combobox',
			itemId: 'project-combo',
			
			forceSelection: true,
	    	triggerAction: 'all',
	    	queryMode: 'local',
	    	editable: true,
	    	name: 'projects',
	    	
	    	fieldLabel: "{{i18n PLUGINS_WORKSPACES_LINKS_PROJECTS_DIALOG_LABEL}}",
	    	labelWidth: 40,
	    	
	    	store: store,
	        valueField: 'name',
	        displayField: 'title',
	        iconClsField: 'type',
	        
	        tpl: Ext.create('Ext.XTemplate',
	        		 '<ul class="x-list-plain">',
	        		 	'<tpl for=".">',
	        		 		'<li role="option" class="x-boundlist-item">{title} <em>({name})</em></li>',
	        		 	'</tpl>',
	        		 '</ul>')
		}
	},
	
	/**
	 * Create the tree store
	 * @param {Object} config The tree panel configuration
	 * @return {Ext.data.TreeStore} The created tree store
	 */
	createTreeStore: function (config)
	{
		return Ext.create('Ext.data.TreeStore', Ext.apply({
			model: 'Ametys.explorer.tree.ExplorerTree.NodeEntry',
			proxy: {
				type: 'ametys',
				plugin: 'workspaces',
				url: 'child-nodes',
				reader: {
					type: 'xml',
					rootProperty: 'Nodes',
					record: '> Node'
					
				}
			},
            autoLoad : false,
            
			listeners: {
				'beforeload': {fn: this._handleBeforeLoad, scope: this}
			}
		}, this._getStoreSortInfo()));
	},
	

	/**
     * Get the resources the name matches the given value
     * @param {String} value The value to match
     * @param {Ext.data.Model[]} nodes The nodes where starting search
     * @param {Boolean} [childNodesOnly] set to 'true' to filter the child nodes only. 
     * @param {Ext.data.TreeModel} [rootNode] The node to start filtering 
     * @private
     */
    _getFilteredResources: function (value, nodes, childNodesOnly, rootNode)
    {
        if (!this._filterRunning)
        {
            this._filterRunning = true;
	        this._filterCounter = nodes.length;
	        this._hasFilterResult = false;
	        this._filteredPaths =  {};
	        
	        for (var i=0; i < nodes.length; i++)
	        {
	            var node = nodes[i];
	            
	            Ametys.data.ServerComm.callMethod({
	                role: "org.ametys.plugins.workspaces.documents.WorkspaceExplorerResourceDAO", 
	                methodName: 'filterResourcesByRegExp', 
	                parameters: [node.getId(), value, this._allowedExtensions],
	                errorMessage: "{{i18n plugin.explorer:PLUGINS_EXPLORER_UITOOL_EXPLORER_TREE_SEARCH_ERROR}}",
	                callback: {
	                    handler: this._getFilteredResourcesCb,
	                    scope: this,
	                    arguments: {
	                        node: node,
	                        childNodesOnly: childNodesOnly,
	                        rootNode: rootNode || node
	                    }
	                }
	            });
	        }
        }
        else
        {
            Ext.defer(this._getFilteredResources, 100, this, [value, nodes, childNodesOnly, rootNode]);
        }
    }
});