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

/**
 * Helper for tag
 * @private
 */
Ext.define('Ametys.plugins.cms.tag.TagHelper', {
    singleton: true,
    
    /**
     * Function called to add a new tag
     * @param {String} parentId id of the parent of the tag to create
     * @param {Ext.form.Panel} formPanel The form panel
     * @param {String} targetId The target id
     * @param {String} tagDAO The tag DAO class
     * @param {String} boxTitle The box title
     * @param {String} boxIcon The box icon
     * @param {Function} callback the callback after creation
     */
    add: function(parentId, formPanel, targetId, tagDAO, boxTitle, boxIcon, callback)
    {
    	this._mode = "new";
    	this._cbFn = callback;
    	this._targetId = targetId;
    	this._tagDAO = tagDAO;
    	
    	if (!this._delayedInitialize(formPanel))
        {
        	return;
        }
    	
    	this._initCreateForm(parentId, boxTitle, boxIcon);
    },
    
    /**
     * Function called to edit a tag
     * @param {String} id id of the tag to edit
     * @param {Ext.form.Panel} formPanel The form panel
     * @param {String} targetId The target id
     * @param {String} tagDAO The tag DAO class
     * @param {String} boxTitle The box title
     * @param {String} boxIcon The box icon
     * @param {Function} callback the callback after edition
     */
    edit: function(id, formPanel, targetId, tagDAO, boxTitle, boxIcon, callback)
    {
    	this._mode = "edit";
    	this._cbFn = callback;
    	this._targetId = targetId;
    	this._tagDAO = tagDAO;
    	
    	if (!this._delayedInitialize(formPanel))
        {
        	return;
        }
    	
    	this._initEditForm(id, boxTitle, boxIcon);
    },
    
    /**
     * Initialize the dialog box to create or edit a tag. 
     * This method does nothing but returning if the dialog box is already initialized
     * @param {Ext.form.Panel} formPanel The form panel
     * @return {Boolean} return true on success.
     * @private
     */
    _delayedInitialize: function(formPanel)
    {
    	this._form = formPanel.getForm();

        if (this._initialized)
        {
        	var oldFormPanel = this._box.items.getAt(0);
        	if (oldFormPanel !== formPanel)
        	{
        		this._box.remove(oldFormPanel, {destroy: false});
        		this._box.add(formPanel);
        	}
        	return true;
        }
        
        this._box = Ext.create('Ametys.window.DialogBox', {
            title: "{{i18n PLUGINS_CMS_HANDLE_TAGS_CREATE}}",
            iconCls: 'ametysicon-tag25 decorator-ametysicon-add64',
            
            layout: 'fit',
            width: 400,
            
            items: [ formPanel ],
            
            defaultFocus: 'title',
            selectDefaultFocus: true,
            
            referenceHolder: true,
            defaultButton: 'validate',

            closeAction: 'hide',
            
            buttons: [{
            	reference: 'validate',
                text: "{{i18n PLUGINS_CMS_HANDLE_DIALOG_BUTTON_OK}}",
                handler : Ext.bind(this._ok, this, []),
                scope: this
            }, {
                text: "{{i18n PLUGINS_CMS_HANDLE_DIALOG_BUTTON_CANCEL}}",
                handler : this._cancel,
                scope: this
            }]
        });
        
        this._initialized = true;
        
        return true;
    },
    
    /**
     * Called when pressing the Ok button on the dialog box
     * @private
     */
    _ok: function ()
    {
        if (this._form.isValid())
        {
            var params = this._form.getValues();            
            if (this._mode === 'new')
            {
            	Ametys.data.ServerComm.callMethod({
        			role: this._tagDAO,
        			methodName: "createTag",
        			parameters: [params.parentID, params.name, params.title, params.description, params, Ametys.getAppParameters()],
        			callback: {
        				scope: this,
        				handler: Ext.bind(this._addTagCb, this, [], 1)
        			},
        			waitMessage: {
                        target: this._box,
                        msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_LOADMASK_DEFAULT_MESSAGE}}"
                    },
                    errorMessage: {
                        msg: "{{i18n PLUGINS_CMS_HANDLE_TAGS_ADD_TAG_ERROR}}",
                        category: this.self.getName()
                    }
        		});
            }
            else
            {
            	Ametys.data.ServerComm.callMethod({
        			role: this._tagDAO,
        			methodName: "updateTag",
        			parameters: [params.id, params.title, params.description, params],
        			callback: {
        				scope: this,
        				handler: Ext.bind(this._editTagCb, this, [], 1)
        			},
        			waitMessage: {
                        target: this._box,
                        msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_LOADMASK_DEFAULT_MESSAGE}}"
                    },
                    errorMessage: {
                        msg: "{{i18n PLUGINS_CMS_HANDLE_TAGS_EDIT_TAG_ERROR}}",
                        category: this.self.getName()
                    }
        		});
            }
        }
    },
    
    /**
     * Callback invoked after adding a tag
     * @param {Object[]} response The JSON response from the server
     * @private
     */
    _addTagCb: function(response) 
    {
    	this._box.hide();
        
    	var tagId = response['tagId'];
        var tagParentId = response['tagParentId'];
        var tagName = response['tagName'];
        
        Ext.create("Ametys.message.Message", {
        	type: Ametys.message.Message.CREATED,
                        
            targets: {
            	id: this._targetId,
                parameters: {
                	id: tagId,
                    parentId: tagParentId,
                    name: tagName
                }
            }
         });
        
        if (Ext.isFunction(this._cbFn))
        {
            this._cbFn (tagId, tagName, tagParentId);
        }
    },
    
    /**
     * Callback invoked after editing a tag
     * @param {Object[]} response The JSON response from the server
     * @private
     */
    _editTagCb: function(response) 
    {
    	this._box.hide();
        
    	var tagId = response['id'];
        var tagName = response['name'];
               
        Ext.create("Ametys.message.Message", {
        	type: Ametys.message.Message.MODIFIED,
                        
            targets: {
            	id: this._targetId,
                parameters: {
                	id: tagId,
                    name: tagName
                }
            }
         });
        
        if (Ext.isFunction(this._cbFn))
        {
            this._cbFn (tagId, tagName);
        }
    },
    
    /**
     * Called when pressing the Cancel button on the dialog box
     * @private
     */
    _cancel: function ()
    {
        this._box.hide();
        
        if (Ext.isFunction(this._cbFn))
        {
            this._cbFn ();
        }
    },
    
    /**
     * Fill the dialog box when creating a new tag
     * @param {String} parentId The id of parent tag for creation mode. Can not be null.
     * @param {String} boxTitle The box title
     * @param {String} boxIcon The box icon
     * @private
     */
    _initCreateForm: function (parentId, boxTitle, boxIcon) 
    {
        this._box.setTitle(boxTitle);
        this._box.setIconCls(boxIcon);
        
        this._form.reset();
        this._form.findField('parentID').setValue(parentId);
        this._form.findField('title').setValue("{{i18n PLUGINS_CMS_HANDLE_TAGS_TITLE_NEW}}");
        var val = this._getAutoKey (this._form.findField('title').getValue());
        this._form.findField('name').setValue(val);
        
        this._box.getDockedItems('toolbar[dock="bottom"]')[0].items.get(0).setDisabled(false);
        
        this._box.show();
    },
    
    /**
     * Fill the dialog box when editing a tag.
     * @param {String} id The id of tag to edit. Can not be null.
     * @param {String} boxTitle The box title
     * @param {String} boxIcon The box icon
     * @private
     */
    _initEditForm: function (id, boxTitle, boxIcon) 
    {
    	this._box.setTitle(boxTitle);
        this._box.setIconCls(boxIcon);
        
        this._form.reset();
        this._box.show();
        
        Ametys.data.ServerComm.callMethod({
			role: this._tagDAO,
			methodName: "getTag",
			parameters: [id],
			callback: {
				scope: this,
				handler: this._getTagCb
			},
			waitMessage: {
                target: this._box,
                msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_LOADMASK_DEFAULT_MESSAGE}}"
            }
		});
    },
    
    /**
     * Callback for #_initForm in edition mode. 
     * @param {Object[]} response The JSON response from the server, containing the tag informations
     * @private
     */
    _getTagCb: function (response) 
    {
        if (response == null)
        {
            Ametys.log.ErrorDialog.display({
                title: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_SERVERCOMM_BADRESPONSE_TITLE}}", 
                text: "{{i18n PLUGINS_CMS_HANDLE_TAGS_EDIT_TAG_UNKNOWN_TAG}}",
                details: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_SERVERCOMM_BADRESPONSE_DESC}} ",
                category: this.self.getName()
            });
            
            this._box.getDockedItems('toolbar[dock="bottom"]')[0].items.get(0).setDisabled(true);
            return;
        }
        
        this._box.getDockedItems('toolbar[dock="bottom"]')[0].items.get(0).setDisabled(false);
        
        for (var key in response)
        {
        	var field = this._form.findField(key);
        	if (field)
        	{
        		field.setValue(response[key]);
        	}
        }
        
        this._form.findField('parentID').setValue('');
    },
    
    /**
     * Delete the tag
     * @param {String} tagId The tag id to delete
     * @param {String} targetId The target id
     * @param {String} tagDAO The tag DAO class
     * @param {String} boxTitle The box title
     * @param {String} boxMsg The box msg
     * @private
     */
    remove: function(tagId, targetId, tagDAO, boxTitle, boxMsg)
    {
    	this._targetId = targetId;
    	this._tagDAO = tagDAO;
    	
    	Ametys.Msg.confirm(boxTitle, 
    			boxMsg, 
                Ext.bind(this._doDelete, this, [tagId], 1)
        );
    },
    
    /**
     * Called in delete mode, delete the tag if the user pressed the "Ok" button
     * @param {String} button The ID of the button pressed
     * @param {String} tagId The tag id to delete
     * @private
     */
    _doDelete: function (button, tagId)
    {   
        if (button == "yes")
        {
            Ametys.data.ServerComm.callMethod({
    			role: this._tagDAO,
    			methodName: "deleteTag",
    			parameters: [tagId, Ametys.getAppParameters()],
    			callback: {
    				scope: this,
    				handler: Ext.bind(this._deleteTagCb, this, [], 1)
    			},
    			errorMessage: {
                    msg: "{{i18n PLUGINS_CMS_HANDLE_TAGS_DELETE_TAG_ERROR}}",
                    category: this.self.getName()
                }
    		});
        }
    },
    
    /**
     * Callback invoked after deleting a tag
     * @param {Object} response The JSON server response
     * @private
     */
    _deleteTagCb: function (response) 
    {
        // get from response
        var id = response['id'];
        var name = response['name'];
        
         Ext.create("Ametys.message.Message", {
             type: Ametys.message.Message.DELETED,
                        
             targets: {
                 id: this._targetId,
                 parameters: {
                     id: id,
                     name: name
                 }
             }
         });
    },
    
    /**
     *  Function called to move one or more tags.
     *  @param {String} target The target id for the move action.
     *  @param {String[]} ids The IDs of the tags to move.
     *  @param {String} tagDAO The tag DAO class
     *  @param {String} targetId The target id
     *  @param {Function} callback A callback function to call when the move is done. Can be null. The arguments are:
     *  @param {String} callback.target The id of target for the move action.
     *  @param {String[]} callback.ids The id of moved tags
     */
    move: function (target, ids, tagDAO, targetId, callback)
    {
        Ametys.data.ServerComm.callMethod({
            role: tagDAO,
            methodName: "moveTags",
            parameters: [ target, ids ],
            callback: {
                handler: Ext.bind(this._moveCb, this, [targetId, callback], true),
                ignoreOnError: false
            },
            waitMessage: {
                msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_LOADMASK_DEFAULT_MESSAGE}}"
            },
            errorMessage: { 
                msg: "{{i18n PLUGINS_CMS_HANDLE_TAGS_MOVE_ERROR}}"
            }
        });
    },
    
   /**
    * Callback function after moving tags
    * @param {Object} response The JSON response from the server, containing the tags informations
    * @param {String} response.target The target id for the move action
    * @param {String[]} response.movedTags The ids of moved tags
    * @param {Object} args The callback arguments
    * @param {String} targetId The target id
    * @param {Function} callback A callback function to call when the move is done. Can be null.
    * @private
    */
    _moveCb: function (response, args, targetId, callback)
    {
        if (!response)
        {
            if (Ext.isFunction(callback))
            {
                callback([]);
            }
            return;
        }
        
        var movedTags = response.movedTags || [];
        if (Ext.isFunction(callback))
        {
            callback(response.target, movedTags, targetId);
        }
    },
    
    /**
     * Listener that fill the name field based on the input in the title field.
     * Does nothing in edit mode.
     */
    autoFillKey: function (input, event)
    {
        var idField = Ametys.plugins.cms.tag.TagHelper._form.findField('id');
        if (idField === undefined || idField.getValue() === "")
        {
            var val = Ametys.plugins.cms.tag.TagHelper._getAutoKey (input.getValue());
            Ametys.plugins.cms.tag.TagHelper._form.findField('name').setValue(val);
        }
    },
    
    /**
     * Generate a valid unique name from the user input in the title field
     * @return {String} valid name
     * @private
     */
    _getAutoKey: function (value)
    {
        var re_a = new RegExp('[áàâäã]','gi');
        var re_e = new RegExp('[éèêë]','gi');
        var re_i = new RegExp('[íìîï]','gi');
        var re_o = new RegExp('[óòôöõ]','gi');
        var re_u = new RegExp('[úùûü]','gi');
        var re_y = new RegExp('[ýÿ]','gi');
        var re_c = new RegExp('[ç]','gi');
        var re_n = new RegExp('[ñ]','gi');
        var re_nalnum = new RegExp('[^a-zA-Z0-9]','gi');
        var re_start = new RegExp('^[^a-zA-Z]');
        
        value = value.replace(re_a,"a");
        value = value.replace(re_e,"e");
        value = value.replace(re_i,"i");
        value = value.replace(re_o,"o");
        value = value.replace(re_u,"u");
        value = value.replace(re_y,"y");
        value = value.replace(re_c,"c");
        value = value.replace(re_n,"n");
        value = value.replace(re_nalnum,"_");
        
        if (re_start.test(value))
        {
            value = 'x_' + value;
        }
        
        value = value.toUpperCase();
        
        return value;
    }
});