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

/**
 * Helper for editing a user
 * @private
 */
Ext.define('Ametys.plugins.coreui.users.EditUserHelper', {
	singleton: true,
	
	/**
	 * @property {Boolean} _chooseUserDirectoryInitialized True if the dialog box for choosing user directory is initialized.
	 * @private
	 */
	/**
	 * @property {String} _mode The current edition mode ('new' or 'edit')
	 * @private
	 */
	/**
	 * @property {String} _usersMessageTargetType The type of message target for user
	 * @private
	 */
    /**
     * @property {Ametys.window.DialogBox} _chooseUserDirectoryDialog The dialog box for choosing the population and the user directory before creating a user.
     * @private
     */
    /**
     * @property {Ametys.window.DialogBox} _box The dialog box for creating/editing a user.
     * @private
     */
	
    /**
     * @property {Ext.XTemplate} _importResultTpl Template for result of import
     * @private
     */
    _importResultTpl: Ext.create('Ext.XTemplate',
            "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_INTRO}}",
            "<ul>",
                "<li>{[this.format('{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_ADDED}}', '{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_ADDED_SINGLE}}', values.addedCount)]}</li>",
                "<li>{[this.format('{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_UPDATED}}', '{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_UPDATED_SINGLE}}', values.existingCount)]}</li>",
                "<li>{[this.format('{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_DELETED}}', '{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_DELETED_SINGLE}}', values.deletedCount)]}</li>",
                "<tpl if='errorCount &gt; 0'>",
                    "<li>{[this.format('{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_ERROR}}', '{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_ERROR_SINGLE}}', values.errorCount)]}</li>",
                "</tpl>",
            "</ul>",
            "<tpl if='errorCount &gt; 0'>",
                "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_MESSAGE_ERROR_SEE_LOGS}}",
            "</tpl>",
            {
                format: function(multiFormat, singleFormat, count)
                {
                    return count > 1 ? Ext.String.format(multiFormat, count) : Ext.String.format(singleFormat, count);
                }
            }
    ),
    
	/**
	 * Open dialog box to create a new user
	 * @param {String[]} populationContexts The contexts for the populations to display in the combobox.
	 * @param {String} [userMessageTargetType=user] the type of user message target
	 * @param {String} [userToolRole] The role of users tool
     * @param {Boolean} [userPopulationOnly] true if the dialog should proposed only directories of its own population
	 * @param {Function} [callback] the callback function. Parameters are:
	 * @param {Object} callback.user The user's properties
	 */
	add: function (populationContexts, userMessageTargetType, userToolRole, userPopulationOnly, callback)
	{
		this._mode = 'new';
		this._userMessageTargetType = userMessageTargetType;
		this._callback = callback;
        
        if (!this._chooseUserDirectoryInitialized)
        {
            var directoryField = this._createDirectoryField(userToolRole, userPopulationOnly);
            
		    this._chooseUserDirectoryDialog = Ext.create('Ametys.window.DialogBox', {
		        title: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_ADD_TITLE}}",
		        icon: Ametys.getPluginResourcesPrefix('core-ui') + '/img/users/add_16.png',
		        
		        layout: {
		            type: 'vbox',
		            align : 'stretch',
		            pack  : 'start'
		        },
		        width: 450,
                
		        defaultFocus: 'userDirectories',
		        items: [
		            {
		                xtype: 'component',
                        html: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_CHOOSE_USER_DIRECTORY_HINT}}",
                        height: 25
		            },
                    directoryField
		        ],
		        
		        closeAction: 'hide',
		        
		        referenceHolder: true,
		        defaultButton: 'next',
		        
		        buttons : [{
		        	reference: 'next',
		            text: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_NEXT}}",
		            handler: Ext.bind(function() {
                        var userDirectoryField = this._chooseUserDirectoryDialog.items.getByKey('userDirectories');
                        if (!userDirectoryField.isValid())
                        {
                            return;
                        }
                        var userDirectoryValue = userDirectoryField.getValue().split('#', 2);
                        this._open(userDirectoryValue[0], userDirectoryValue[1], null);
                        this._chooseUserDirectoryDialog.close();
		            },this)
		        }, {
		            text: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_CANCEL}}",
		            handler: Ext.bind(function() {this._chooseUserDirectoryDialog.close();}, this)
		        }]
		    });
            
            this._chooseUserDirectoryInitialized = true;
        }

        this._chooseUserDirectoryDialog.show();
	},
	
	/**
	 * Open dialog box to to edit user's information
	 * @param {String} login The login of user to edit
	 * @param {String} populationId The id of the population of the user
	 * @param {String} [userMessageTargetType=user] the type of user message target
	 * @param {Function} [callback] the callback function. Parameters are:
	 * @param {Object} callback.user The user's properties
	 */
	edit: function (login, populationId, userMessageTargetType, callback)
	{
		this._mode = 'edit';
		this._userMessageTargetType = userMessageTargetType;
		this._callback = callback;
		
		this._open (populationId, null, login);
	},
    /**
     * Open dialog box to bulk import users
     * @param {String} [userToolRole] The role of users tool
     * @param {Boolean} [userPopulationOnly] true if the dialog should proposed only directories of its own population
     * @param {Function} [callback] function called with true/false if success/error
     */
    importUsers: function (userToolRole, userPopulationOnly, callback)
    {
        this._importCallback = callback;
        if (this._importDialog == null)
        {
            this._importDialog = this._createImportDialogBox(userToolRole, userPopulationOnly);
        }
        this._importDialog.show();
        this._initImportForm();
    },

    /**
     * Create a new Select User Directory field
     * @private
     * @param {String} [userToolRole] The role of users tool
     * @param {Boolean} [userPopulationOnly] true if the dialog should proposed only directories of its own population
     * @return {Ametys.form.field.SelectUserDirectory} a new Select User Directory field
     */
    _createDirectoryField: function(userToolRole, userPopulationOnly)
    {
            var directoryField = Ext.create("Ametys.form.field.SelectUserDirectory", {
                itemId: 'userDirectories',
                name: 'userDirectories',
                labelWidth: 150,
                allowBlank: false,

                onlyModifiable: true,
                showLabels: true,
                showDescriptions: true,
                userPopulationOnly: userPopulationOnly,
                layout: {
                    type: 'vbox',
                    align : 'stretch',
                    pack  : 'start'
                }
            });
            directoryField.getStore().on('load', function(store, records) {
                if (records.length == 0)
                {
                    if (this._chooseUserDirectoryDialog)
                    {
                        this._chooseUserDirectoryDialog.close();
                    }
                    Ametys.Msg.show({
                        title: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_NO_MODIFIABLE_POPULATION_WARNING_TITLE}}",
                        msg: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_NO_MODIFIABLE_POPULATION_WARNING_MSG}}",
                        buttons: Ext.Msg.OK,
                        icon: Ext.MessageBox.INFO
                    });
                }
                else
                {
                    directoryField._userPopulations.select(records[0].get('id'));

                    // If UserTool opened, try to select the same values in the comboboxes
                    if (userToolRole)
                    {
                        var tool = Ametys.tool.ToolsManager.getTool(userToolRole);
                        if (tool != null)
                        {
                            var value = tool.getPopulationComboValue();
                            if (value && value != '#all')
                            {
                                directoryField.setValue(value); // First set the first combobox to update the second one

                                var userDirectoryId = tool.getUserDirectoryComboValue();
                                if (directoryField._userDirectories.getStore().findExact('index', userDirectoryId) >= 0) // test if the value selected in the tool is present in the dialog box
                                {
                                    value += "#" + userDirectoryId;
                                    directoryField.setValue(value);
                                }
                            }
                        }
                    }
                }
            }, this);
        directoryField.getStore().load();
        return directoryField;
    },

	/**
	 * @private
	 * Show dialog box for user edition
	 * @param {String} populationId The id of the population of the user. Cannot be null
	 * @param {String} userDirectoryId The id of the user directory in its population. Can be null in 'edit' mode
	 * @param {String} login The user's login. Can be null in 'new' mode
	 */
	_open: function (populationId, userDirectoryId, login)
	{
		var me = this;
		function configureCallback (success)
		{
			if (success)
			{
				me._box.show();
				me._initForm (login, populationId);
			}
		}
		
		// Create dialog box if needed
		this._createDialogBox(login, populationId, userDirectoryId, configureCallback);
	},
	
	/**
	 * @private
	 * Creates the dialog if needed.
     * @param {String} login The user's login. Can be null in 'new' mode.
     * @param {String} populationId The id of the population of the user. Cannot be null.
     * @param {String} userDirectoryId The index of the user directory in its population. Can be null in 'edit' mode
	 * @param {Function} callback Function to called after drawing box.
	 */
	_createDialogBox: function (login, populationId, userDirectoryId, callback)
	{
		this._form = Ext.create('Ametys.form.ConfigurableFormPanel', {
            'fieldNamePrefix': '',
			
			defaultFieldConfig: {
				labelWidth: 100
			}
		});
		
		this._box = Ext.create('Ametys.window.DialogBox', {
			title: this._mode == 'new' ? "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_ADD_TITLE}}" : "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_EDIT_TITLE}}",
			iconCls: 'ametysicon-black302' + (this._mode == 'new' ? ' ametysicon-add64' : ' ametysicon-edit45'),
			
			layout: 'fit',
			width: 500,
			maxHeight: 500,
			
			items: [ this._form ],
			
			closeAction: 'hide',
			
			referenceHolder: true,
			defaultButton: 'validate',
			
			buttons : [{
				reference: 'validate',
				text: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_OK}}",
				handler: Ext.bind(this._validate, this, [populationId, userDirectoryId])
			}, {
				text: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_CANCEL}}",
				handler: Ext.bind(function() {this._box.hide();}, this)
			}]
		});
		
		this._configureForm(login, populationId, userDirectoryId, callback);
	},
	
	/**
	 * @private
	 * Configures the user edition form.
     * @param {String} login The user's login. Can be null in 'new' mode.
     * @param {String} populationId The id of the population of the user. Cannot be null.
     * @param {Number} userDirectoryId The id of the user directory in its population. Can be null in 'edit' mode
	 * @param {Function} callback Function to called after drawing box.
	 */
	_configureForm: function (login, populationId, userDirectoryId, callback)
	{
		Ametys.data.ServerComm.callMethod({
			role: "org.ametys.plugins.core.user.UserDAO",
			methodName: this._mode == "new" ? "getEditionModelForDirectory" : "getEditionModelForUSer",
			parameters: this._mode == "new" ? [populationId, userDirectoryId] : [login, populationId],
			callback: {
				handler: this._getEditionModelCb,
				scope: this,
				arguments: [callback]
			},
			errorMessage: true
		});
	},
	
	/**
	 * @private
	 * Callback function after retrieving user's edition model. Configure the form.
	 * @param {Object} view the user's edition view
	 * @param {Object[]} args the callback arguments.
	 */
	_getEditionModelCb: function (view, args)
	{
        var model = view.elements;
		model['password'].widget = 'edition.changepassword';
		this._form.configure(model);
		
		args[0](true);
	},
	
	/**
	 * @private
	 * Initialize the form
	 * @param {String} [login] The user's login. Can not be null in edition mode.
	 * @param {String} [populationId] The id of the population of the user. Can not be null in edition mode.
	 */
	_initForm: function (login, populationId)
	{
		if (this._mode == 'new')
		{
			this._form.reset();
            this._form.setValues(); // setValues must always be called for configurable form panel in order to complete its initialization
			this._form.getForm().findField('login').enable();
			this._form.getForm().findField('login').focus();
		}
		else
		{
			Ametys.plugins.core.users.UsersDAO.getStoredUser([login, populationId], this._getUserCb, {scope: this});
		}
	},
	
	/**
	 * @private
	 * Callback function invoked after retrieving user's properties
	 * Initialize the form
	 * @param {Object} user the user's properties
	 */
	_getUserCb: function (user)
	{
	    user.password = "PASSWORD" ;
		this._form.setValues({values: user, comments: {}, repeaters: []});
		this._form.getForm().findField('login').disable();
		
		// focus first field != changepasswordfield
        this._form.getForm().getFields().each(function(item, index, length) {
            if (item.isDisabled() || item.type == 'password')
            {
                return true;
            }
            else
            {
                item.focus(true);
                return false;
            }
        });
	},
	
	/**
	 * @private
	 * Validates the dialog box.
	 * Creates or edits user.
     * @param {String} populationId The id of the population the user belongs to ('edit' mode) or where the user has to be created ('new' mode)
     * @param {String} userDirectoryId The index of the user directory in its population. Can be null in 'edit' mode
	 */
	_validate: function(populationId, userDirectoryId)
	{
		if (!this._form.isValid())
		{
			return;
		}
		
		var values = this._form.getValues();
		if (this._mode == 'new')
		{
			Ametys.plugins.core.users.UsersDAO.addUser([populationId, userDirectoryId, values, this._userMessageTargetType], this._editUserCb, {scope: this, waitMessage: {target: this._box}});
		}
		else
		{
			values.login = this._form.getForm().findField('login').getValue(); // disabled field
			Ametys.plugins.core.users.UsersDAO.editUser([populationId, values, this._userMessageTargetType], this._editUserCb, {scope:this, waitMessage: {target: this._box}});
		}
	},

	/**
	 * @private
	 * Callback function invoked after group creation/edition process is over.
	 * @param {Object} user the added/edited user or the errors
	 * @param {Object} args the callback arguments
	 */
	_editUserCb: function (user, args)
	{
		if (user.errors)
		{
			var errors = user.errors;
            
            var me = this;
            Ext.Object.each(errors, function(fieldName, fieldErrors) {
                var fd = me._form.getField(fieldName);
                if (fd)
                {
                    if (fieldErrors && fieldErrors.errors)
                    {
                        var msgError = [];
	                    Ext.Array.forEach(fieldErrors.errors, function(fieldError) {
	                        msgError.push(fieldError);
	                    });
	                    fd.markInvalid(msgError.join("<br>"));
                    }
                    else
                    {
                        fd.markInvalid("{{i18n PLUGINS_CORE_UI_USERS_DIALOG_INVALID_FIELD}}");
                    }
                }
            });
            
			return;
		}
		
		this._box.hide();
		
		if (Ext.isFunction (this._callback))
		{
			this._callback (user)
		}
	},

    /**
     * Create the dialog box for importing users.
     * @param {String} [userToolRole] The role of users tool
     * @param {Boolean} [userPopulationOnly] true if the dialog should proposed only directories of its own population
     * @return {Ametys.window.DialogBox} The importing dialog box
     * @private
     */
    _createImportDialogBox: function(userToolRole, userPopulationOnly)
    {
        var formPanel = Ext.create('Ext.form.Panel', {
            border: false,
            itemId: 'importForm',
            scrollable: false,

            defaults: {
                cls: 'ametys',
                labelSeparator: '',
                labelAlign: 'right',
                labelWidth: 150,
                anchor: '100%'
            },
            items: [
                {
                    xtype: 'component',
                    cls: 'a-text',
                    html: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_CHOOSE_USER_DIRECTORY_HINT}}"
                },
                this._createDirectoryField(userToolRole, userPopulationOnly),
                {
                    xtype: 'fileuploadfield',
                    id: 'importFile',
                    name: 'importFile',
                    fieldLabel: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_DIALOG_FILE_LABEL}}",
                    ametysDescription: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_FILE_DESC}}",
                    allowBlank: false,
                    emptyText: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_FILE_EMPTY_TEXT}}",
                    buttonText: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_FILE_BUTTON}}"
                },
                {
                    xtype: 'checkbox',
                    name: 'cleanDirectory',
                    inputValue: 'true',
                    hideLabel: true,
                    style: {
                        marginLeft: '150px'
                    },
                    boxLabel: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_CLEAN_DIRECTORY_LABEL}}",
                    ametysDescription: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_CLEAN_DIRECTORY_DESC}}",
                    checked: false
                }
            ]
        });

        var dialog = Ext.create('Ametys.window.DialogBox', {
            layout: 'fit',

            title: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_TITLE}}",
            iconCls: 'ametysicon-black302 decorator-ametysicon-upload119',

            width: 550,
            scrollable: false,

            items: [
                    formPanel
                ],

            closeAction: 'hide',
            buttons: [{
                text: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_OK}}",
                handler: Ext.bind(this._okImport, this)
            }, {
                text: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_CANCEL}}",
                handler: Ext.bind(this._cancelImport, this)
            }]
        });

        return dialog;
    },

    /**
     * Initializes the import form.
     * @private
     */
    _initImportForm: function()
    {
        var form = this._importDialog.getComponent('importForm').getForm();
        form.findField('importFile').reset();
        form.findField('cleanDirectory').setValue(false);
    },

    /**
     * The action to perform when the user clicks on the OK button from the importing dialog box.
     * @param {Ext.button.Button} button The clicked button.
     * @param {Ext.event.Event} event The click event.
     * @private
     */
    _okImport: function(button, event)
    {
        var form = this._importDialog.getComponent('importForm').getForm();
        var clean = form.findField('cleanDirectory').checked;

        if (clean)
        {
            Ametys.Msg.confirm("{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_DIALOG_WAIT_TITLE}}",
                    "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_CLEAN_CONFIRM}}",
                    function(answer) {
                        if (answer == 'yes')
                        {
                            this._doImport();
                        }
                    },
                    this
            );
        }
        else
        {
            this._doImport();
        }
    },

    /**
     * The action to perform when the user clicks on the cancel button from the importing dialog box.
     * @param {Ext.button.Button} button The clicked button.
     * @param {Ext.event.Event} event The click event.
     * @private
     */
    _cancelImport: function(button, event)
    {
        this._importDialog.hide();
    },

    /**
     * The action to perform when the user confirmed the import.
     * @private
     */

    _doImport: function()
    {
        var form = this._importDialog.getComponent('importForm').getForm();

        if (form.isValid())
        {
            form.submit({
                url: Ametys.getPluginDirectPrefix('core-ui') + '/users/import',
                params : Ametys.getAppParameters(),
                
                waitTitle: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_DIALOG_WAIT_TITLE}}",
                waitMsg: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_DIALOG_WAIT_MSG}}",

                success: Ext.bind(this._successImport, this),
                failure: Ext.bind(this._failureImport, this)
            });
        }
    },

    /**
     * The callback that will be invoked after a successful response
     * @param {Ext.form.Basic} form The form that requested the action.
     * @param {Ext.form.action.Action} action The Action object which performed the operation.
     * @private
     */
    _successImport: function(form, action)
    {
        var result = Ext.applyIf(action.result, {
            addedCount: 0,
            existingCount: 0,
            deletedCount: 0,
            errorCount: 0
        })
        
        var message = this._importResultTpl.applyTemplate(result);

        Ametys.Msg.show({
            title: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_SUCCESS_TITLE}}",
            msg: message,
            buttons: Ext.Msg.OK,
            icon: Ext.MessageBox.INFO
        });
        
        var userDirectoryValue = form.findField("userDirectories").getValue();
        var userDirectoryValues = userDirectoryValue.split('#', 2);
        var populationId = userDirectoryValues[0];
        //fake message to refresh tool
        if (result.addedCount > 0 || result.existingCount > 0 || result.deletedCount > 0)
        {
            Ext.create('Ametys.message.Message', {
                    type: Ametys.message.Message.CREATED,
                    targets: {
                        id: Ametys.message.MessageTarget.USER,
                        parameters: {
                           id: "fake-login", // bad way of doing it, but it can be dangerous to send a full list of users, there can be sooooo many
                           populationId: populationId
                       }
                    }
                });
        }
        this._importDialog.hide();
        if (Ext.isFunction (this._importCallback))
        {
            this._importCallback (true)
        }
    },

    /**
     * The callback that will be invoked after a failed transaction attempt.
     * @param {Ext.form.Basic} form The form that requested the action.
     * @param {Ext.form.action.Action} action The Action object which performed the operation.
     * @private
     */
    _failureImport: function(form, action)
    {
        var message = action.result.message;

        Ametys.Msg.show({
            title: "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_ERROR_TITLE}}",
            msg: message || "{{i18n PLUGINS_CORE_UI_USERS_DIALOG_IMPORT_ERROR_MSG}}",
            buttons: Ext.Msg.OK,
            icon: Ext.MessageBox.ERROR
        });

        if (Ext.isFunction (this._importCallback))
        {
            this._importCallback (false)
        }
    }
});