/*
 *  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 is a singleton to handle actions on folder
 */
Ext.define('Ametys.explorer.resources.actions.Folder', {
	singleton: true,
	
	//------------------------------------------------------//
	//					ADD FOLDER							//
	//------------------------------------------------------//
	
	/**
	 * Creates a new folder
	 * @param {String} parentID The parent folder id
	 * @param {String} name The new folder name
	 * @param {Function} callback The function called when the folder was created. Has the following parameters:
	 * @param {String} callback.parentID The parent folder id
	 * @param {String} callback.id The id of the new folder
	 * @param {String} callback.name The new folder name
	 * @param {Object} scope the callback scope
	 */
	add: function(parentID, name, callback, scope)
	{
		name = Ext.String.trim(name); // Avoid compat issue with native String#trim();
		var renameIfExists = true;
		
		Ametys.data.ServerComm.callMethod({
			role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO', 
			methodName: 'addResourceCollection',
			parameters: [parentID, name, renameIfExists],
			callback: {
				handler: this._addCb,
				scope: this,
				arguments: [callback, scope]
			},
			waitMessage: true,
			errorMessage: true
		});
	},
	
	/**
	 * @private
	 * Callback of #add
	 * @param {Object[]} response the server response
	 * @param {Object[]} args the callback args
	 */
	_addCb: function(response, args)
	{
		var msg = response['message'] || null,
			id =  response['id'],
			parentID = response['parentID'],
			name = response['name'];
		
		var callback = args[0] || Ext.emptyFn,
			scope = args[1] || this;
		
		if (msg == 'locked')
		{
			Ametys.Msg.show({
				title: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_ADD}}",
				msg: "{{i18n PLUGINS_EXPLORER_FOLDER_ADD_LOCKED}}",
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
		}
		else
		{
			// Sending message
			Ext.create("Ametys.message.Message", {
				type: Ametys.message.Message.CREATED,
				
				targets: {
					id: Ametys.message.MessageTarget.EXPLORER_COLLECTION,
					parameters: { ids: [id]}
				}
			});
		}
		
		// callback
		callback.apply(scope, [parentID, id, name]);
	},
	
	//------------------------------------------------------//
	//					ADD CMIS							//
	//------------------------------------------------------//
	
	/**
	 * Create or edit a CMIS connection
	 * @param {String} id The parent folder id for creation or the folder id for edition
	 * @param {String} mode 'new' for creation or 'edit' for edition
	 * @param {Function} callback The callback function
	 * @param {String} callback.parentID The parent folder id
	 * @param {String} callback.id The id of the new CMIS resource
	 * @param {String} callback.name The new CMIS folder name
	 * @param {Object} scope the callback scope
	 */
	addCMIS: function(id, mode, callback, scope)
	{
		Ametys.explorer.resources.helper.CMISConnection.open(id, Ext.bind(this._addCMISCb, this, [callback, scope], true), mode);
	},
	
	/**
	 * @private
	 * Callback function called after #addCMIS is processed
	 * @param {String} parentId The id of parent folder
	 * @param {String} id The id of created folder
	 * @param {String} name The name of the created folder
	 * @param {Function} callback The callback function
	 * @param {String} callback.parentID The parent folder id
	 * @param {String} callback.id The id of the new CMIS resource
	 * @param {String} callback.name The new CMIS folder name
	 * @param {Object} scope the callback scope
	 */
	_addCMISCb: function(parentId, id, name, callback, scope)
	{
		var callback = callback || Ext.emptyFn,
			scope = scope || this;
		
		var parameters = {};
		if (parentId == null)
		{
    		parameters.major = true;
		}
		
		Ext.create("Ametys.message.Message", {
			type: parentId == null ? Ametys.message.Message.MODIFIED : Ametys.message.Message.CREATED,
			parameters: parameters,
			targets: {
				id: Ametys.message.MessageTarget.EXPLORER_COLLECTION,
				parameters: { ids: [id]}
			}
		});
		
		// callback
		callback.apply(scope, [parentId, id, name]);
	},

	//------------------------------------------------------//
	//						RENAME							//
	//------------------------------------------------------//
	
	/**
	 * Rename a folder
	 * @param {String} id The folder id to rename
	 * @param {String} name The new name
	 * @param {Function} callback The callback function called when the folder has been renamed
	 * @param {String} callback.id The id of the renamed resource.
	 * @param {String} callback.name The new folder name
	 * @param {Object} scope the callback scope
	 */
	rename: function(id, name, callback, scope)
	{
		var name = Ext.String.trim(name),
			callback = Ext.isFunction(callback) ? callback : Ext.emptyFn,
			scope = scope|| this;
		
		if (name == '' || !/^[^\\/:*?"<>|]*$/.test(name))
		{
			Ametys.Msg.alert(
				"{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_RENAME}}",
				"{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_RENAME_INVALID_CHARACTERS}}"
			);
			
			callback.apply(scope, [id, name]);
			return;
		}
		
		Ametys.data.ServerComm.callMethod({
			role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO', 
			methodName: 'renameObject',
			parameters: [id, name],
			callback: {
				handler: this._renameCb,
				scope: this,
				arguments: [callback, scope]
			},
			waitMessage: true,
			errorMessage: true
		});
	},
	
	/**
	 * @private
	 * Callback of #rename
	 * @param {Object[]} response the server response
	 * @param {Object[]} args the callback args
	 */
	_renameCb: function(response, args)
	{
		var msg = response['message'] || null,
			id =  response['id'],
			name = response['name'];
		
		var callback = args[0] || Ext.emptyFn,
			scope = args[1] || this;
		
		if (msg == 'locked')
		{
			Ametys.Msg.show({
				title: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_RENAME}}",
				msg: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_RENAME_LOCKED}}",
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
		}
		else if (msg == 'already-exist')
		{
			Ametys.Msg.show({
				title: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_RENAME}}",
				msg: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_RENAME_ALREADY_EXISTS}}",
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
		}
		else
		{
			// Sending message
			Ext.create("Ametys.message.Message", {
				type: Ametys.message.Message.MODIFIED,
				
				targets: {
					id: Ametys.message.MessageTarget.EXPLORER_COLLECTION,
					parameters: { ids: [id]}
				}
			});
		}
		
		// callback
		callback.apply(scope, [id, name, true]);
	},
	
	//------------------------------------------------------//
	//						REMOVE							//
	//------------------------------------------------------//
	
	/**
	 * Function to delete a folder
	 * @param {String} id The folder id to delete
	 * @param {Function} callback The callback function called when the folder has been deleted
	 * @param {Object} scope the callback scope
	 */
	remove: function(id, callback, scope)
	{
		Ametys.Msg.confirm(
			"{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_DELETE}}", 
			"{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_DELETE_CONFIRM}}", 
			function (btn) {
				this._doRemove(btn, id, callback, scope);
			}, 
			this
		);
	},
	
	/**
	 * @private
	 * Internal remove function.
	 * @param {String} answer The id of the button pressed.
	 * @param {String} id id of the removed resource.
	 * @param {Function} callback The callback function called when the folder has been deleted
	 * @param {Object} scope the callback scope
	 */
	_doRemove: function(answer, id, callback, scope)
	{
		var ids = [id],
			callback = Ext.isFunction(callback) ? callback : Ext.emptyFn,
			scope = scope|| this;
		
		if (answer == 'yes')
		{
			var me = this; 
			
			// Sending the deleting message to store target info
			Ext.create("Ametys.message.Message", {
				type: Ametys.message.Message.DELETING,
				
				targets: {
					id: Ametys.message.MessageTarget.EXPLORER_COLLECTION,
					parameters: {ids: ids}
				},
				
				callback: function(deletingMsg) {
					
					// Effectively removing the folder
					Ametys.data.ServerComm.callMethod({
						role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO', 
						methodName: 'deleteObject',
						parameters: [ids],
						callback: {
							handler: me._removeCb,
							scope: me,
							arguments: [callback, scope, deletingMsg.getTargets(), id]
						},
						waitMessage: true,
						errorMessage: true
					});
				}
			});
		}
		else
		{
			// callback
			callback.apply(scope, [id]);
		}
	},
	
	/**
	 * @private
	 * Callback of #_doRemove
	 * @param {Object[]} response the server response
	 * @param {Object[]} args the callback args
	 */
	_removeCb: function(response, args)
	{
		var msg = response['message'] || null;
		
		var callback = args[0] || Ext.emptyFn,
			scope = args[1] || this,
			targets = args[2],
			id = args[3];
		
		if (msg == 'locked')
		{
			Ametys.Msg.show({
				title: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_DELETE}}",
				msg: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_DELETE_LOCKED}}",
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
		}
		else
		{
			// Sending the deleted message with stored targets
			Ext.create("Ametys.message.Message", {
				type: Ametys.message.Message.DELETED,
                // FIXME this should be determined based on the response
                parameters: {trashed: true},
				targets: targets
			});
		}
		
		// callback
		callback.apply(scope, [id]);
	},
	
	//------------------------------------------------------//
	//						ARCHIVE							//
	//------------------------------------------------------//
	
	/**
	 * Function to download a folder as a ZIP archive
	 * @param {String} id The id of the folder
	 * @param {String} name The folder name
	 */
	archive: function(id, name)
	{
		var args = {
            'id': id
        }
        if (name)
        {
            args.name = name;
        }
        
        Ametys.openWindow(Ametys.getPluginDirectPrefix('explorer') + '/folder/archive.zip', args)
	},
	
	//------------------------------------------------------//
	//						MOVE							//
	//------------------------------------------------------//
	
	/**
	 * Move a folder to a target folder
	 * @param {String} target The id of folder to move into
	 * @param {String} ids The id of folders to move
	 * @param {Function} callback The callback function called when the folders has been moved
	 * @param {String} callback.target The id of target
	 * @param {String[]} callback.ids The ids of the moved folders.
	 */
	move: function(target, ids, callback)
	{
		var params = {
			id: ids,
			target: target
		};
		
		Ametys.data.ServerComm.callMethod({
			role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO', 
			methodName: 'moveObject',
			parameters: [ids, target],
			callback: {
				handler: this._moveCb,
				scope: this,
				arguments: {
					callback: callback,
					target: target
				}
			},
			errorMessage: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_MOVE_ERROR}}"
		});
	},
	
	/**
	 * @private
	 * Callback function invoked after moving objects
	 * @param {Object} response The server result
	 * @param {String} response.message In case of error
	 * @param {String[]} response.moved-objects The ids of effective moved objects
	 * @param {String[]} response.unmoved-objects The ids of unmoved objects
     * @param {Object[]} args Additionnal arguments
     * @param {Function} [args.callback] A callback at the end
     * @param {String[]} args.callback.copiedResources The identifiers of the copied objects
     * @param {String} args.callback.target The target in #move
     * @param {String} [args.target] The target in #move
	 */
	_moveCb: function (response, args)
	{
		if (response.message && response.message == 'locked')
		{
			Ametys.Msg.show({
				title: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_MOVE}}",
				msg: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_MOVE_LOCKED}}",
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
			return;
		}
		
		if (response.message && response.message == 'already-exist')
		{
			var unmovedObjects = response["unmoved-objects"];
			
			Ametys.Msg.show({
				title: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_MOVE}}",
				msg: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_MOVE_UNPASTE}}" + unmovedObjects.join(", ") + "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_MOVE_UNPASTE_2}}",
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.WARN
			});
		}
		
		var noRightOjects = response["noright-objects"] || [];
		if (noRightOjects.length > 0)
		{
			Ametys.Msg.show({
				title: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_MOVE}}",
				msg: "{{i18n PLUGINS_EXPLORER_FOLDER_HANDLE_MOVE_NORIGHT}}" + noRightOjects.join(", "),
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
		}
		
		var movedObjects = response["moved-objects"] || [];
		if (movedObjects.length > 0)
		{
			Ext.create("Ametys.message.Message", {
				type: Ametys.message.Message.MOVED,
				
				targets: {
					id: Ametys.message.MessageTarget.EXPLORER_COLLECTION,
					parameters: {ids: movedObjects}
				}
			});
		}
		
		if (Ext.isFunction(args.callback))
		{
			args.callback(args.target, movedObjects);
		}
	}
});