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

/**
 * Singleton class for actions on skin's resources
 * @private
 */
Ext.define('Ametys.plugins.skineditor.resources.SkinResourcesActions', {
    singleton: true,

    /**
     * Saves the changes of the current file without leaving the editing.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    save: function (controller)
    {
        this._startSave(controller, false);
    },

    /**
     * Saves the changes of the current file and leave the editing.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    saveAndQuit: function (controller)
    {
        this._startSave(controller, true);
    },

    /**
     * Saves the content of the current editor tool
     * Sends a {@link Ametys.message.Message#MODIFIED} event on success.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     * @param {Boolean} quit true close tool edition.
     */
    _startSave: function (controller, quit)
    {
    	var target = controller.getMatchingTargets()[0];
		var fileName = target.getParameters().name;
		var path = target.getParameters().path;
		var skinName = target.getParameters().skinName;
		
		var tool = Ametys.tool.ToolsManager.getFocusedTool();
		var content = tool.getText();
		
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.skineditor.resources.SkinResourceDAO",
            methodName: "save",
            parameters: [skinName, path, content],
            callback: {
                scope: this,
                handler: this._saveCb,
                arguments:
                {
                    tool: tool,
                    skinName: skinName,
                    name: fileName,
                    path: path,
                    quit: quit
                }
            },
            waitMessage: {
                target: tool.getContentPanel(),
                msg: "{{i18n plugin.cms:CONTENT_EDITION_SAVING}}"
            },
            errorMessage: {
                msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_ERROR}}",
                category: "Ametys.plugins.cms.params.editor.EditorTool"
            }
        });
    },

    /**
     * Callback function called after saving
     * @param {Object[]} response The server response.
     * @param {Boolean} response.success true if the operation succeeded, false otherwise.
     * @param {String} [response.error] The error message in case of failure
     * @param {Object[]} args The callback arguments.
     * @private
     */
    _saveCb: function (response, args)
    {
        if (!response.success && response.error == 'unknown-file')
        {
            Ametys.Msg.show({
                title: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_LABEL}}",
                msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_UNKNOWN_FILE}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
            return;
        }

        if (response.isI18n)
        {
            Ametys.Msg.show({
                title: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_LABEL}}",
                msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_NEED_WAIT}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.INFO
            });
        }

        args.tool.setDirty(false);

        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.MODIFIED,
            parameters: { major: true },
            targets: {
                id: Ametys.message.MessageTarget.SKIN_RESOURCE,
                parameters: {
                    'name': args.name,
                    'path': args.path,
                    'skinName': args.skinName
                }
            }
        });

        if (args.quit)
        {
            args.tool.close();
        }
    },

    /**
     * Cancel current changes.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    unsave: function (controller)
    {
        Ametys.Msg.confirm("{{i18n PLUGINS_SKINEDITOR_EDITOR_UNSAVE_LABEL}}",
            "{{i18n PLUGINS_SKINEDITOR_EDITOR_UNSAVE_CONFIRM}}",
            Ext.bind(this._unsaveConfirm, this),
            this
        );
    },

    /**
     * Callback function invoked after the 'unsave' confirm box is closed
     * @param {String} answer Id of the button that was clicked
     * @private
     */
    _unsaveConfirm: function (answer)
    {
        if (answer == 'yes')
        {
            var editorTool = Ametys.tool.ToolsManager.getFocusedTool();
            editorTool.close();
        }
    },

    // ------------------------ FOLDERS -------------------------------//

    /**
     * Create sa new folder.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    addFolder: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
            Ametys.data.ServerComm.callMethod({
                role: "org.ametys.plugins.skineditor.resources.SkinResourceDAO",
                methodName: "addFolder",
                parameters: [targets[0].getParameters().skinName, targets[0].getParameters().path, "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_ADD_FOLDER_NEW}}", true],
                callback: {
                    scope: this,
                    handler: this._addFolderCb
                },
                errorMessage:{
                    msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_ADD_FOLDER_ERROR}}",
                    category: this.self.getName()
                }
            });
        }
    },

    /**
     * Callback invoked when adding a folder
     * @param {Object[]} response The JSON response from the server
     * @param {String} response.path the path of the folder
     * @param {String} response.parentPath the path of the parent 
     * @param {String} response.name the name of the folder
     * @param {String} response.skinName the skin's name
     */
    _addFolderCb: function (response)
    {
        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.CREATED,
            parameters: {parentPath: response.parentPath},
            targets:
            {
                id: Ametys.message.MessageTarget.SKIN_COLLECTION,
                parameters: {
                    path: response.path,
                    name: response.name,
                    skinName: response.skinName
                }
            }
        });
    },

    // -----------------------------------------------------------
    /**
     * Deletes a folder.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    removeFolder: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
            Ametys.Msg.confirm("{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FOLDER_TITLE}}",
                "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FOLDER_CONFIRM}}",
                function (btn)
                {
                    this._doRemove(btn, targets[0]);
                },
                this);
        }
    },

    /**
     * Do remove the current file or folder.
     * @param {String} answer The id of the button pressed.
     * @param {Ametys.message.MessageTarget} target The target of the folder or file to delete
     * @private
     */
    _doRemove: function (answer, target)
    {
        if (answer == 'yes')
        {
            Ametys.data.ServerComm.callMethod({
                role: "org.ametys.plugins.skineditor.resources.SkinResourceDAO",
                methodName: "deleteFile",
                parameters: [target.getParameters().skinName, target.getParameters().path],
                callback: {
                    scope: this,
                    handler: this._doRemoveCb,
                    arguments: {
                        target: target
                    }
                },
                errorMessage: {
                    msg: target.getId() == Ametys.message.MessageTarget.SKIN_COLLECTION ? "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FOLDER_ERROR}}" : "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FILE_ERROR}}",
                    category: this.self.getName()
                },
            });
        }
    },

    /**
     * @private
     * Callback function after deletion.
     * @param {Object[]} result the server's response
     * @param {Object} params The callback arguments
     */
    _doRemoveCb: function (result, params)
    {
        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.DELETED,
            targets: params.target
        });
    },

    // -----------------------------------------------------------
    /**
     * Renames a folder
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    renameFolder: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
            var oldName = targets[0].getParameters().name;

            Ametys.Msg.prompt(
                "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_TITLE}}",
                "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_MSG}}",
                function (btn, text)
                {
                    if (btn == 'ok' && text != oldName)
                    {
                    	this.rename (targets[0].getParameters().skinName, targets[0].getParameters().path, text, 'collection');
                    }
                },
                this,
                false,
                oldName
            );
        }
    },

    /**
     * Refresh the currently selected folder inside the SkinEditor tool
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    refreshFolder: function (controller)
    {
        var targets = controller.getMatchingTargets();
        var skinEditorTool = Ametys.tool.ToolsManager.getFocusedTool();
        if (targets.length > 0 && skinEditorTool != null)
        {
            skinEditorTool.refreshNode(targets[0].getParameters().path);
        }
    },

    // ----------------------------- FILES -------------------------------//

    /**
     * Open or download a file.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    openFile: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
        	this.doOpenFile(targets[0].getParameters().name, targets[0].getParameters().path, targets[0].getParameters().skinName);
        }
    },

    /**
     * Open the editor corresponding to the file, or starts the download if no editor matches
     * @param {String} filename The name of the file
     * @param {String} path The path of the file
     * @param {String} skinName the name of the skin
     */
    doOpenFile: function (filename, path, skinName)
    {
    	if (this.isFileEditableOnline(filename))
		{
			var params = {};
		   	params.id = path.replace(/\//g, "-");
		   	params.filename = filename;
		   	params.path = path;
		   	params.skinName = skinName;
		   	
		   	var fileTool = Ametys.tool.ToolsManager.getTool("uitool-skin-file-editor$" + params.id);
			if (fileTool)
			{
				fileTool.focus();
			}
			else
			{
				Ametys.tool.ToolsManager.openTool("uitool-skin-file-editor", params);
			}
		   	
		}
		else
		{
			// Download uneditable file
			var args = "path=" + path + "&skinName=" + skinName;
			var url = Ametys.getPluginDirectPrefix('skineditor') + '/file/download?' + args;
			window.open(url);
		}
    },
    
    /**
	 * Determines if a file can be edited online by its name
	 * @param {String} name The file name
	 */
	isFileEditableOnline: function (name)
	{
		var extension = Ametys.file.AbstractFileExplorerTree.getFileExtension(name).toLowerCase();
		return extension == 'js' || extension == 'html' || extension == 'xhtml' || extension == 'css' || extension == 'xml' || extension == 'xsl' || extension == 'xslt' || extension == 'txt' || extension == 'dtd';
	},

    /**
     * Function called to add or update a file
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    addFile: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
            Ametys.plugins.skineditor.resources.UploadFile.open(targets[0].getParameters().skinName, targets[0].getParameters().path, Ext.bind(this._addFileCb, this, [targets[0].getParameters().skinName], true));
        }
    },

    /**
     * Callback function called after #addFile action is processed
     * @param {String} name The name of uploaded file
     * @param {String} path The path of uploaded file
     * @param {String} parentPath The parent path of uploaded file
     * @param {String} skinName The skin name
     * @private
     */
    _addFileCb: function (name, path, parentPath, skinName)
    {
        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.CREATED,
            parameters: {parentPath: parentPath},
            targets: {
                id: Ametys.message.MessageTarget.SKIN_RESOURCE,
                parameters:
                {
                    path: path,
                    name: name,
                    skinName: skinName
                }
            }
        });
    },

    /**
     * Deletes a file
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    removeFile: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
            Ametys.Msg.confirm("{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FILE_TITLE}}",
                "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FILE_CONFIRM}}",
                function (btn)
                {
                    this._doRemove(btn, targets[0], targets[0].getParameters().skinName);
                },
                this);
        }
    },

    /**
     * Renames a file
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    renameFile: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
            var name = targets[0].getParameters().name;
            
            Ametys.Msg.prompt(
                "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_PROMPT_TITLE}}",
                "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_PROMPT_MSG}}",
                function (btn, text)
                {
                	if (btn == 'ok' && text != name) 
                    {
                    	this.rename (targets[0].getParameters().skinName, targets[0].getParameters().path, text, 'resource');
                    }
                },
                this,
                false,
                name
            );
        }
    },

    /**
	 * Renames a file or a folder
	 * @param {String} skinName The skin's name
	 * @param {String} path The path of file/folder to rename
	 * @param {String} name The new name
	 * @param {String} type The type of resource : 'resource' or 'collection'
	 * @param {Function} [callback] Callback function. The function receives the following parameters:
	 * @param {Boolean} callback.success true if the renaming was successful
	 * @param {String} callback.path The path of the renamed file
	 * @param {String} callback.name The name of the renamed file
	 */
    rename: function (skinName, path, name, type, callback)
    {
        name = Ext.String.trim(name);
        if (name == '' || !/^[^\\/:*?"<>|]*$/.test(name))
        {
        	// Invalid name
            var alertMsg = type == 'resource' ? "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FILE_INVALID_CHARACTERS}}" : "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_INVALID_CHARACTERS}}";
            Ametys.Msg.alert(
                "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_FILE}}",
                alertMsg
            );

            if (Ext.isFunction(callback))
            {
                callback(false, path, name);
            }
            return false;
        }

        var errorMsg = type == 'resource' ? "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FILE_ERROR}}" : "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_ERROR}}";

        Ametys.data.ServerComm.callMethod({
            role: 'org.ametys.plugins.skineditor.resources.SkinResourceDAO',
            methodName: 'renameSource',
            parameters: [skinName, path, name],
            callback: {
                scope: this,
                handler: this._renameCb,
				arguments: {
					name: name, 
					type: type, 
					path: path,
					callback: callback,
					messageTargetType: type == 'resource' ? Ametys.message.MessageTarget.SKIN_RESOURCE : Ametys.message.MessageTarget.SKIN_COLLECTION
				}
            },
            errorMessage: {
                msg: errorMsg,
                category: Ext.getClassName(this) + '.rename'
            },
            waitMessage: true
        });
    },
    
    /**
	 * @private
	 * Callback invoked after renaming a file or folder
	 * @param {Object} result The server result
	 * @param {Object} args the callback arguments
	 */
	_renameCb: function (result, args)
	{
		if (result.error == 'already-exist')
		{
			var errorMsg = args.type == 'resource' ? "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FILE_ALREADY_EXISTS}}" : "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_ALREADY_EXISTS}}";
			Ametys.Msg.show({
				title: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_FILE}}",
				msg: errorMsg,
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
			
			if (Ext.isFunction(args.callback))
			{
			    args.callback(false, args.path, args.name);
			}
			return false;
		}
		
		Ext.create("Ametys.message.Message", {
			type: Ametys.message.Message.MODIFIED,
			
			targets: {
			    id: args.messageTargetType,
				parameters: { 
					path: result.path,
					name: result.name,
					skinName: result.skinName
				}
			}
		});
		
		if (Ext.isFunction(args.callback))
		{
			args.callback(true, result.path, result.name);
		}
	},

    /**
     * Download the currently selected file
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    downloadFile: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
            var args = {
                "path": targets[0].getParameters().path,
                "skinName": targets[0].getParameters().skinName
            }
            Ametys.openWindow(Ametys.getPluginDirectPrefix('skineditor') + '/file/download', args);
        }
    },

    // ----------------------------- CLIPBOARD -------------------------------//
    /**
     * Copy the currently selected file or folder. This allows the {#paste} function to be called
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    copy: function (controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length == 0)
        {
            return;
        }

        var data = Ext.apply (targets[0].getParameters(), {mode: 'copy', messageTargetType: targets[0].getId()});
        Ametys.clipboard.Clipboard.setData (targets[0].getId(), data);
    },

    /**
     * Cut the currently selected file or folder. This allow the {#paste} function to be called
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    cut: function (controller)
    {
    	var targets = controller.getMatchingTargets();
        if (targets.length == 0)
        {
            return;
        }

        var data = Ext.apply (targets[0].getParameters(), {mode: 'cut', messageTargetType: targets[0].getId()});
        Ametys.clipboard.Clipboard.setData (targets[0].getId(), data);
    },

    /**
     * Paste a file or a folder previously saved in clipboard
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    paste: function (controller)
    {
        if (Ametys.clipboard.Clipboard.getType() != Ametys.message.MessageTarget.SKIN_RESOURCE && Ametys.clipboard.Clipboard.getType() != Ametys.message.MessageTarget.SKIN_COLLECTION)
        {
            return;
        }

        var targets = controller.getMatchingTargets();
        if (targets.length == 0)
        {
            return;
        }

        var clipboardData = Ametys.clipboard.Clipboard.getData();
        if (Ext.isEmpty(clipboardData))
        {
        	return;
        }
        
        var skinName = clipboardData[0].skinName;

        if (clipboardData[0].mode == 'cut')
        {
        	// First check that file is not currently in edition
        	var id = clipboardData[0].path.replace(/\//g, "-");
		   	var tool = Ametys.tool.ToolsManager.getTool("uitool-skin-file-editor$" + id);
            if (tool != null)
            {
                Ametys.Msg.alert("{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE}}", "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_OPEN}}");
                return;
            }

            this.move(clipboardData[0].skinName, clipboardData[0].path, targets[0].getParameters().path, clipboardData[0].messageTargetType);
        }
        else
        {
            this.doCopy(clipboardData[0].skinName, clipboardData[0].path, targets[0].getParameters().path, clipboardData[0].messageTargetType);
        }

        Ametys.clipboard.Clipboard.setData (targets[0].getId(), null);
    },

    /**
     * Move the selected file or folder to the target path
     * @param {String} skinName The name of the skin
     * @param {String} srcPath The path of the file or folder to move
     * @param {String} targetPath The path where the file or folder will be moved
     * @param {String} messageTargetType The message target type concerned by the move.
     */
    move: function (skinName, srcPath, targetPath, messageTargetType)
    {
        Ametys.data.ServerComm.callMethod({
            role: 'org.ametys.plugins.skineditor.resources.SkinResourceDAO',
            methodName: 'moveSource',
            parameters: [skinName, srcPath, targetPath],
            callback: {
                scope: this,
                handler: this._moveCb,
                arguments:
                {
                    skinName: skinName,
                    oldPath: srcPath,
                    messageTargetType: messageTargetType
                }
            },
            errorMessage: {
                msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_ERROR}}",
                category: this.self.getName()
            },
            waitMessage: true
        });
    },

    /**
     * Callback for the {#_move} function
     * @param {Object[]} response The data from the move action
     * @param {Object[]} args The arguments sent to the callback function
     * @private
     */
    _moveCb: function (response, args)
    {
        if (!response.success && response.msg == 'already-exists')
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE}}",
                msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_ALREADY_EXISTS}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
            return;
        }
        else if (!response.success && response.msg == 'no-exists')
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE}}",
                msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_NO_EXISTS}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
            return;
        }

        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.MOVED,
            parameters: {oldPath: args.oldPath},
            targets: {
                id: args.messageTargetType,
                parameters: {
                    name: response.name,
                    path: response.path,
                    skinName: response.skinName
                }
            }
        });
    },

    /**
     * @private
     * Copy the selected file or folder to the target path
     * @param {String} skinName The name of the skin
     * @param {String} path The path of file/folder to copy
     * @param {String} targetPath The path where the file or folder will be copied
     * @param {String} messageTargetType The message target type concerned by the copy.
     */
    doCopy: function (skinName, path, targetPath, messageTargetType)
    {
        Ametys.data.ServerComm.callMethod({
            role: 'org.ametys.plugins.skineditor.resources.SkinResourceDAO',
            methodName: 'copySource',
            parameters: [skinName, path, targetPath],
            callback:
            {
                scope: this,
                handler: this._copyCb,
                arguments:{
                	skinName: skinName,
                    parentPath: targetPath,
                    messageTargetType: messageTargetType
                }
            },
            errorMessage: {
                msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_ERROR}}",
                category: this.self.getName()
            },
            waitMessage: true
        });
    },

    /**
     * Callback invoked after copying source
     * @param {Object[]} response The data from the copy action
     * @param {Object[]} args The arguments sent to the callback function
     * @private
     */
    _copyCb: function (response, args)
    {
        if (!response.success && response.error == 'already-exists')
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_COPY}}",
                msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_COPY_ALREADY_EXISTS}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
            return;
        }
        else if (!response.success && response.error == 'no-exists')
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_COPY}}",
                msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_COPY_NO_EXISTS}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
            return;
        }

        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.CREATED,
            parameters: {parentPath: args.parentPath},
            targets:
            {
                id: args.messageTargetType,
                parameters: {
                    name: response.name,
                    path: response.path,
                    skin: response.skinName
                }
            }
        });
    }

});