/*
 *  Copyright 2013 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 handles the access to explorer node properties.
 * See {@link Ametys.explorer.ExplorerNode}
 */
Ext.define('Ametys.explorer.ExplorerNodeDAO', {
	singleton: true,
	
	constructor: function(config)
 	{
		/**
    	 * @callable
    	 * @param member Ametys.explorer.ExplorerNodeDAO
    	 * @method hasRight
    	 * Check the current user right on an explorer node
    	 * This calls the method 'hasRight' of the server DAO 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO'.
    	 * @param {Object[]} parameters The parameters to transmit to the server method
    	 * @param {String} parameters.id The id of explorer node
    	 * @param {String} parameters.right The id of right to check
    	 * @param {Function} callback The function to call when the java process is over. Use options.scope for the scope. 
		 * @param {Object} callback.hasRight true if the user has right, false otherwise.
		 * @param {Object} callback.arguments Other arguments specified in option.arguments                 
		 * @param {Object} [options] Advanced options for the call.
		 * @param {Boolean/String/Object} [options.errorMessage] Display an error message. See Ametys.data.ServerComm#callMethod errorMessage.
		 * @param {Boolean/String/Object} [options.waitMessage] Display a waiting message. See Ametys.data.ServerComm#callMethod waitMessage.
		 * @param {Number} [options.scope] This parameter is the scope used to call the callback. Moreover is the given class is a mixin of Ametys.data.ServerCaller, its methods Ametys.data.ServerCaller#beforeServerCall and Ametys.data.ServerCaller#afterServerCall will be used so see their documentation to look for additional options (such a refreshing on Ametys.ribbon.element.ui.ButtonController#beforeServerCall).
		 * @param {Number} [options.priority] The message priority. See Ametys.data.ServerComm#callMethod for more information on the priority. PRIORITY_SYNCHRONOUS cannot be used here.
		 * @param {String} [options.cancelCode] Cancel similar unachieved read operations. See Ametys.data.ServerComm#callMethod cancelCode.
		 * @param {Object} [options.arguments] Additional arguments set in the callback.arguments parameter.                  
		 * @param {Boolean} [options.ignoreCallbackOnError] If the server throws an exception, should the callback beeing called with a null parameter. See Ametys.data.ServerComm#callMethod ignoreOnError.
    	 */
		this.addCallables({
		    role: "org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO",
			methodName: "hasRight",
			waitMessage: false,
			errorMessage: {
			    msg: "{{i18n PLUGINS_EXPLORER_DAOS_EXPLORER_NODE_CHECK_RIGHT_ERROR}}",
			    category: Ext.getClassName(this)
			}
		});
 	},
	
	/**
	 * Retrieve a explorer node by its id
	 * @param {String} id The explorer node identifier. Cannot be null.
	 * @param {Function} callback The callback function called when the explorer node is retrieved. Can be null for synchronous mode (not recommended!). Parameters are
	 * @param {Ametys.explorer.ExplorerNode} callback.node The explorer node retrieved. Can be null if explorer node does not exist.
	 * @return {Ametys.explorer.ExplorerNode} The explorer node retrieved if no callback function is specified or null otherwise.
	 */
	getExplorerNode: function (id, callback)
	{
		if (Ext.isEmpty(id))
		{
			callback(null);
			return;
		}
		this._sendRequest ([id], Ext.bind(this._getExplorerNodeCb, this, [callback], 1));
	},
	/**
	 * @private
	 * Callback function called after #getExplorerNode is processed
	 * @param {Ametys.explorer.ExplorerNode[]} nodes The explorer nodes retrieved
	 * @param {Function} callback The callback function called 
	 */
	_getExplorerNodeCb: function (nodes, callback)
	{
		callback((nodes.length == 0) ? null : nodes[0]);
	},
	
	/**
	 * Retrieve explorer nodes by their ids
	 * @param {String[]} ids The explorer nodes identifiers. Cannot be null.
	 * @param {Function} callback The callback function called when the explorer node is retrieved. Can be null for synchronous mode (not recommended!). Parameters are
	 * @param {Ametys.explorer.ExplorerNode} callback.node The explorer node retrieved. Can be null if explorer node does not exist.
	 * @return {Ametys.explorer.ExplorerNode} The explorer node retrieved if no callback function is specified or null otherwise.
	 */
	getExplorerNodes: function (ids, callback)
	{
		if (Ext.isEmpty(ids))
		{
			callback([]);
			return;
		}
		this._sendRequest (ids, Ext.bind(this._getExplorerNodesCb, this, [callback], 1));
	},
	/**
	 * @private
	 * Callback function called after #getExplorerNodes is processed
	 * @param {Ametys.explorer.ExplorerNode[]} nodes The explorer node retrieved
	 * @param {Function} callback The callback function called 
	 */
	_getExplorerNodesCb: function (nodes, callback)
	{
		callback(nodes);
	},
	
	/**
	 * @private
	 * Send request to server to retrieved nodes
	 * @param {String[]} ids The id of nodes to retrieve
	 * @param {Function} callback The callback function to be called after server process
	 */
	_sendRequest: function (ids, callback)
	{
		Ametys.data.ServerComm.callMethod({
			role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO',
			methodName: 'getNodesInfo',
			parameters: [ids],
			callback: {
				handler: this._getExplorerNodesCB,
				scope: this,
				arguments: [callback]
			},
			waitMessage: false,
			errorMessage: "{{i18n PLUGINS_EXPLORER_DAOS_EXPLORER_NODE_ERROR}}"
		});
	},
	
	/**
	 * @private
	 * Callback function called after #_sendRequest is processed
	 * @param {Object} result The server result
	 * @param {Array} arguments The callback arguments.
	 */
	_getExplorerNodesCB: function (result, arguments)
	{
		var nodes = [],
			nodesCfg = result.objects,
			nodeCfg, app, className;
		
		for (var i=0; i < nodesCfg.length; i++)
		{
			nodeCfg = nodesCfg[i];
			className = 'Ametys.explorer.ExplorerNode';
			
			nodes.push(Ext.create(className, nodeCfg));
		}
		
		var objectsNotFound = result.objectsNotFound;
		if (objectsNotFound.length > 0)
		{
			Ametys.log.ErrorDialog.display({
				title: "{{i18n PLUGINS_EXPLORER_DAOS_EXPLORER_NODE_NOT_FOUND}}", 
				text: "{{i18n PLUGINS_EXPLORER_DAOS_EXPLORER_NODE_NOT_FOUND_HINT}}",
				details: objectsNotFound.join(", "),
				category: "Ametys.explorer.ExplorerNodeDAO"
			});
		}

		if (typeof arguments[0] == 'function')
		{
			arguments[0](nodes);
		}
	},
	
	/**
	 * Get the root nodes info to be passed to an explorer tree.
	 * @param {Function} callback The callback function to be called once the root nodes info are retrieved
	 * @param {Object} [scope] The callback scope
	 * @param {String} [callMethodRole=org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO] the component role of the call method that should retrieves the root nodes info can be overriden
	 * @param {String} [callMethodName=getRootNodesInfo] the name of the call method that should retrieves the root nodes info can be overriden
	 * @param {Object} [callMethodParams]  the params of the call method that should retrieves the root nodes info can be overriden
	 */
	getRootNodesInfo: function(callback, scope, callMethodRole, callMethodName, callMethodParams)
	{
		callMethodRole = callMethodRole || 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO';
		callMethodName = callMethodName || 'getRootNodesInfo'
		
		Ametys.data.ServerComm.callMethod({
			role: callMethodRole,
			methodName: callMethodName,
			parameters: callMethodParams || [],
			callback: {
				handler: this._getRootNodesInfoCb,
				scope: this,
				arguments: [callback, scope],
                ignoreOnError: false
			},
			waitMessage: false,
			errorMessage: true,
            priority: Ametys.data.ServerComm.PRIORITY_LONG_REQUEST // due to potential request to CMIS
		});
	},
	
	/**
	 * The _getRootNodesInfo callback
	 * @param {Object} response The root nodes info
	 * @param {Object[]} args The callback arguments
	 */
	_getRootNodesInfoCb: function(response, args)
	{
		var callback = args[0] || Ext.emptyFn,
			scope = args[1] || this;
		
		callback.apply(scope, [response]);
	},
	
    /**
     * Determines if a file can be renamed.
     * @param {String} path The resource path in the explorer
     * @return {Boolean} true if the file can be renamed.
     */
    canRenameFile: function(path)
    {   
        // FIXME Refactor the call to canRenameFile to allow async processing?
        var response = Ametys.data.ServerComm.send({
            plugin: 'core', 
            url: 'has-right',
            parameters: {
                rights: 'Plugin_Explorer_File_Rename',
                context: '/resources/' + path
            },
            priority: Ametys.data.ServerComm.PRIORITY_SYNCHRONOUS,
            waitMessage: true,
            errorMessage: true
        });
        
        return response != null && Ext.dom.Query.selectValue('ActionResult/hasRight', response) == 'true';

    },
    
    /**
     * @protected
     * @template
     * Determines if the node application can be renamed. Returns false by default.
     * Override this method to allow the renaming.
     * @param {Ext.data.Model} node The node
     * @return {Boolean} true if the node can be renamed
     */
    canRenameNode: function(node) 
    {
        return true;
    },

    /**
     * Must provide the object which hold the rename action.
     * Rename action is mandatory as long as canRenameNode return value is not always false.
     * The rename action parameters are :
     * @return {Function} The object holding the rename action. Expected parameters for the rename function are :
     * - {String} id The explorer node id to rename
     * - {String} name The new name
     * - {Function} callback The callback function called when the explorer node has been renamed
     * - {String} callback.id The id of the renamed explorer node.
     * - {String} callback.name The new name
     * - {Object} scope the callback scope
     */
    getRenameActionHolder: function()
    {
        return Ametys.explorer.resources.actions.Folder;
    }
});