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

/**
 * Singleton class defining the actions related to addition, edition of content types
 * @private
 */
Ext.define('Ametys.plugins.contenttypeseditor.editor.EditContentTypeActions', {
	singleton: true,
    
    /**
     * Open a dialog box to add a new content type
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    addContentType: function(controller)
    {
        var config = {
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_ADD_CONTENT_TYPE_DIALOG_TITLE}}",
            helpMessage: "{{i18n PLUGINS_CONTENTTYPESEDITOR_ADD_CONTENT_TYPE_DIALOG_HINT}}",
            callback: Ext.bind(this._openNewContentType, this)
        }
        Ametys.plugins.contenttypeseditor.editor.EditContentTypeHelper.add(config);
    },
    
    /**
     * @private
     * Callback function called after validate the dialog box for create a new content type.
     * Open a new content type in content type editor tool
     *  @param {Object} contentTypeInfos All information about the new content type :
     *  @param {String} [contentTypeInfos.pluginName] The plugin name
     *  @param {String} [contentTypeInfos.id] The content type id
     *  @param {String} contentTypeInfos.defaultTitle] The default title of content type
     *  @param {String} [contentTypeInfos.description] The description of content type
     *  @param {String} [contentTypeInfos.iconGlyph] The icon glyph of content type
     *  @param {String} [contentTypeInfos.iconDecorator] The icon decorator of content type
     *  @param {Boolean} [contentTypeInfos.private] True if the content type is private
     *  @param {Boolean} [contentTypeInfos.referencetable] True if the content type is a reference table
     *  @param {Boolean} [contentTypeInfos.mixin] True if the content type is a mixin
     *  @param {Boolean} [contentTypeInfos.abstract] True if the content type is abstract
     *  @param {Object} [contentTypeInfos.superTypes] Supertypes of content type :
     *  @param {String} [contentTypeInfos.superTypes.id] The id of super content type
     *  @param {String} [contentTypeInfos.superTypes.label] The label of super content type
      */
    _openNewContentType: function(contentTypeInfos)
    {
        var contentTypeId = "content-type." + contentTypeInfos.id;
        contentTypeInfos.id = contentTypeId;
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeId, true]
        }); 
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeId, contentTypeInfos: contentTypeInfos, mode: 'add'});
    },
    
    /**
     * Save content type
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    saveContentType: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (tool._mode === "add" || tool._mode === "edit")
        {
            controller.serverCall('saveContentType', [tool._contentTypeInfos], Ext.bind(this._saveContentTypeCb, this));
        }
        else
        {
            Ametys.notify({
                title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_SAVE_IMPOSSIBLE_ERROR_TITLE}}",
                description: "{{i18n PLUGINS_CONTENTTYPESEDITOR_SAVE_IMPOSSIBLE_ERROR_MESSAGE}}",
                type: "error"
            });
        }
    },
    
    /**
     * @private
     * Callback function called after save a content type
     * @param {Boolean} success False if the backup of new content type failed 
     */
    _saveContentTypeCb: function(success)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        if (!success)
        {
            Ametys.notify({
                title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_SAVE_ERROR_TITLE}}",
                description: "{{i18n PLUGINS_CONTENTTYPESEDITOR_SAVE_ERROR_MESSAGE}}",
                type: "error"
            });
        }
        else 
        {
            Ametys.data.ServerComm.callMethod({
                role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
                methodName: "markContentTypeAsSaved",
                parameters: [tool._contentTypeId],
                callback: {
                    handler: function() {
                        tool.setParams({id: tool._contentTypeId, mode: "save"});
                        Ametys.notify({
			                title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_SAVE_SUCCESS_TITLE}}",
			                description: "{{i18n PLUGINS_CONTENTTYPESEDITOR_SAVE_SUCCESS_MESSAGE}}"
			            });
                    }
                }
            }); 
        }
    },
    
    /**
     * Remove a content type
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    removeContentType: function(controller)
    {
        var contentTypeId = controller.getMatchingTargets()[0].getParameters().id;
        controller.serverCall('isUnusedContentType', [contentTypeId], Ext.bind(this._isUnusedContentType, this, [controller], 1));
    },
    
    /**
     * Remove a content type if it is unused
     * @param {String} isUnused True if a content type if unused
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */ 
    _isUnusedContentType: function(isUnused, controller)
    {
        if (isUnused)
        {
            var contentTypeId = controller.getMatchingTargets()[0].getParameters().id;
            controller.serverCall('getRemovedContentTypeInfo', [contentTypeId], Ext.bind(this._confirmRemoveContentType, this, [controller], 1));
        }
        else
        {
            Ext.Msg.show({
			    title:"{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_CONTENT_TYPE_LINKED_CONTENTS_TITLE}}",
			    message: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_CONTENT_TYPE_LINKED_CONTENTS_DESCRITPION}}",
			    buttons: Ext.Msg.OK,
			    icon: Ext.Msg.INFO
			});
        }
    },
    
    /**
     * @private
     * Open Remove content type UI
     * @param {Object} contentTypeInfo Content type information :
     * @param {String} contentTypeInfo.id The content type id
     * @param {String} contentTypeInfo.plugin The content type plugin
     * @param {String} contentTypeInfo.label The content type label
     * @param {String} contentTypeInfo.location The content type location
     * @param {String} contentTypeInfo.destination The content type destination
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    _confirmRemoveContentType: function(contentTypeInfo, controller)
    {
        var message = '{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_CONTENT_TYPE_MESSAGE_HINT}} <strong>"'+ contentTypeInfo.label + '"</strong> (' + contentTypeInfo.id + ') ? <br/><br/>' + 
        '{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_CONTENT_TYPE_MESSAGE_HINT_LOCATION}} ' + contentTypeInfo.location + "</br>" +
        '{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_CONTENT_TYPE_MESSAGE_DESTINATION}} ' + contentTypeInfo.destination;
       
        Ext.Msg.show({
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_CONTENT_TYPE_MESSAGE_TITLE}}",
            message: message,
            buttons: Ext.Msg.YESNO,
            icon: Ext.Msg.QUESTION,
            fn : function(btn) {
                if (btn === 'yes') {
                    this._confirmRestartServerAfterConfirmRemoveContentType(contentTypeInfo.id, controller);
                }
            },
            scope : this
        });  
    },
    
    /**
     * @private
     * Ask confirmation to restart 
     * @param {String} contentTypeId the id of the content type
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    _confirmRestartServerAfterConfirmRemoveContentType: function(contentTypeId, controller)
    {
        Ext.Msg.show({
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_CONTENT_TYPE_MESSAGE_RESTART_TITLE}}",
            message: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_CONTENT_TYPE_MESSAGE_RESTART_HINT}}",
            buttons: Ext.Msg.YESNO,
            icon: Ext.Msg.QUESTION,
            fn : function(btn) {
                if (btn === 'yes') {
                    this._removeContentType(true, contentTypeId, controller);
                }
                else
                {
                    this._removeContentType(false, contentTypeId, controller);
                }
            },
            scope : this
        });  
    },
    
    /**
     * @private
     * effectively remove
     * @param {Boolean} restart Restart required? 
     * @param {String} contentTypeId the id of the content type
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    _removeContentType: function(restart, contentTypeId, controller)
    {
        controller.serverCall('removeContentType', [contentTypeId], Ext.bind(this._removeContentTypeCb, this, [restart], 1));  
    },
    
    /**
     * @private
     * Callback after removing
     * @param {Boolean} success Was successfully remove?
     * @param {Boolean} restart Was a restart required?
     */
    _removeContentTypeCb: function(success, restart)
    {
        if (success)
        {
            Ametys.notify({
                title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_SUCCESS_TITLE}}",
                description: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_SUCCESS_DESCRIPTION}}"
            });
            if (restart)
            {
                // Restart the application
                this.restartServer();
            }
        }
        else
        {
            Ametys.notify({
                title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_ERROR_TITLE}}",
                description: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_ERROR_DESCRIPTION}}",
                type: "error"
            });
        }
    },
    
    /**
     * Restart the server
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    restart: function (controller)
    {
        Ametys.Msg.confirm("{{i18n PLUGINS_CONTENTTYPESEDITOR_RESTART_LABEL}}", 
                "{{i18n PLUGINS_CONTENTTYPESEDITOR_RESTART_CONFIRM}}", 
                Ext.bind(this._restartConfirm, this, [controller], 1),
                this
        );
    },
    
    /**
     * @private
     * Callback after asking for a restart 
     * @param {String} answer 'yes' to restart
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    _restartConfirm: function (answer, controller)
    {
        if (answer == 'yes')
        {   
            this.restartServer();
        }
    },
    
    /**
     * @private
     * Effectively restart the server
     */
    restartServer: function()
    {
        var url = Ametys.getPluginDirectPrefix('admin') + "/restart",
        result = null,
        ex = '';
    
        var id = Ametys.mask.GlobalLoadMask.mask("{{i18n PLUGINS_CONTENTTYPESEDITOR_RESTART_LOADING}}");
        
        function restart()
        {
            try
            {
                result =  Ext.Ajax.request({url: url, async: false});   
            }
            catch (e)
            {
                ex = e;
            }
            
             Ametys.mask.GlobalLoadMask.unmask(id); 
            
            if (result == null)
            {
                Ametys.log.ErrorDialog.display({
                    title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_RESTART_FAILED}}", 
                    text: "{{i18n PLUGINS_CONTENTTYPESEDITOR_RESTART_FAILED_TEXT}}",
                    details: ex,
                    category: "Ametys.plugins.contenttypeseditor.editor.EditContentTypeAction.restart"
                });
                return;
            }
            
            // Reload application
            document.location.reload(true);
        }
        window.setTimeout(restart, 1);
    },
    
    /**
     * Edit a content type
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    editContentType: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        
        var attributes = {
            attributes: tool._contentTypeInfos.attributes,
            views: tool._contentTypeInfos.views,
            indexingModel: tool._contentTypeInfos.indexingModel
        };
        
        var contentTypeInfosTool = tool._contentTypeInfos;
        var supertypes = []
        Ext.Array.each(tool._contentTypeInfos.superTypes, function(supertype){
            supertypes.push(supertype.id);
        });
        
        var language = Ametys.cms.language.LanguageDAO.getCurrentLanguage();
        
        var contentTypeInfo = {
            'id': contentTypeInfosTool.id,
            'plugin': contentTypeInfosTool.pluginName,
            'superTypes': supertypes,
            'glyph': contentTypeInfosTool.iconGlyph,
            'decorator': contentTypeInfosTool.iconDecorator,
            'private': contentTypeInfosTool['private'],
            'referenceTable': contentTypeInfosTool.referencetable,
            'mixin': contentTypeInfosTool.mixin,
            'abstract': contentTypeInfosTool['abstract'],
            'tags': contentTypeInfosTool.tags,
            'right': contentTypeInfosTool.right,
            'label': contentTypeInfosTool.label,
            'defaultTitle': contentTypeInfosTool.defaultTitle,
            'description': contentTypeInfosTool.description,
            'category': contentTypeInfosTool.category,
            'newCategory': contentTypeInfosTool.newCategory,
            'attributes': contentTypeInfosTool.attributes,
            'parentRef' : contentTypeInfosTool.parentRef,
            'hasImages' : contentTypeInfosTool.hasImages
        };
        var config = {
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_CONTENT_TYPE_DIALOG_TITLE}}",
            helpMessage: "",
            contentTypeInfo: contentTypeInfo,
            callback: Ext.bind(this._editContentTypeCb, this, [attributes], true)
        }
        Ametys.plugins.contenttypeseditor.editor.EditContentTypeHelper.edit(config);
    },

    /**
     * @private
     * Callback after editing
     * @param {Object} contentTypeInfos The server side object
     * @param {Object} metadata The metadata variable transmitted from #editContentType
     */
    _editContentTypeCb: function(contentTypeInfos, metadata)
    {
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeInfos.id, false]
        });
        contentTypeInfos.attributes = metadata.metadata;
        contentTypeInfos.views = metadata.metadataSets;
        contentTypeInfos.indexingModel = metadata.indexingModel;
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfos.id, contentTypeInfos: contentTypeInfos, mode: 'edit'});
    },
    
    /**
     * Add a metadata
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    addMetadata: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var config = {
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_METADATA_DIALOG_ADD_TITLE}}",
            iconCls: 'ametysicon-add64',
            mode: 'add',
            metadataNames: tool._contentTypeInfos.metadataNames,
            focusField: "metadata-name",
            callback: Ext.bind(this._addMetadataCb, this)
        }
        Ametys.plugins.contenttypeseditor.editor.EditMetadataHelper.open(config);
    },
    
    /**
     * @private
     * Callback after adding a metadata
     * @param {Object} metadataInfo The returned value for Ametys.plugins.contenttypeseditor.editor.EditMetadataHelper#open
     */
    _addMetadataCb: function(metadataInfo)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var contentTypeInfosTool = tool._contentTypeInfos;
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeInfosTool.id, false]
        });
        
        metadataInfo.contentTypeId = contentTypeInfosTool.id;
        metadataInfo.referenceContentTypeId = contentTypeInfosTool.id;
        var language = Ametys.cms.language.LanguageDAO.getCurrentLanguage();
        var referenceContentTypeLabel = "";
        if (contentTypeInfosTool.label.isMultilingual)
        {
            referenceContentTypeLabel = contentTypeInfosTool.label.values[language];
        }
        else
        {
            referenceContentTypeLabel = contentTypeInfosTool.label.values;
        }
        metadataInfo.referenceContentTypeLabel = referenceContentTypeLabel;
        metadataInfo.edition = true;
        
        var selectedNode = tool._treeComponent.getSelection()[0];
        if (selectedNode.data.depth == 1 && selectedNode.data.index == 0) // Metadata node
        {
            metadataInfo.path = metadataInfo.name;
            var index = 0;
            if (contentTypeInfosTool.attributes)
            {
                index = contentTypeInfosTool.attributes.length;
            }
            else 
            {
                contentTypeInfosTool.attributes = [];  
            }
            metadataInfo.index = index;
            contentTypeInfosTool.attributes[index] = metadataInfo;
        }
        else // Composite or repeater node
        {
            metadataInfo.path = selectedNode.data.path + "/" + metadataInfo.name;
            
            contentTypeInfosTool.attributes = this._updateMetadatas(contentTypeInfosTool.attributes, metadataInfo, selectedNode.data.path, true);
        }
        
        // Adding of the name of new metadata
        if (contentTypeInfosTool.metadataNames)
        {
            contentTypeInfosTool.metadataNames.push(metadataInfo.name);
        }
        else
        {
            contentTypeInfosTool.metadataNames = []; 
            contentTypeInfosTool.metadataNames.push(metadataInfo.name);
        }
        
        // Using of openTool even if the tool is opened because otherwise the tool is not load as well when the window is refresh
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfosTool.id, contentTypeInfos: contentTypeInfosTool, selectMetadata: metadataInfo.path, mode: 'edit'})
    },
    
    /**
     * Edit a metadata
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    editMetadata: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var selectedNodeInfo = tool._treeComponent.getSelection()[0].data;
        
        var linkedContentType = "";
        if (selectedNodeInfo.linkedContentType)
        {
            linkedContentType = selectedNodeInfo.linkedContentType.id;
        }
        var metadataInfo = {
            dataType: selectedNodeInfo.dataType,
            id: selectedNodeInfo.id,
            name: selectedNodeInfo.name,
            label: selectedNodeInfo.label,
            description: selectedNodeInfo.description,
            type: selectedNodeInfo.type,
            multiple: selectedNodeInfo.multiple,
            type: selectedNodeInfo.type,
            contentTypeId: selectedNodeInfo.contentTypeId,
            referenceContentTypeId: selectedNodeInfo.referenceContentTypeId,
            referenceContentTypeLabel: selectedNodeInfo.referenceContentTypeLabel,
            linkedContentType: linkedContentType,
            invertRelationPath: selectedNodeInfo.invertRelationPath
        };
        
        if (selectedNodeInfo.type === "repeater")
        {
            metadataInfo.initializeSize = selectedNodeInfo.initializeSize;
            metadataInfo.minSize = selectedNodeInfo.minSize;
            metadataInfo.maxSize = selectedNodeInfo.maxSize;
            metadataInfo.addLabel = selectedNodeInfo.addLabel;
            metadataInfo.deleteLabel = selectedNodeInfo.deleteLabel;
            metadataInfo.headerLabel = selectedNodeInfo.headerLabel;
        }
        else if (selectedNodeInfo.type !== "composite")
        {
            metadataInfo.widget = selectedNodeInfo.widget;
            metadataInfo.widgetParams = selectedNodeInfo.widgetParams;
            
            if (selectedNodeInfo.validator)
            {
                metadataInfo.validator = selectedNodeInfo.validator;
                metadataInfo.mandatory = selectedNodeInfo.mandatory;
                if (selectedNodeInfo.defaultValidator)
                {
                    metadataInfo.defaultValidator = selectedNodeInfo.defaultValidator;
                }
                if (selectedNodeInfo.customValidatorClass)
                {
                    metadataInfo.customValidatorClass = selectedNodeInfo.customValidatorClass;
                    metadataInfo.customValidatorConfiguration = selectedNodeInfo.customValidatorConfiguration;
                }
            }
            if (selectedNodeInfo.enumerated)
            {
                metadataInfo.enumerated = selectedNodeInfo.enumerated;
                if (selectedNodeInfo.defaultEnumerator)
                {
                    metadataInfo.defaultEnumerator = selectedNodeInfo.defaultEnumerator;
                }
                else if (selectedNodeInfo.customEnumeratorClass)
                {
                    metadataInfo.customEnumeratorClass = selectedNodeInfo.customEnumeratorClass;
                    metadataInfo.customEnumeratorConfiguration = selectedNodeInfo.customEnumeratorConfiguration;
                }
            }
        }
        
        var config = {
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_METADATA_DIALOG_EDIT_TITLE}}",
            iconCls: 'ametysicon-edit45',
            metadataInfo: metadataInfo,
            mode: 'edit',
            focusField: "metadata-label",
            callback: Ext.bind(this._editMetadataCb, this)
        }
        Ametys.plugins.contenttypeseditor.editor.EditMetadataHelper.open(config);
    },
    
    /**
     * @private
     * Callback after editing a metadata
     * @param {Object} metadataInfo The returned value of Ametys.plugins.contenttypeseditor.editor.EditMetadataHelper#open
     */
    _editMetadataCb: function(metadataInfo)
    {
        if (metadataInfo.mandatory)
        {
            var tool = Ametys.tool.ToolsManager.getFocusedTool();
            var contentTypeId = tool._contentTypeInfos.id;
            
            Ametys.data.ServerComm.callMethod({
                role: "org.ametys.plugins.contenttypeseditor.edition.EditContentTypeInformationHelper",
                methodName: "getInvalidContent",
                parameters: [contentTypeId, metadataInfo.name],
                callback: {
                    handler: this._warningInvalidContents,
                    arguments: {
                        metadataInfo: metadataInfo
                    },
                    scope: this
                }
            });
        }
        else
        {
            this._editMetadata(metadataInfo)
        }
   },
   
   /**
    * @private
    * Callback to handle possible contents that are now invlids
    * @param {String[]} invalidContents Name of the contents that are invalid
    * @param {Object} metadataInfo The returned value of Ametys.plugins.contenttypeseditor.editor.EditMetadataHelper#open
    */
   _warningInvalidContents: function(invalidContents, metadataInfo)
   {
        if (invalidContents && invalidContents.length > 0)
        {
            var message = '{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_METADATA_INVALID_CONTENT_MESSAGE}}</br></br>';
            Ext.Array.each(invalidContents, function(name, index) {
                message = message + "- " + name + "</br>";
            });
            Ext.Msg.show({
                title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_METADATA_INVALID_CONTENT_TITLE}}",
                message: message,
                buttons: Ext.Msg.OKCANCEL,
                icon: Ext.Msg.WARNING,
                width: 500,
                height: 250,
                fn : function(btn) {
                    if (btn === 'ok') {
                        this._editMetadata(metadataInfo.metadataInfo)
                    }
                },
                scope : this
            });  
        }
        else
        {
            this._editMetadata(metadataInfo.metadataInfo);
        }
   },
    
   /**
    * @private
    * After a metadata was edited
    * @param {Object} metadataInfo The returned value of Ametys.plugins.contenttypeseditor.editor.EditMetadataHelper#open
    */
    _editMetadata: function(metadataInfo)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var contentTypeInfosTool = tool._contentTypeInfos;
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeInfosTool.id, false]
        });
        
        metadataInfo.contentTypeId = contentTypeInfosTool.id;
        metadataInfo.referenceContentTypeId = contentTypeInfosTool.id;
        var referenceContentTypeLabel = "";
        var language = Ametys.cms.language.LanguageDAO.getCurrentLanguage();
        if (contentTypeInfosTool.label.isMultilingual)
        {
            referenceContentTypeLabel = contentTypeInfosTool.label.values[language];
        }
        else
        {
            referenceContentTypeLabel = contentTypeInfosTool.label.values;
        }
        metadataInfo.referenceContentTypeLabel = referenceContentTypeLabel;
        metadataInfo.edition = true;
        metadataInfo.path = tool._treeComponent.getSelection()[0].data.path;
        
        contentTypeInfosTool.attributes = this._updateMetadatas(contentTypeInfosTool.attributes, metadataInfo, metadataInfo.path, false);

        // Using of openTool even if the tool is opened because otherwise the tool is not load as well when the window is refresh
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfosTool.id, contentTypeInfos: contentTypeInfosTool, selectMetadata: metadataInfo.path, mode: 'edit'})
    },
    
    /**
     * @private
     * Update the metadatas with a metadata
     * @param {Object} metadatas The metadatas to update
     * @param {Object} metadata The metadata to update in metadatas
     * @param {String} metadataPath The metadata path
     * @param {Boolean} add Was the metadata added?
     * @return {Object} The modified metadatas
     */
    _updateMetadatas: function(metadatas, metadata, metadataPath, add)
    {
	    var updatedMetadatas = []; 
	    var path = metadataPath.split("/");
	    for (var i = 0; i < metadatas.length; i++)
        {
            if (metadatas[i].path == path[0])
            {
                updatedMetadatas[i] = this._updateMetadata(metadatas[i], metadata, metadataPath, add);
            }
            else
            {
                updatedMetadatas[i] = metadatas[i];
            }
        }
	    return updatedMetadatas;
    },
    
    /**
     * @private
     * Update a single value of #_updateMetadatas
     * @param {Object} currentMetadata The currently edited metadata
     * @param {Object} metadata The metadata to update
     * @param {String} metadataPath The fullpath
     * @param {Boolean} add Was the metadata added?
     * @return {Object} The modified metadata
     */
    _updateMetadata: function(currentMetadata, metadata, metadataPath, add)
    {
        if (currentMetadata.path == metadataPath)
        {
            if (add)
            {
                if (currentMetadata.children)
                {
                    var index = currentMetadata.children.length;
                    currentMetadata.children[index] = metadata;
                }
                else
                {
                    currentMetadata.children = [];
                    currentMetadata.children[0] = metadata;
                }
            }
            else
            {
                if (currentMetadata.children)
	            {
	               metadata.children = currentMetadata.children; 
	            }
	            currentMetadata = metadata;                
            }
        }
        else
        {
            if (currentMetadata.children)
            {
                for (var i = 0; i < currentMetadata.children.length; i++)
                {
                   currentMetadata.children[i] = this._updateMetadata(currentMetadata.children[i], metadata, metadataPath, add); 
                }
            }
        }
        return currentMetadata;
    },
   
    
    /**
     * Remove a metadata
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    removeMetadata: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var selectedNodeInfo = tool._treeComponent.getSelection()[0].data;
        
        var message = "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_METADATA_DIALOG_MESSAGE}} '" + selectedNodeInfo.text + "' ?";
        if (selectedNodeInfo.type == 'content') 
        {
            message = "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_METADATA_CONTENT_DIALOG_MESSAGE}} '" + selectedNodeInfo.text + "' ?";
        }
        Ext.Msg.show({
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_REMOVE_METADATA_DIALOG_TITLE}}",
            message: message,
            buttons: Ext.Msg.OKCANCEL,
            icon: Ext.Msg.QUESTION,
            fn : function(btn) {
                if (btn === 'ok') {
                    var tool = Ametys.tool.ToolsManager.getFocusedTool();
                    var selectedNodeInfo = tool._treeComponent.getSelection()[0].data;
                    
                    var contentTypeInfosTool = tool._contentTypeInfos;
                    Ametys.data.ServerComm.callMethod({
                        role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
                        methodName: "markContentTypeAsEdited",
                        parameters: [contentTypeInfosTool.id, false]
                    });
                    
                    contentTypeInfosTool.metadataNames = this._updatedMetadataNames(contentTypeInfosTool.attributes, selectedNodeInfo.path, contentTypeInfosTool.metadataNames);
                    contentTypeInfosTool.attributes = this._removeMetadata(contentTypeInfosTool.attributes, selectedNodeInfo.path);
                    
                    // Using of openTool even if the tool is opened because otherwise the tool is not load as well when the window is refresh
                    Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfosTool.id, contentTypeInfos: contentTypeInfosTool, mode: 'edit'})
                }
            },
            scope : this
        });
    },
    
    /**
     * @private
     * Remove the metadata from the metadatas
     * @param {Object} metadatas The metedatas to edit
     * @param {String} metadataPath The path of the metadata to remove
     * @return {Object} The modified metadatas
     */
    _removeMetadata: function(metadatas, metadataPath)
    {
        var updatedMetadatas = []
        for (var i = 0; i < metadatas.length; i++)
        {
            var currentMetadata = metadatas[i];
            if (currentMetadata.path !== metadataPath)
            {
                if (currentMetadata.children)
                {
                    currentMetadata.children = this._removeMetadata(currentMetadata.children, metadataPath);
                }
                else
                {
                    currentMetadata.children = [];
                }
                updatedMetadatas.push(currentMetadata);
            }
        }
        return updatedMetadatas;
    },
    
    /**
     * @private
     * Update the metadata names by removing some
     * @param {Object} metadatas The metadata to edit
     * @param {String} metadataPath The metadata path to remove
     * @param {String[]} metadataNames The metadata names to edit
     * @return {Object} The modified metadatas names
     */
    _updatedMetadataNames: function(metadatas, metadataPath, metadataNames)
    {
        var updatedMetadataNames = [];
        var metadataNamesToRemove = this._getChildrenMetadataNames(metadatas, metadataPath);
        for (var i = 0 ; i < metadataNames.length; i++)
        {
            if (!Ext.Array.contains(metadataNamesToRemove,metadataNames[i]))
            {
                updatedMetadataNames.push(metadataNames[i]);
            }
        }
        return updatedMetadataNames;
    },
    
    /**
     * @private
     * Get the metadata names of the given path
     * @param {Object} metadatas The metadatas
     * @param {String} metadataPath The path
     * @return {String[]} The names of metadata at this path
     */
    _getChildrenMetadataNames: function(metadatas, metadataPath)
    {
        var childrenMetadataNames = []
        for (var i = 0; i < metadatas.length; i++)
        {
            var currentMetadata = metadatas[i];
            if (currentMetadata.path == metadataPath)
            {
                childrenMetadataNames.push(currentMetadata.name);
                if (currentMetadata.children)
                {
                    childrenMetadataNames = Ext.Array.push(childrenMetadataNames, this._getMetadataNames(currentMetadata.children));
                }
                
            }
        }
        return childrenMetadataNames;
    },
    
    /**
     * @private
     * Get a flat array of every metadata name
     * @param {Object} metadatas The metadatas
     * @return {String[]} The metadata name
     */
    _getMetadataNames: function(metadatas)
    {
        var names = []
        for (var i = 0; i < metadatas.length; i++)
        {
            names.push(metadatas[i].name);
            if (metadatas[i].children)
            {
                Ext.Array.push(names, this._getMetadataNames(metadatas[i].children));
            }
        }
        return names;
    },
    
    /**
     * Add a metadata
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    addMetadataSet: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var config = {
            contentTypeId: tool._contentTypeInfos.id,
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_METADATASET_DIALOG_ADD_TITLE}}",
            iconCls: 'ametysicon-add64',
            mode: 'add',
            callback: Ext.bind(this._addMetadataSetCb, this)
        }
        Ametys.plugins.contenttypeseditor.editor.EditMetadataSetHelper.open(config);
    },
    
    /**
     * @private
     * Callback when the metadata set is added
     * @param {Object} metadataSetInfo The info returned by Ametys.plugins.contenttypeseditor.editor.EditMetadataSetHelper#open
     */
    _addMetadataSetCb: function(metadataSetInfo)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var contentTypeInfosTool = tool._contentTypeInfos;
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeInfosTool.id, false]
        });
        var contentTypeId = contentTypeInfosTool.id;
        
        var selectedNode = tool._treeComponent.getSelection()[0];
        
        var index = 0;
        if (contentTypeInfosTool.views)
        {
            index = contentTypeInfosTool.views.length;
        }
        else 
        {
            contentTypeInfosTool.views = [];  
        }
        metadataSetInfo.index = index;
        contentTypeInfosTool.views[index] = metadataSetInfo;
        var indexTabView = [];
        indexTabView.push(index);
        
        // Using of openTool even if the tool is opened because otherwise the tool is not load as well when the window is refresh
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfosTool.id, contentTypeInfos: contentTypeInfosTool, selectMetadataSet: indexTabView, mode: 'edit'})
    },
    
    /**
     * Edit a metadata
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    editMetadataSet: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var selectedNodeInfo = tool._treeComponent.getSelection()[0].data;
        
        var metadataSetInfo = {};
        metadataSetInfo.name = selectedNodeInfo.name;
        metadataSetInfo.label = selectedNodeInfo.label;
        metadataSetInfo.description = selectedNodeInfo.description;
        metadataSetInfo.isEdition = selectedNodeInfo.isEdition;
        metadataSetInfo.iconGlyph = selectedNodeInfo.iconGlyph;

        var config = {
            contentTypeId: tool._contentTypeInfos.id,
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_METADATASET_DIALOG_EDIT_TITLE}}",
            iconCls: 'ametysicon-edit45',
            mode: 'edit',
            metadataSetInfo: metadataSetInfo,
            callback: Ext.bind(this._editMetadataSetCb, this)
        };
        
        Ametys.plugins.contenttypeseditor.editor.EditMetadataSetHelper.open(config);
    },
    
    /**
     * @private
     * The callback after editing a metadata set
     * @param {Object} metadataSetInfo The info returned by Ametys.plugins.contenttypeseditor.editor.EditMetadataSetHelper#open 
     */
    _editMetadataSetCb: function(metadataSetInfo)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var contentTypeInfosTool = tool._contentTypeInfos;
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeInfosTool.id, false]
        });
        var contentTypeId = contentTypeInfosTool.id;
        
        var selectedNode = tool._treeComponent.getSelection()[0];
        var indexTabView = this._indexTabView(selectedNode, tool._treeComponent.getStore());
        var metadataSets = this._updateMetadataRefs(contentTypeInfosTool.views, metadataSetInfo, indexTabView, 0, false)
        contentTypeInfosTool.views = metadataSets;
        
        // Using of openTool even if the tool is opened because otherwise the tool is not load as well when the window is refresh
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfosTool.id, contentTypeInfos: contentTypeInfosTool, selectMetadataSet: indexTabView, mode: 'edit'})
    },
    
    /**
     * @private
     * Get the currently selected metadata set
     * @param {Ext.data.NodeInterface} selectedNode The currently node in the tree
     * @param {Ext.data.TreeStore} store The tree store
     * @return {Number[]} The data index of the currently node
     */
     _indexTabView: function(selectedNode, store)
    {
        var node = selectedNode;
        var isViewNode = false;
        
        var indexTab = [];
        indexTab.push(selectedNode.data.index);
        while (!isViewNode)
        {
            var currentNode = store.getById(node.data.parentId);
            if (currentNode.data.depth == 1 && currentNode.data.index == 1)
            {
                isViewNode = true;
            }
            else
            {
                indexTab.push(currentNode.data.index);
            }
            node = currentNode;
        }
        return indexTab.reverse();
    },
    
    /**
     * Remove a metadata
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    removeMetadataSet: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var contentTypeInfosTool = tool._contentTypeInfos;
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeInfosTool.id, false]
        });
        
        var selectedNode = tool._treeComponent.getSelection()[0];
        var indexTabView = this._indexTabView(selectedNode, tool._treeComponent.getStore());
        var metadataSets = this._removeMetadataSet(contentTypeInfosTool.views, indexTabView, 0)
        contentTypeInfosTool.views = metadataSets;
        
        indexTabView.length = indexTabView.length - 1;
        
        // Using of openTool even if the tool is opened because otherwise the tool is not load as well when the window is refresh
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfosTool.id, contentTypeInfos: contentTypeInfosTool, selectMetadataSet: indexTabView, mode: 'edit'})
    },
    
    /**
     * @private
     * Remove the current metadata set
     * @param {Object} metadataSets The metadata sets
     * @param {Number[]} indexTabView The metadata set index
     * @param {Number} index The index in indexTabView for recurcivity
     * @return {Object} The modified metadata sets
     */
    _removeMetadataSet: function(metadataSets, indexTabView, index)
    {
        var updatedMetadataSets = []; 
        for (var i = 0; i < metadataSets.length; i++)
        {
            if (i == indexTabView[index])
            {
                if (index < indexTabView.length-1)
                {
                    var emptyIndex = updatedMetadataSets.length;
                    updatedMetadataSets[emptyIndex] = metadataSets[i];
                    if (metadataSets[i].children && metadataSets[i].children.length > 0)
                    {
                        var children = metadataSets[i].children;
                        updatedMetadataSets[emptyIndex].children = [];
                        updatedMetadataSets[emptyIndex].children = this._removeMetadataSet(children, indexTabView, index + 1); 
                    }
                }
            }
            else
            {
                updatedMetadataSets[updatedMetadataSets.length] = metadataSets[i]
            }
        }
        return updatedMetadataSets;
    },
    
    /**
     * Add a metadata ref
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    addMetadataRef: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var config = {
            contentTypeId: tool._contentTypeInfos.id,
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_METADATAREF_DIALOG_ADD_TITLE}}",
            iconCls: 'ametysicon-add64',
            mode: 'add',
            metadataNames: tool._contentTypeInfos.metadataNames,
            callback: Ext.bind(this.addMetadataRefCb, this)
        }
        Ametys.plugins.contenttypeseditor.editor.EditMetadataRefHelper.open(config);
    },
    
    /**
     * @private
     * Callback after adding a metadata reference
     * @param {Object} metadataRefInfo The returned value of Ametys.plugins.contenttypeseditor.editor.EditMetadataRefHelper#open
     */
    addMetadataRefCb: function(metadataRefInfo)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var contentTypeInfosTool = tool._contentTypeInfos;
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeInfosTool.id, false]
        });
        var contentTypeId = contentTypeInfosTool.id;
        
        var selectedNode = tool._treeComponent.getSelection()[0];
        var indexTabView = this._indexTabView(selectedNode, tool._treeComponent.getStore());
        var metadataSets = this._updateMetadataRefs(contentTypeInfosTool.views, metadataRefInfo, indexTabView, 0, true)
        
        contentTypeInfosTool.views = metadataSets;
        
        // Using of openTool even if the tool is opened because otherwise the tool is not load as well when the window is refresh
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfosTool.id, contentTypeInfos: contentTypeInfosTool, selectMetadataSet: indexTabView, mode: 'edit'})
    },
    
    /**
     * Edit a metadata ref
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    editMetadataRef: function(controller)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var selectedNodeInfo = tool._treeComponent.getSelection()[0].data;
        
        var config = {
            contentTypeId: tool._contentTypeInfos.id,
            title: "{{i18n PLUGINS_CONTENTTYPESEDITOR_EDIT_METADATAREF_DIALOG_EDIT_TITLE}}",
            iconCls: 'ametysicon-edit45',
            mode: 'edit',
            metadataNames: tool._contentTypeInfos.metadataNames,
            callback: Ext.bind(this.editMetadataRefCb, this)
        };
        
        var metadataRefInfo = {};
        metadataRefInfo.dataType = selectedNodeInfo.dataType;
        
        if (selectedNodeInfo.dataType === "model_item_ref")
        {
            config.isMetadataSet = false;
            metadataRefInfo.name = selectedNodeInfo.name;
        }
        else if (selectedNodeInfo.dataType === "fieldset")
        {
            config.isMetadataSet = false;
            metadataRefInfo.role = selectedNodeInfo.role;
            metadataRefInfo.label = selectedNodeInfo.label;
        }
        
        config.metadataRefInfo = metadataRefInfo;

        Ametys.plugins.contenttypeseditor.editor.EditMetadataRefHelper.open(config);
    },
    
    /**
     * @private
     * The callback after edition
     * @param {Object} metadataRefInfo The modified informations
     */
    editMetadataRefCb: function(metadataRefInfo)
    {
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        var contentTypeInfosTool = tool._contentTypeInfos;
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.plugins.contenttypeseditor.edition.ContentTypeStateComponent",
            methodName: "markContentTypeAsEdited",
            parameters: [contentTypeInfosTool.id, false]
        });
        var contentTypeId = contentTypeInfosTool.id;
        
        var selectedNode = tool._treeComponent.getSelection()[0];
        var indexTabView = this._indexTabView(selectedNode, tool._treeComponent.getStore());
        var metadataSets = this._updateMetadataRefs(contentTypeInfosTool.views, metadataRefInfo, indexTabView, 0, false)
        contentTypeInfosTool.views = metadataSets;
        
        // Using of openTool even if the tool is opened because otherwise the tool is not load as well when the window is refresh
        Ametys.tool.ToolsManager.openTool('uitool-contenttypeseditor', {id: contentTypeInfosTool.id, contentTypeInfos: contentTypeInfosTool, selectMetadataSet: indexTabView, mode: 'edit'})
    
    },
    
    /**
     * Update 
     * @param {Object} metadataSets todo
     * @param {Object} metadataRefInfo todo
     * @param {Number[]} indexTabView todo
     * @param {Number} index todo
     * @param {Boolean} add todo
     * @return {Object[]} The updated metadataref
     */
    _updateMetadataRefs: function(metadataSets, metadataRefInfo, indexTabView, index, add)
    {
        var updatedMetadataSets = []; 
        for (var i = 0; i < metadataSets.length; i++)
        {
            if (i == indexTabView[index])
            {
                // View in edition
                if (index < indexTabView.length-1)
                {
                    updatedMetadataSets[i] = metadataSets[i];
                    if (metadataSets[i].children && metadataSets[i].children.length > 0)
                    {
                        updatedMetadataSets[i].children = this._updateMetadataRefs(metadataSets[i].children, metadataRefInfo, indexTabView, index + 1, add); 
                    }
                }
                else
                {
                    if (add)
                    {
                        updatedMetadataSets[i] = metadataSets[i];
                        var childrenIndex = 0;
                        if (metadataSets[i].children && metadataSets[i].children.length > 0)
                        {
                            childrenIndex = metadataSets[i].children.length;
                        }
                        else
                        {
                            updatedMetadataSets[i].children = [];
                        }
                        updatedMetadataSets[i].leaf = false;
                        updatedMetadataSets[i].children[childrenIndex] = metadataRefInfo;
                        updatedMetadataSets[i].children[childrenIndex].index = childrenIndex;
                    }
                    else
                    {
                        if (metadataSets[i].children && metadataSets[i].children.length > 0)
                        {
                            metadataRefInfo.leaf = false;
                            updatedMetadataSets[i] = metadataRefInfo;  
                            updatedMetadataSets[i].index = i;
                            updatedMetadataSets[i].children = metadataSets[i].children;
                        }
                        else
                        {
                            updatedMetadataSets[i] = metadataRefInfo;  
                            updatedMetadataSets[i].index = i;  
                        }
                    }
                }
            }
            else
            {
                updatedMetadataSets[i] = metadataSets[i]
            }
        }
        return updatedMetadataSets;
    },
    
     /**
     * Cancel modification on content type. Close the selected content type editor tool
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     */
    cancelModifications: function(controller)
    {
        Ametys.tool.ToolsManager.getFocusedTool().close();
    }
});