/*
 *  Copyright 2017 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 for actions on hierarchical reference tables
  */
Ext.define('Ametys.plugins.cms.content.actions.HierarchicalReferenceTablesActions', {
    singleton: true,
    
    /**
     * Adds a new (non-leaf) reference table content.
     * @param {Ametys.plugins.cms.content.controller.HierarchicalReferenceTablesController} controller The controller calling this function
     */
    add: function(controller)
    {
    	var targets = controller.getMatchingTargets();
        
        if (targets.length > 0)
        {
            if (targets[0].getId() == Ametys.message.MessageTarget.REFERENCE_TABLE_CONTENT)
            {
                var parentContentId = targets[0].getParameters().id;
                controller.serverCall("getContentTypesForChild", [parentContentId], Ext.bind(this._openCreateContentDialog, this, [controller.getInitialConfig(), parentContentId], 1));
            }
            else
            {
                controller.serverCall("getContentTypeForRoot", [targets[0].getParameters().contentType], Ext.bind(this._openCreateContentDialog, this, [controller.getInitialConfig(), null], 1));
            }
        }
    },
    
    /**
     * @private
     * Configure and open dialog box of content creation
     * @param {String|String[]} cTypeIds The id of content types to create
     * @param {Object} btnConfig The configuration button
     * @param {String} [parentId] The id of parent
     */
    _openCreateContentDialog: function (cTypeIds, btnConfig, parentId)
    {
        var contentTypes = [];
        var cTypeIds = Ext.Array.from(cTypeIds);
        Ext.Array.each(cTypeIds, function (cTypeId) {
            contentTypes.push(Ametys.cms.content.ContentTypeDAO.getContentType(cTypeId));
        });
        
        var openParams = {
            contentTypes: contentTypes,
            contentLanguage: btnConfig.contentLanguage,
            initWorkflowActionId: btnConfig.initWorkflowActionId,
            workflowName: btnConfig.workflowName,
            defaultContentTitle: contentTypes[0].getDefaultTitle(),
            title: "{{i18n PLUGINS_CMS_UITOOL_HIERARCHICAL_REFERENCE_TABLES_NEW_CONTENT_DIALOG_TITLE}}",
            contentMessageTargetType: Ametys.message.MessageTarget.REFERENCE_TABLE_CONTENT
        }
        
        Ametys.cms.uihelper.CreateContent.open (openParams, Ext.bind(this._createCb, this, [parentId, cTypeIds, btnConfig], true), this);
    },
    
    /**
     * @private
     * Callback after creating the new content. Set the relation to parent
     * @param {String} contentId The newly created content
     * @param {String} parentContentId The identifier of the parent content
     * @param {String[]} cTypeIds The id of content types
     * @param {Object} btnConfig The configuration of the button
     */
    _createCb: function(contentId, parentContentId, cTypeIds, btnConfig)
    {
        if (parentContentId)
        {
            Ametys.data.ServerComm.callMethod({
                role: "org.ametys.cms.content.referencetable.HierarchicalReferenceTablesHelper",
                methodName: "getParentAttribute",
                parameters: [contentId],
                callback: {
                    handler: this._getParentAttributeCb,
                    scope: this,
                    arguments: {
                        contentId: contentId, 
                        parentContentId: parentContentId, 
                        btnConfig: btnConfig
                    }
                },
                waitMessage: false
            });
        }
        else
        {
            Ext.create("Ametys.message.Message", {
                type: Ametys.message.Message.MODIFIED,
                
                targets: {
                    id: Ametys.message.MessageTarget.REFERENCE_TABLE_CONTENT_ROOT,
                    parameters: { contentType: cTypeIds}
                },
                
                parameters: {
                    major: false
                }
            });
        }
    },
    
    /**
     * @private
     * Callback invoked after getting the parent attribute path. Set the relation to parent
     * @param {String} parentAttributePath The parent attribute path
     * @param {Object} args The callback arguments
     * @param {String} args.contentId The identifier of the newly created content
     * @param {String} args.parentContentId The identifier of the parent content
     * @param {Object} args.btnConfig The configuration of the button
     */
    _getParentAttributeCb: function(parentAttributePath, args)
    {
        var me = this,
            btnConfig = args.btnConfig,
            contentId = args.contentId,
            parentContentId = args.parentContentId,
            contentIdsToEdit = {};
            contentIdsToEdit[contentId] = null;
        
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.core.ui.RelationsManager",
            id: "org.ametys.cms.relations.setcontentattribute",
            methodName: "setContentAttribute",
            parameters: [
                [parentContentId],
                contentIdsToEdit,
                [],
                parentAttributePath,
                [btnConfig.editWorkflowActionId || "2"]
            ],
            callback: {
                handler: function(response, args) {
                    if (response == null)
                    {
                        Ametys.log.ErrorDialog.display({
                            title: "{{i18n PLUGINS_CMS_HIERARCHICAL_REFERENCE_TABLES_CREATEDNOTASSOCIATED_TITLE}}",
                            text: "{{i18n PLUGINS_CMS_HIERARCHICAL_REFERENCE_TABLES_CREATEDNOTASSOCIATED_TEXT}}",
                            category: this.self.getName()
                        });
                    }
                    else
                    {
                        var errors = response['errorMessages'];
                        if (errors && errors.length > 0)
                        {
                            var detailedMsg = "";
                            for (var i=0; i < errors.length; i++)
                            {
                                detailedMsg = response['errorMessages'][i] + "<br/>";
                            }
                        
                            this.getLogger().error({
                                message: "{{i18n PLUGINS_CMS_HIERARCHICAL_REFERENCE_TABLES_CREATEDNOTASSOCIATED_TEXT}}", 
                                details: detailedMsg,
                                defaultFocus: 0
                            });
                
                            Ametys.form.SaveHelper.SaveErrorDialog.showErrorDialog ("{{i18n PLUGINS_CMS_HIERARCHICAL_REFERENCE_TABLES_CREATEDNOTASSOCIATED_TITLE}}", "", detailedMsg);
                            return;
                        }

                        if (response['success'] == true)
                        {
                            Ext.create("Ametys.message.Message", {
                                type: Ametys.message.Message.MODIFIED,
                                
                                targets: {
                                    id: Ametys.message.MessageTarget.REFERENCE_TABLE_CONTENT,
                                    parameters: { ids: [parentContentId]}
                                },
                                
                                parameters: {
                                    major: false
                                }
                            });
                        }
                    }
                },
                arguments: null
            },
            waitMessage: true
        });
    },
    
    /**
     * Rename a (non-leaf) simple content.
     * @param {Ametys.plugins.cms.content.controller.HierarchicalReferenceTablesController} controller The controller calling this function
     */
    rename: function(controller)
    {
        var targets = controller.getMatchingTargets();
        if (targets.length > 0)
        {
            var contentId = targets[0].getParameters().id;
            controller.serverCall("getTitleForEdition", [contentId], Ext.bind(this._getTitleForEditionCb, this, [contentId, controller.getInitialConfig("editWorkflowActionId")], 1));
        }
    },
    
    /**
     * @private
     * Callback function invoked after retrieving current title value and type
     * @param {Object} titleInfo The title's properties
     * @param {String} titleInfo.type The title's type
     * @param {String|Object} titleInfo.value The title's value
     * @param {String} contentId The id of content being renamed
     * @param {String} actionId The workflow action id
     */
    _getTitleForEditionCb: function(titleInfo, contentId, actionId)
    {
        this._createRenameDialogBox(titleInfo, contentId, actionId);
        this._renameBox.show();
    },
    
    /**
     * Rename a (non-leaf) simple content.
     * @param {String} id The id of the content
     * @param {String} editWorkflowActionId The id of the edit workflow action
     * @param {String|Object} value Value of the new content title
     * @param {Function} [callback] Callback function to call after editing
     * @param {Object} [scope] The scope for callback
     */
    doRename: function(id, editWorkflowActionId, value, callback, scope)
    {
        Ametys.cms.content.ContentDAO.editContent({
            contentId: id,
            editWorkflowActionId: editWorkflowActionId,
            values: {
                "content.input.title": value
            }
        }, callback, scope, false, Ametys.message.MessageTarget.REFERENCE_TABLE_CONTENT);
    },
    
    /**
     * @private
     * Create the dialog box to rename a content in the tree
     * @param {Object} titleInfo The title's properties
     * @param {String} titleInfo.type The title's type
     * @param {String|Object} titleInfo.value The title's value
     * @param {String} contentId The id of content being renamed
     * @param {String} actionId The workflow action id
     */
    _createRenameDialogBox: function(titleInfo, contentId, actionId)
    {
        var formPanel = Ext.create('Ext.form.Panel', {
            border: false, 
            defaults: {
                cls: 'ametys',
                anchor: '95%'
            },
            fieldDefaults : {
                labelAlign: 'right',
                labelSeparator: '',
                labelWidth: 50
            },
            
            items : [{
                        xtype: titleInfo.type == 'multilingual-string' ? 'edition.multilingual-string' : 'textfield',
                        name: 'title',
                        allowBlank: false,
                        value: titleInfo.value,
                        fieldLabel: titleInfo.label
                     }
            ]
        });
        
        this._renameBox = Ext.create('Ametys.window.DialogBox', {
            title: "{{i18n PLUGINS_CMS_UITOOL_HIERARCHICAL_REFERENCE_TABLES_RENAME_CONTENT_LABEL}}",
            iconCls: 'ametysicon-list6 decorator-ametysicon-text1',
            
            layout :'fit',
            width : 350,
            
            items: formPanel,
            
            defaultFocus: formPanel.getForm().findField('title'),
            closeAction: 'destroy',
            
            referenceHolder: true,
            defaultButton: 'validate',
            
            buttons: [{
                reference: 'validate',
                text :"{{i18n PLUGINS_CMS_UITOOL_HIERARCHICAL_REFERENCE_TABLES_RENAME_OK_BUTTON}}", 
                handler : function() {
                    if (!formPanel.getForm().isValid())
                    {
                        return;
                    }
                    
                    var value = formPanel.getForm().findField("title").getValue();
                    this.doRename(contentId, actionId, value, Ext.bind(function() {this._renameBox.close();}, this));
                },
                scope: this
            },{
                text :"{{i18n PLUGINS_CMS_UITOOL_HIERARCHICAL_REFERENCE_TABLES_RENAME_CANCEL_BUTTON}}", 
                handler : Ext.bind(function() {this._renameBox.close();}, this)
            }]
        });
    },
    
    /**
	 * Delete the contents registered by the controller.
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	delete: function (controller)
	{
		var contentIds = controller.getContentIds();
		var tool = Ametys.tool.ToolsManager.getFocusedTool();
		if (contentIds.length > 0)
		{
			var contentTargets = controller.getMatchingTargets();
			var validContentTargets = [];
			var contentTitles = [];
			Ext.Array.forEach (contentTargets, function (contentTarget) {
				if (Ext.Array.contains (contentIds, contentTarget.getParameters().id))
				{
					validContentTargets.push(contentTarget);
					contentTitles.push (contentTarget.getParameters().title);
				}
			});
			
			Ametys.Msg.confirm("{{i18n CONTENT_DELETE_LABEL}}", 
					"{{i18n CONTENT_DELETE_CONFIRM}}" + contentTitles.join(', ') + ' ?', 
					Ext.bind(this._deleteConfirm, this, [controller, contentIds, tool], 1),
					this
			);
		}
	},
	
	/**
	 * Callback function invoked after the #act confirm box is closed
	 * @param {String} answer Id of the button that was clicked
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the #act function
	 * @param {String[]} contentIds The content identifiers
     * @param {Ametys.tool.Tool} tool The tool the deletion comes from
	 * @private
	 */
	_deleteConfirm: function (answer, controller, contentIds, tool)
	{
		if (answer == 'yes')
		{
			Ametys.data.ServerComm.callMethod({
	            role: "org.ametys.cms.content.referencetable.HierarchicalReferenceTablesDeleteContentDAO",
	            methodName: "trashContents",
	            parameters: [contentIds],
	            callback: {
	                handler: this._deleteConfirmCb,
	                scope: this,
	                arguments: {
						targets: controller.getMatchingTargets()
					}
	            },
	            waitMessage: {
                    msg: "{{i18n PLUGINS_CMS_UITOOL_HIERARCHICAL_REFERENCE_TABLES_DELETE_CONTENT_WAIT_MSG}}",
                    target: tool && tool.getContentPanel()
                }
	        });
		}
	},
	
	/**
	 * @private
	 * Callback function called after contents were removed
	 * @param {Object} response The server result
	 * @param {Object} args The callback arguments :
	 * @param {Ametys.message.MessageTarget[]} args.targets The content's targets
	 * @param {Ametys.message.MessageTarget[]} [args.callback] The callback function
	 */
	_deleteConfirmCb: function (response, args)
	{
		var targets = args.targets;
		var deletedContents = response['deleted-contents'];
		
		if (deletedContents.length > 0)
		{
			var deletedContentTargets = [];
			
			for (var i=0; i < deletedContents.length; i++)
			{
				for (var j=0; j < targets.length; j++)
				{
		        	if (targets[j].getParameters().id == deletedContents[i].id)
					{
						deletedContentTargets.push(targets[j]);
					}
				}
				
				// Remove content from navigation history
				Ametys.navhistory.HistoryDAO.removeEntry (deletedContents[i].id);
				
				// Notify content deletion
		        Ametys.notify({
		            type: 'info',
		            iconGlyph: 'ametysicon-text70',
		            title: "{{i18n PLUGINS_CMS_NOTIFICATION_DELETE_CONTENT_TITLE}}",
		            description: Ext.String.format("{{i18n PLUGINS_CMS_NOTIFICATION_DELETE_CONTENT_DESCRIPTION}}", Ext.String.escapeHtml(deletedContents[i].title))
		        });
			}
			
			// Fires deleted event
			Ext.create("Ametys.message.Message", {
				type: Ametys.message.Message.DELETED,
                parameters : {trashed: true},
				targets: deletedContentTargets
			});
		}
		
        var undeletedContents = response['undeleted-contents'];
        var referencedContents = response['referenced-contents'];
        var lockedContents = response['locked-contents'];
        var unauthorizedContents = response['unauthorized-contents'];
        if (undeletedContents.length > 0 || referencedContents.length > 0 || lockedContents.length > 0 || unauthorizedContents.length > 0)
        {
            var message = '';
            
            var message = this._buildErrorMessage(message, undeletedContents, "{{i18n CONTENT_DELETE_FAILED_CONTENTS}}");
            message = this._buildErrorMessage(message, referencedContents, "{{i18n CONTENT_DELETE_REFERENCED_CONTENTS}}", ".<br/>{{i18n CONTENT_DELETE_REFERENCED_CONTENTS_END}}");
            message = this._buildErrorMessage(message, lockedContents, "{{i18n CONTENT_DELETE_LOCKED_CONTENTS}}");
            message = this._buildErrorMessage(message, unauthorizedContents, "{{i18n CONTENT_DELETE_UNAUTHORIZED_CONTENTS}}");
            
            Ametys.Msg.show({
                   title: "{{i18n CONTENT_DELETE_LABEL}}",
                   msg: message,
                   buttons: Ext.Msg.OK,
                   icon: Ext.MessageBox.ERROR
            });
        }
        
        if (Ext.isFunction (args.callback))
        {
        	args.callback.call(args.scope, response);
        }
	},
	
	/**
     * @private
     * Build error message
     * @param {String} message The initial error message
     * @param {Object[]} contentsInError The contents in error
     * @param {String} startDesc The start description
     * @param {String} endDesc The end description
     */
    _buildErrorMessage: function(message, contentsInError, startDesc, endDesc)
    {
        message = message || '';
        if (contentsInError.length > 0)
        {
            if (message.length > 0)
            {
                message += '<br/><br/>';
            }
            
            message += startDesc || '';
            for (var i=0; i < contentsInError.length; i++)
            {
                message += (i > 0 ? ', ' : '') + contentsInError[i].title;
            }
            message += endDesc || '';
        }
        return message;
    }
	
});