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

/**
 * Dialog box displaying a form to edit or create a project
 * @private
 */
Ext.define('Ametys.plugins.workspaces.project.helper.ProjectEdition', {
    singleton: true,
    
    /**
     * @property {Function} _cbFn Optional callback
     * @private
     */
    /**
     * @property {Ametys.plugins.workspaces.project.Project} _project The editing project. Can be null
     * @private
     */
    /**
     * @property {String} _mode The mode of the form (either 'new' for a creation, or 'edit' for an edition)
     */
    
    /**
     * @property {Ext.form.Panel} _form The form panel
     */
    /**
     * @property {Ametys.window.DialogBox} _box The dialog box that contains the form
     */
    
    
    /**
     * @property {Ext.util.DelayedTask} _updateNameTask The task to update the name field. It is used to buffer the execution of the update name method.
     * @private 
     */
    
    /**
     * @property {Boolean} _initialized True if the dialog box was already initialized
     * @private
     */
    _initialized: false,
    
    /**
     * Open and initialize the dialogbox given mode and parameters
     * @param {String} mode The mode: "new" to create a new project, "edit" to edit an existing project
     * @param {Ametys.plugins.workspaces.project.Project} project The project to edit. Can be null on "new" mode
     * @param {Function} callback The callback on successful creation/modification of the project. The arguments are:
     * @param {Function} callback.id The identifier of the created or modified project
     * @param {Object} scope The callback scope
     */
    act: function(mode, project, callback, scope)
    {
        this._mode = mode || 'new';
        this._cbFn = callback;
        this._cbScope = scope;
        this._project = project;
        
        if (!this._isConfigurationComplete())
        {
            Ametys.log.ErrorDialog.display({
                title: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_ERROR_CONFIGURATION}}",
                text: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_ERROR_CONFIGURATION_INCOMPLETE}}",
                category: Ext.getClassName(this)
            });
            return;
        }
        
        this._delayedInitialize();
        this._box.setTitle(this._mode == 'edit' ? "{{i18n PLUGINS_WORKSPACES_PROJECT_EDIT_DIALOG_TITLE}}" : "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_DIALOG_TITLE}}");
        
        this._box.show();
        this._initForm();
    },
    
    /**
     * Ensure that mandatory configuration parameters are present.
     * @return {Boolean} 
     */
    _isConfigurationComplete: function()
    {
        return (this._mode == 'new')
            || (this._mode == 'edit' && this._project.getId());
    },
    
    /**
     * Initialize the dialog box
     * @private
     */
    _delayedInitialize: function()
    {
        if (this._initialized)
        {
            return;
        }
        
        this._form = Ext.create('Ext.form.Panel', {
            border: false,
            
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            
            defaults: {
                cls: 'ametys',
                labelWidth: 120,
                labelAlign: 'right',
                labelSeparator: '',
                msgTarget: 'side'
            },
            
            items: this._getFormItemsCfg()
        });
        
        this._box = Ext.create('Ametys.window.DialogBox', {
            iconCls: 'ametysicon-folder250',
            
            width: 550,
            
            items : [ this._form ],
            closeAction: 'hide',
            defaultFocus: 'title',
            
            referenceHolder: true,
            defaultButton: 'validate',
            
            buttons : [{
                reference: 'validate',
                text :"{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_OK}}",
                handler : this._ok,
                scope: this
            }, {
                text :"{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_CANCEL}}",
                handler: this._cancel,
                scope: this
            }]
        });
        
        this._initialized = true;
        return;
    },
    
    /**
     * Provide the items configuration of the form panel
     * @return {Object/Object[]} the items configuration of the form panel
     */
    _getFormItemsCfg: function()
    {
        var inscriptionStatusStore = Ext.create('Ext.data.Store', {
            fields: ['value', 'text'],
            data : [
                { value: 'open', text: "{{i18n PLUGINS_WORKSPACES_PROJECT_INSCRIPTION_STATUS_ENUM_OPEN}}" },
                { value: 'moderated', text: "{{i18n PLUGINS_WORKSPACES_PROJECT_INSCRIPTION_STATUS_ENUM_MODERATED}}" },
                { value: 'private', text: "{{i18n PLUGINS_WORKSPACES_PROJECT_INSCRIPTION_STATUS_ENUM_PRIVATE}}" }
            ]
         });
        
        return [{
            xtype: 'component',
            cls: 'a-text',
            itemId: 'create-help-text',
            html: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_DIALOG_HELP_TEXT}}"
        }, {
            xtype: 'component',
            cls: 'a-text',
            itemId: 'edition-help-text-title',
            html: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_HELP_TEXT_TITLE}}"
        }, {
            xtype: 'textfield',
            fieldLabel: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_FORM_TITLE}} *",
            ametysDescription: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_FORM_TITLE_DESC}}",
            itemId: 'title',
            name: 'title',
            allowBlank: false,
            regex: /^[0-9-_]*[a-z].*$/i,
            regexText: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_FORM_TITLE_REGEX_ERROR}}",
            listeners: {
                change: {
                    fn: this._updateNameOnTitleChange,
                    scope: this
                }
            }
        }, {
            xtype: 'component',
            cls: 'a-text',
            itemId: 'create-help-text-name',
            html: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_DIALOG_HELP_TEXT_NAME}}"
        }, {
            xtype: 'textfield',
            fieldLabel: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_DIALOG_FORM_NAME}} *",
            ametysDescription: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_DIALOG_FORM_NAME_DESC}}",
            name: 'name',
            allowBlank: false,
            regex: /^[a-z][a-z0-9\.\-_]*$/,
            regexText: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_DIALOG_FORM_NAME_REGEX_ERROR}}"
        }, {
            xtype: 'textarea',
            fieldLabel :"{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_FORM_DESCRIPTION}}",
            ametysDescription: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_FORM_DESCRIPTION_DESC}}",
            name :'description',
            height: 100
        }, {
            xtype: 'textfield',
            fieldLabel: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_FORM_MAILING_LIST}}",
            ametysDescription: "{{i18n PLUGINS_WORKSPACES_PROJECT_EDITION_DIALOG_FORM_MAILING_LIST_DESC}}",
            name: 'mailing-list',
            regex: /^((\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z0-9][A-Za-z0-9]+))|([^<]+<(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z0-9][A-Za-z0-9]+)>)$/,
            regexText: "{{i18n plugin.core:PLUGINS_CORE_REGEXP_INVALID_MAIL}}"
        }, {
            xtype: 'combobox',
            store: inscriptionStatusStore,
            queryMode: 'local',
            displayField: 'text',
            valueField: 'value',
            fieldLabel: "{{i18n PLUGINS_WORKSPACES_PROJECT_INSCRIPTION_STATUS_FORM_NAME}} *",
            ametysDescription: "{{i18n PLUGINS_WORKSPACES_PROJECT_INSCRIPTION_STATUS_FORM_NAME_DESC}}",
            name: 'inscriptionStatus',
            allowBlank: false,
            listeners: {
                'change': this._onChangeInscriptionStatus,
                scope: this
            }
        }, {
            xtype: 'combobox',
            itemId: 'defaultProfile',
            fieldLabel: "{{i18n PLUGINS_WORKSPACES_PROJECT_DEFAULT_PROFILE_FORM_NAME}} *",
            ametysDescription: "{{i18n PLUGINS_WORKSPACES_PROJECT_DEFAULT_PROFILE_FORM_NAME_DESC}}",
            name: 'defaultProfile',
            valueField: 'id',
            displayField: 'label',
            store: {
                autoDestroy: true,
                proxy: {
                    type: 'ametys',
                    role: 'org.ametys.plugins.workspaces.project.ProjectManager',
                    methodName: 'getProjectProfiles',
                    methodArguments: [],
                    reader: {
                        type: 'json',
                        rootProperty: 'profiles'
                    }
                },
                sorters: [{property: 'label', direction: 'ASC'}],
                fields: [
                    {name: 'id'},
                    {name: 'label', type: 'string'}
                ]
            },
            style: {
                marginBottom: '10px'
            }
        }, {
            xtype: 'component',
            cls: 'a-text',
            itemId: 'edit-site-help-text',
            padding: '5 10',
            tpl: new Ext.XTemplate(
                '<a href="#">',
                    '<tpl if="title">',
                        "{{i18n PLUGINS_WORKSPACES_PROJECT_EDIT_DIALOG_SITE_CONFIG_HELP_TEXT}}",
                    '</tpl>',
                '</a>'
            ),
            listeners:
            {
                // add click listener on the link to open the site config.
                afterrender: {
                    scope: this,
                    fn: function(component) {
                        component.addListener({
                            click: {
                                fn: this._openSiteConfig,
                                scope: this,
                                element: 'el',
                                delegate: 'a'
                            }
                        });
                    }
                }
            }
        }]
    },
    
    /**
     * @private
     * Initialize the box form
     */
    _initForm: function ()
    {
        var form = this._form.getForm();
        
        if (this._mode == 'new')
        {
        	form.findField('name').setValue();
            form.findField('name').enable();
        	form.findField('title').setValue();
        	form.findField('description').setValue();
        	form.findField('mailing-list').setValue();
            form.findField('inscriptionStatus').setValue();
            form.findField('defaultProfile').setValue();
            form.findField('defaultProfile').setDisabled(true);
        	
        	this._form.down('#edit-site-help-text').setVisible(false);
        }
        else
        {
        	form.findField('name').setValue(this._project.getName());
            form.findField('name').disable();
        	form.findField('title').setValue(Ext.String.htmlDecode(this._project.getTitle())); // decode previously encoded HTML chars.
            form.findField('description').setValue(this._project.getDescription());
            form.findField('mailing-list').setValue(this._project.getMailingList());
            var inscriptionStatus = this._project.getInscriptionStatus();
            form.findField('inscriptionStatus').setValue(inscriptionStatus);
            form.findField('defaultProfile').setValue(inscriptionStatus !== "open" ? null : this._project.getDefaultProfile());
            form.findField('defaultProfile').setDisabled(inscriptionStatus !== "open");
            
            var site = this._project.getSite();
            if (site != null)
            {
            	this._form.down('#edit-site-help-text').update(site);
            	this._form.down('#edit-site-help-text').setVisible(true);
            }
            else
            {
            	this._form.down('#edit-site-help-text').setVisible(false);
            }
        }
        
        this._form.down('#create-help-text').setVisible(this._mode == 'new');
        this._form.down('#create-help-text-name').setVisible(this._mode == 'new');
        
        form.clearInvalid();
    },
    
    /**
     * @private
     * Compute project's name from title input
     * @param {Ext.form.field.Field} titleField The title field of which the value just changed
     */
    _updateNameOnTitleChange: function(titleField)
    {
        if (this._mode == 'new')
        {
            this._updateNameTask = this._updateNameTask || new Ext.util.DelayedTask(function() {
                var form = this._form.getForm();
                var nameField = form.findField('name');
                
                var nameValue = this._titleToName(titleField.getValue());
                nameField.setValue(nameValue);
            }, this);
            
            this._updateNameTask.delay(500); // 500ms delay 
        }
    },
    
    /**
     * @private
     * Transforms a title into a valid name
     * @param {String} value The title to transform
     * @return {String} The computed name value
     */
    _titleToName: function(value)
    {
        // toLowerCase -> trim -> deemphasize -> all non valid characters become '-' 
        // -> multiple '-' replaced by one -> do not start with '-' -> do not end with '-'
        return Ext.String.deemphasize(value.toLowerCase().trim())
            .replace(/\W/g, '-')
            .replace(/-+/g, '-')
            .replace(/^-/, '')
            .replace(/-$/, '');
    },
    
    /**
     * @private
     * Open the site config tool of the project workspace
     */
    _openSiteConfig: function()
    {
        // Open site configuration tool to allow the user to configure the site
        // of the project workspace
        
        var site = this._project.getSite();
        Ametys.tool.ToolsManager.openTool('uitool-admin-site-config', {id: site.name, siteId: site.id, siteName: site.name, siteTitle: site.title});
    },

    /**
     * Triggered when the value of the combo is changed via the setValue method.
     * @param {Ext.form.field.ComboBox} combo The combo box.
     * @param {Object} newValue The new value.
     * @param {Object} oldValue The old value.
     * @param {Object} eOpts The event options.
     * @private
     */
    _onChangeInscriptionStatus: function(combo, newValue, oldValue, eOpts)
    {
        var defaultProfileField = this._form.getForm().findField('defaultProfile');
        var isOpen = newValue === "open";

        defaultProfileField.setDisabled(!isOpen);
        defaultProfileField.allowBlank = !isOpen;
        if (!isOpen)
        {
            defaultProfileField.setValue();
        }
    },
    
    /**
     * The cancel button handler
     * @private
     */
    _cancel: function()
    {
        this._box.close();
    },
    
    /**
     * Callback on the ok button. 
     * @private
     */
    _ok: function()
    {
        var form = this._form.getForm();
        if (!form.isValid())
        {
            return;
        }
        
        var values = form.getValues(),
            title = Ext.String.htmlEncode(values.title); // encode HTML chars, title do not accept html
        
        var params = [
            title, 
            values.description || null,
            values['mailing-list'] || null,
            values.inscriptionStatus,
            values.defaultProfile || null
        ];
        
        if (this._mode == 'edit')
        {
            // insert id as first parameter
            params.unshift(this._project.getId());
            
            Ametys.data.ServerComm.callMethod({
                role: 'org.ametys.plugins.workspaces.project.ProjectManager',
                methodName: 'editProject',
                parameters: params,
                callback: {
                    scope: this,
                    handler: this._editProjectCb
                },
                waitMessage: true,
                errorMessage: true
            });
        }
        else
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_CONFIRM}}",
                message: Ext.String.format("{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_CONFIRM_MESSAGE}}", title),
                width: 500,
                buttons: Ext.Msg.OKCANCEL,
                icon: Ext.Msg.INFO,
                fn: this._okConfirmCreateCb,
                scope: this,
                fnArgs: {
                    params: params
                }
            });
            
            // insert name
            params.unshift(values.name);
        }
    },
    
    /**
     * Callback called after the user confirmed the project creation.
     */
    _okConfirmCreateCb: function(btn, text, opt)
    {
        if (btn == 'ok')
        {
            var params = opt.fnArgs.params;
            
            Ametys.data.ServerComm.callMethod({
                role: 'org.ametys.plugins.workspaces.project.ProjectManager',
                methodName: 'createProject',
                parameters: params,
                callback: {
                    scope: this,
                    handler: this._createProjectCb
                },
                waitMessage: true,
                errorMessage: true
            });
        }
    },
    
    /**
     * Callback function called after the edition
     * @param {Object} response The response object.
     * @private
     */
    _editProjectCb: function(response)
    {
        // success callback
        this._successCb(this._project.getId());
    },
    
    /**
     * Callback function called after the creation
     * @param {Object} response The response object.
     * @private
     */
    _createProjectCb: function(response)
    {
        if (response.error == 'project-exists')
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_ERROR}}",
                message: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_ERROR_PROJECT_EXISTS}}",
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.ERROR
            });
        }
        else if (response.error == 'name-exists')
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_ERROR}}",
                message: "{{i18n PLUGINS_WORKSPACES_PROJECT_CREATE_ERROR_NAME_EXISTS}}",
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.ERROR
            });
        }
        else
        {
            // success callback
            this._successCb(response.id);
        }
    },
    
    /**
     * Success callback.
     * Closes the dialog box and calls user callback.
     * @param {String} id identifier of the project (which has been edited or created)
     * @private
     */
    _successCb: function(id)
    {
        this._box.close();
        
        if (Ext.isFunction(this._cbFn))
        {
            this._cbFn.call(this._cbScope, id);
        }
    }
});