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

/**
 * Action for creating a new right
 */
Ext.define('Ametys.plugins.coreui.rights.ManageRightAction', {
    singleton: true,
    
    /**
    * @private
    * @property {String[]} _unavailableIds list of used rights ids
    */
    
    /**
    * @private
    * @property {Ametys.window.DialogBox} _dialogBox the creation dialog box for rights
    */
    
    /**
    * @private
    * @property {Ametys.window.DialogBox} _deletionDialogBox the deletion dialog box for rights
    */
    
    /**
     * Initialize dialog box for adding a right
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    addRight: function(controller)
    {
        Ametys.data.ServerComm.callMethod({
           role: "org.ametys.core.ui.right.ExternalRightsDAO",
           methodName: "getRightsIds",
           parameters: [],
           callback: {
               handler: this._getRightsIdsCB,
               scope: this
            },
           waitMessage: true,
           errorMessage: { msg: "{{i18n PLUGINS_CORE_UI_MANAGE_RIGHT_SERVER_ERROR}}" }
       });   
    },
    
    /**
     * @private
     * Callback of getRightsIds, set unavailableIds, reset fields and show dialogBox
     * @param {String[]} response the list of unavailable ids
     */
    _getRightsIdsCB: function(response)
    {
        this._unavailableIds = response;
        if (!this._dialogBox)
        {
            this._createDialogBox()
        }
        this._initializeForm();
        this._dialogBox.show();
        
    },
    
    /**
     * @private
     * Initialize form fields
     */
    _initializeForm: function()
    {
        this._idChanged = false;
        this._dialogBox.getComponent('id').reset();
        this._dialogBox.getComponent('label').reset();
        this._dialogBox.getComponent('description').reset();
    },
    
    /**
     * @private
     * Validator for id field
     * @param {String} id the id value to check
     * @returns {Object} true if pass validation, error msg if not
     */
    _idValidator: function(id)
    {
        return this._unavailableIds.includes(id)
                ? "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_ID_ERROR}}"
                : true;
    },
    
    /**
     * @private
     * Create a dialog box
     */
    _createDialogBox()
    {
        this._dialogBox = Ext.create('Ametys.window.DialogBox',  {
            title : "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_TITLE}}",
            iconCls: "ametysicon-add64",
            width:400,
            
            layout: 'anchor',
            defaults:
            {
                msgTarget: "side",
                cls: 'ametys',
                padding: 5,
                anchor: '100%',
                labelAlign: "top",
                labelSeparator: "",
                labelStyle: "font-weight:bold",
            },
            items : [
                {
                    name: 'label',
                    itemId: 'label',
                    xtype:'textfield',
                    fieldLabel: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_LABEL}} *",
                    ametysDescription: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_LABEL_DESC}}",
                    allowBlank: false
                },
                {
                    name: 'description',
                    itemId: 'description',
                    xtype:'textfield',
                    fieldLabel: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_DESCRIPTION}} *",
                    ametysDescription: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_DESCRIPTION_DESC}}",
                    allowBlank: false
                },
                {
                    xtype: "textfield",
                    name: 'id',
                    itemId: 'id',
                    allowBlank: false,
                    fieldLabel: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_ID}} *",
                    ametysDescription: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_ID_DESC}}",
                    enableKeyEvents: true,
                    regex: /^[a-zA-Z\_]*$/,
                    regexText: "{{i18n PLUGINS_CORE_UI_INVALID_CHARACTER_RIGHT_ID_ERROR}}",
                    validator: Ext.bind(this._idValidator, this)
                },
                {
                    xtype: "combobox",
                    name: 'category',
                    itemId: 'category',
                    fieldLabel: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_CATEGORY_LABEL}} *",
                    ametysDescription: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_CATEGORY_DESC}}",
                    store: this._getCategoriesStore(),
                    queryMode: 'local',
                    allowBlank: false,
                    displayField: 'label',
                    valueField: 'id',
                    editable: false
                }
            ],
            defaultFocus: 'label',
            selectDefaultFocus: true,
            closeAction: 'hide',
            
            referenceHolder: true,
            defaultButton: 'validate',
            
            buttons : [
                {
                    reference: 'validate',
                    text: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_OK_BTN}}",
                    handler: Ext.bind(this._ok, this)
                },
                {
                    text: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_CANCEL_BTN}}",
                    handler: Ext.bind(this._hideDialogBox, this)
                }
            ]
        });
        
        var labelField = this._dialogBox.getComponent('label');
        var idField = this._dialogBox.getComponent('id');
        labelField.addListener("change", function(field, value) 
        {
            if (!this._idChanged && value && Object.values(value).length > 0)
            {
                var id = (Ext.String.deemphasize(value)).replace(/[^a-zA-Z]/gi, "_");
                idField.setValue(id);
            }
        }, this);
        idField.addListener("keyup", function(field, value) 
        {
            this._idChanged = true;
        }, this);
        
    },
    
    /**
     * @private
     * Get the category combobox's store data
     * @returns {Ext.data.Store} the category store
     */
    _getCategoriesStore: function()
    {
        var store = Ext.create('Ext.data.Store', {
            fields: ['id', 'label'], 
            autoload: true,
            sorters: [{
                property: 'label',
                direction: 'ASC'
            }],
            proxy: {
                type: 'ametys',
                role: 'org.ametys.core.ui.right.ExternalRightsDAO',
                methodName: 'getRightsCategories',
                methodArguments: [],
                reader: {
                    type: 'json',
                    rootProperty: 'data'
                }
             },
             autoLoad: true,
             sortOnLoad: true
        })
        return store;
    },
    
    /**
     * @private
     * Add the right to server 
     */
    _ok: function ()
    {
        if (this._hasInvalid(this._dialogBox))
        {
            return;
        }
        var id = this._dialogBox.getComponent('id').getValue();
        var label = this._dialogBox.getComponent('label').getValue();
        var description = this._dialogBox.getComponent('description').getValue();
        var category = this._dialogBox.getComponent('category').getValue();
        
        Ametys.data.ServerComm.callMethod({
           role: "org.ametys.core.ui.right.ExternalRightsDAO",
           methodName: "addRight",
           parameters: [
               id,
               label, 
               description,
               category
           ],
           callback: {
               handler: this._okCB,
               scope: this
            },
           waitMessage: true,
           errorMessage: { msg: "{{i18n PLUGINS_CORE_UI_MANAGE_RIGHT_SERVER_ERROR}}" }
       });   
    },
    
    /**
     * @private
     * Callback of _ok, show message of success or failure
     * @param {Object} response the server response
     * @param {String} response.message an error message, can be undefined when success
     * @param {String} response.id id of the right added, can be undefined when failure
     */
    _okCB: function(response)
    {
        if(!response.message)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.CREATED,
                targets: {
                    id: Ametys.message.MessageTarget.RIGHT,
                    parameters: {id: response.id}
                }
            });
            
            Ametys.notify({
                type: 'info',
                title: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_SUCCESS_TITLE}}",
                description: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_SUCCESS}}",
                icon: Ext.Msg.INFO
            });
        }
        else
        {
            var msg = response.message == "duplicate-id"
                ? "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_ERROR_DUPLICATE}}"
                : "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_ERROR}}";
            Ametys.notify({
                type: 'error',
                title: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_ERROR_TITLE}}",
                description: msg,
                icon: Ext.Msg.ERROR
            });
        }
        this._dialogBox.hide();
    },
    
    /**
     * @private
     * Hide the creation dialog box
     */
    _hideDialogBox: function ()
    {
        this._dialogBox.hide();
    },
    
    /**
     * @private
     * Return true if a field is invalid
     * @param {Ametys.window.DialogBox} box the dialog box
     */
    _hasInvalid: function(box)
    {
        var fields = box.query("[isFormField]");
        var hasInvalid = false;
        for (let field of fields)
        {
            if (!field.isValid())
            {
                hasInvalid = true;
            }
        }
        return hasInvalid;
    },
    
    /**
     * Initialize and open dialog box to delete a right
     */
    removeRight: function()
    {
        if (!this._deletionDialogBox)
        {
            this._createDeletionDialogBox()
        }
        var comboRights = this._deleteRightsPanel.getComponent("rights");
        var me = this;
        comboRights.reset();
        comboRights.getStore().load({
            callback: function(){
                 var rights = comboRights.getStore().getData().items;
                 if (rights.length == 0)
                 {
                     me._deleteRightsPanel.mask("{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_DIALOG_INTRO_NO_RIGHT}}", "ametys-mask-unloading");
                     me._deletionDialogBox.down("#validate").disable();
                 }
                 else
                 {
                     me._deleteRightsPanel.unmask();
                     me._deletionDialogBox.down("#validate").enable();
                 }
                 me._deletionDialogBox.show();
             }
        });
    },
    
    /**
     * @private
     * Create a dialog box for deleting a right
     */
    _createDeletionDialogBox()
    {
        this._deleteRightsPanel = Ext.create('Ext.Container', {
            layout: 'anchor',
            border: false,
            width:400,
            defaults:
            {
                msgTarget: "side",
                cls: 'ametys',
                padding: 5,
                anchor: '100%',
                labelAlign: "top",
                labelSeparator: "",
                labelStyle: "font-weight:bold",
            },
            items: [
                {
                    xtype: 'component',
                    cls: 'a-text',
                    itemId: 'deleteRightsIntro',
                    html: "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_DIALOG_INTRO}}"
                },
                {
                    xtype: "combobox",
                    name: 'rights',
                    itemId: 'rights',
                    fieldLabel: "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_DIALOG_RIGHTS_LABEL}} *",
                    ametysDescription: "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_DIALOG_RIGHTS_DESC}}",
                    store: this._getRightsToDeleteStore(),
                    queryMode: 'local',
                    allowBlank: false,
                    displayField: 'label',
                    valueField: 'id',
                    editable: false
                }
            ],
        });
        
        this._deletionDialogBox = Ext.create('Ametys.window.DialogBox',  {
            title : "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_DIALOG_TITLE}}",
            iconCls: "ametysicon-delete30",
            
            layout: 'fit',
            
            items : [
                this._deleteRightsPanel
            ],
            defaultFocus: 'label',
            selectDefaultFocus: true,
            closeAction: 'hide',
            
            referenceHolder: true,
            defaultButton: 'validate',
            
            buttons : [
                {
                    itemId: 'validate',
                    reference: 'validate',
                    text: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_OK_BTN}}",
                    handler: Ext.bind(this._confirmDeletion, this)
                },
                {
                    text: "{{i18n PLUGINS_CORE_UI_ADD_RIGHT_DIALOG_CANCEL_BTN}}",
                    handler: Ext.bind(function() {this._deletionDialogBox.hide();}, this) 
                }
            ]
        });
    },
    
    /**
     * @private
     * Get the rights combobox's store data
     * @returns {Ext.data.Store} the rights store
     */
    _getRightsToDeleteStore: function()
    {
        var store = Ext.create('Ext.data.Store', {
            fields: ['id', 'label'], 
            sorters: [{
                property: 'label',
                direction: 'ASC'
            }],
            proxy: {
                type: 'ametys',
                role: 'org.ametys.core.ui.right.ExternalRightsDAO',
                methodName: 'getRightsToDelete',
                methodArguments: [],
                reader: {
                    type: 'json',
                    rootProperty: 'data'
                }
             },
             autoLoad: true,
             sortOnLoad: true
        })
        return store;
    },
    
    /**
     * @private
     * Send confirmation message for deletion
     */
    _confirmDeletion: function()
    {
        if (this._hasInvalid(this._deletionDialogBox))
        {
            return;
        }
        var rightCombobox = this._deleteRightsPanel.getComponent('rights'),
            rightId = rightCombobox.getValue(),
            rightLabel = rightCombobox.getDisplayValue();
        var msg = Ext.String.format("{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_DIALOG_CONFIRM}}", rightLabel);
        Ametys.Msg.confirm("{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_LABEL}}",
                msg,
                Ext.bind(this._doRemove, this, [rightId], 1),
                this
        );
    },
    
    /**
     * @private
     * Proceed to the right removal
     * @param {String} btn The pressed button. Can only be 'yes'/'no'
     * @param {String} rightId The id of the right to remove.
     */
    _doRemove: function(btn, rightId)
    {
        if (btn == 'yes')
        {
            Ametys.data.ServerComm.callMethod({
                role: "org.ametys.core.ui.right.ExternalRightsDAO",
                methodName: "removeRight",
                parameters: [
                    rightId
               ],
                callback: {
                    handler: this._doRemoveCB,
                    scope: this
                },
                waitMessage: true,
                errorMessage: { msg: "{{i18n PLUGINS_CORE_UI_MANAGE_RIGHT_SERVER_ERROR}}" }
            });   
        }   
    },
    
    /**
     * @private
     * Callback of _doRemove, show message of success or failure
     * @param {Object} response the server response
     * @param {String} response.message an error message, can be undefined
     * @param {String} response.id id of the deleted right, can be null when deletion failed
     */
    _doRemoveCB: function(response)
    {
        if(!response.message)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.DELETED,
                targets: {
                    id: Ametys.message.MessageTarget.RIGHT,
                    parameters: {id: response.id}
                }
            });
            
            Ametys.notify({
                type: 'info',
                title: "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_SUCCESS_TITLE}}",
                description: "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_SUCCESS}}",
                icon: Ext.Msg.INFO
            });
        }
        else
        {
            var msg = response.message == "rigth-used"
                ? "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_ERROR_USED}}"
                : "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_ERROR}}";
            
            Ametys.notify({
                type: 'info',
                title: "{{i18n PLUGINS_CORE_UI_REMOVE_RIGHT_ERROR_TITLE}}",
                description: msg,
                icon: Ext.Msg.ERROR
            });
        }
        this._deletionDialogBox.hide();
    },
    
});