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

/**
 * Singleton class to save content modifications
 * @private
 */
Ext.define('Ametys.plugins.cms.content.actions.SaveAction', {
	singleton: true,
	
	/**
	 * Action function to be called by the controller.
	 * Quit the edition without saving
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	unsave: function (controller)
	{
        var target = controller.getMatchingTargets()[0];
        var contentId = target.getParameters().id;
        var tool = Ametys.tool.ToolsManager.getFocusedTool();
        
        if (tool.isDirty())
        {
    		Ametys.Msg.confirm("{{i18n CONTENT_EDITION_UNSAVE_LABEL}}", 
    				"{{i18n CONTENT_EDITION_UNSAVE_CONFIRM}}", 
    				Ext.bind(this._unsaveConfirm, this, [controller], 1),
    				this
    		);
        }
        else
        {
            this._unsaveConfirm('yes', controller);
        }
	},
	
	/**
	 * Callback function invoked after the 'unsave' 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 #unsave function
	 * @private
	 */
	_unsaveConfirm: function (answer, controller)
	{
		if (answer == 'yes')
		{
			var target = controller.getMatchingTargets()[0];
			var contentId = target.getParameters().id;
            var tool = Ametys.tool.ToolsManager.getFocusedTool();
			
			// Delete the automatic save.
			Ametys.data.ServerComm.callMethod({
				role: "org.ametys.cms.content.autosave.ContentBackupClientInteraction",
				methodName: "deleteContentBackup",
				parameters: [contentId],
				callback: {
	 				scope: this,
					handler: this._deleteAutoBackupCb
				},
				errorMessage: false
			});
            
            tool.quitEditionMode();
            tool.fireMessagesOnSuccessEdition();

            // Unlock content
            Ametys.cms.content.ContentDAO.unlockContent(contentId, target.getId());
		}
	},
   
	
	/**
	 * Action function to be called by the controller.
	 * Will save the content modifications
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	save: function (controller)
	{
		this._startSave(controller, false, false);
	},
	
	/**
	 * Action function to be called by the controller.
	 * Will save the content modifications and quit edition form
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	saveAndQuit: function (controller)
	{
		this._startSave(controller, true, false);
	},
	
	/**
	 * Action function to save the content modifications
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 * @param {Boolean} quit true to quit edition form after saving modifications
     * @param {Boolean} ignoreWarnings True to ignore warnings from server response
	 * @private
	 */
	_startSave: function (controller, quit, ignoreWarnings)
	{
		var form = Ametys.form.SaveHelper.getForm(controller.getMatchingTargets());
		if (form != null)
		{
			var target = controller.getMatchingTargets()[0];
			var contentId = target.getParameters().id;
			
			var tool = Ametys.tool.ToolsManager.getFocusedTool();
			
			// Validate form
			var invalidFields = Ext.Array.merge(form.getInvalidFields(), form.getInvalidRepeaters());
			if (invalidFields.length > 0)
			{
				Ametys.Msg.show({
					   title: "{{i18n PLUGINS_CMS_SAVE_ACTION_SAVE}}", //{{i18n CONTENT_EDITION_SAVE_LABEL}}",
					   msg: "{{i18n PLUGINS_CMS_SAVE_ACTION_INVALIDFIELDS}}" + Ametys.form.SaveHelper.getInvalidFieldsAsReadableList(invalidFields), //"{{i18n CONTENT_EDITION_SAVE_INVALID_FIELD}}",
					   buttons: Ext.Msg.OK,
					   icon: Ext.MessageBox.ERROR
				});
				return;
			}
			
			var warnedFields = form.getWarnedFields();
			if (!Ext.Object.isEmpty(warnedFields))
			{
			    Ametys.Msg.show({
			        title: "{{i18n PLUGINS_CMS_SAVE_ACTION_SAVE}}",
			        msg: "{{i18n PLUGINS_CMS_SAVE_ACTION_WARNED_FIELDS_START}}" + Ametys.form.SaveHelper.getWarnedFieldsAsReadableList(warnedFields) + "{{i18n PLUGINS_CMS_SAVE_ACTION_WARNED_FIELDS_END}}",
			        buttons: Ext.Msg.YESNO,
			        icon: Ext.Msg.QUESTION,
			        modal: true,
			        fn: Ext.bind (this._bypassWarnedFields, this, [tool, form, contentId, quit, ignoreWarnings], 1),
			        scope: this
			    });
			    return;
			}
            
			this._continueSave (tool, form, contentId, quit, ignoreWarnings);
		}
	},
    
    /**
     * @private
     * Next step to save the content
     * @param {Ametys.tool.Tool} tool The content tool
     * @param {Ametys.form.ConfigurableFormPanel} form The form panel
     * @param {String} contentId The content id
     * @param {Boolean} quit True to quit edition after saving
     * @param {Boolean} ignoreWarnings True to ignore warnings during content modification
     */
    _continueSave: function(tool, form, contentId, quit, ignoreWarnings)
    {
        let me = this;
        
        // Determine if base version is still ok
        tool._getData(next);
        
        function _toReadableVersion(v)
        {
            let i = v.indexOf(".");
            return parseInt(v.substring(i + 1)) + 1;
        }

        
        function next(response)
        {
            let currentData = tool._extractDataFromResponse(response);
            tool.form.getField(tool.form.fieldNamePrefix + "_version").setValue(currentData.version);

            if (tool._baseData.version == currentData.version
                || !currentData 
                || currentData.data == tool._baseData.data)
            {
                me._doSave (tool, form, contentId, quit, ignoreWarnings);
            }
            else
            {
                // Show warning 
                Ametys.form.SaveHelper.SaveErrorDialog.showWarningDialog(
                    "{{i18n CONTENT_EDITION_VALIDATION_ERRORS_VERSION_COLLISION_TITLE}}",
                    "",
                    new Ext.Template("<p style='padding: 0 10px'>{{i18n plugin.cms:CONTENT_EDITION_VALIDATION_ERRORS_VERSION_COLLISION}}</p>").apply([
                        "Ext.getCmp(Ext.fly(this).findParent('.ametys-dialogbox').id).close(); Ametys.tool.ToolsManager.openTool('uitool-diff-content', { id: '" + contentId + "', contentId: '" + contentId + "', baseVersion: '" + tool._baseData.version + "', version: '" + currentData.version + "'" + (tool._viewName ? ", 'view-name': '" + tool._viewName + "'" : "") + ", 'allData': false });",
                        _toReadableVersion(tool._baseData.version),
                        _toReadableVersion(currentData.version)
                    ]), 
                    "{{i18n PLUGINS_CMS_SAVE_ACTION_WARNING_DESC_QUESTION}}", 
                    function(yes) {
                        if (yes)
                        {
                            me._doSave (tool, form, contentId, quit, ignoreWarnings);
                        }
                    }
                );
            }
        }
    },
    
	/**
	 * @private
	 * Save the content
	 * @param {Ametys.tool.Tool} tool The content tool
	 * @param {Ametys.form.ConfigurableFormPanel} form The form panel
	 * @param {String} contentId The content id
	 * @param {Boolean} quit True to quit edition after saving
     * @param {Boolean} ignoreWarnings True to ignore warnings during content modification
	 */
	_doSave: function (tool, form, contentId, quit, ignoreWarnings)
	{
        // Disarm the autosave timer function.
        tool.clearAutosaveTimeout();
        
		var params = {};
		params.values = form.getJsonValues();
		params.contentId = contentId;
		params.unlock = quit;
        params.editWorkflowActionId = tool._workflowAction;
		params.viewName = tool._viewName;
        params.fallbackViewName = tool._fallbackViewName;
        params.bypassedWarnings = form.getWarnedFields();
        params.ignoreWarnings = ignoreWarnings;
		
        Ametys.cms.content.ContentDAO.editContent(params, Ext.bind(this._saveCb, this, [quit, form, tool], true), this, false, null, null, tool.getContentPanel());
		
		tool.fireMessageBeforeSaving();
	},
	
	/**
	 * @private
	 * This function is called after validated confirm dialog box
	 * @param {String} answer The button answer ('yes' or 'no')
	 * @param {Ametys.tool.Tool} tool The content tool
	 * @param {Ametys.form.ConfigurableFormPanel} form The form panel
	 * @param {String} contentId The content id
	 * @param {Boolean} quit True to quit edition after saving
     * @param {Boolean} ignoreWarnings True to ignore warnings from server response
	 */
	_bypassWarnedFields : function (answer, tool, form, contentId, quit, ignoreWarnings)
	{
		if (answer == 'yes')
		{
			this._continueSave (tool, form, contentId, quit, ignoreWarnings);
		}
	},
	
	/**
	 * Callback function called after #_doSave is processed.
	 * Fires {@link Ametys.message.Message#MODIFIED} message for edited contents
     * @param {boolean} success If the save was successful
     * @param {String} contentId The content id
     * @param {String[]} workflowErrors Errors messages related to the workflow
     * @param {Object} fieldsInError The list of fields in error associated with their error message
     * @param {Object} fieldsWithWarning The list of fields with warning associated with their warning message
     * @param {Boolean} ignoreWarnings True to ignore warnings from server response
     * @param {Boolean} quit True to quit edition after saving
     * @param {Ametys.form.ConfigurableFormPanel} form The form panel
     * @param {Ametys.tool.Tool} tool The content tool
	 * @private
	 */
	_saveCb: function (success, contentId, workflowErrors, fieldsInError, fieldsWithWarning, ignoreWarnings, quit, form, tool)
	{
        // Re-arm the autosave timer function.
	    tool.armAutosaveTimeout();
	    
        if (!success && workflowErrors == null && fieldsInError == null)
        {
            tool.fireMessageOnFailEdition();
            return;
        }
        
        if (!success && !Ext.Object.isEmpty(fieldsInError))
        {
            form.markFieldsInvalid (fieldsInError);
            return;
        }
        
        if (!success && ignoreWarnings)
        {
            // The ignore warning can only be set to true if there was warnings
            // But it can be warnings from global validator, then fieldsWithWarning is empty
            this._doSave (tool, form, contentId, quit, true);
            return;
        }
        
        if (!success && !Ext.Object.isEmpty(fieldsWithWarning))
        {
            form.markFieldsWarning (fieldsWithWarning);
            return;
        }

        if (!success)
        {
            return;
        }

        // If the current content has indexing references, send a message.
        if (tool.hasIndexingReferences())
        {
            Ametys.Msg.show({
                title: "{{i18n PLUGINS_CMS_SAVE_ACTION_CONTENT_MODIFICATION}}",
                msg: "{{i18n PLUGINS_CMS_SAVE_ACTION_CONTENT_HAS_INDEXING_REFERENCES}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.INFO
            });
        }
		
		// Delete the automatic save.
		Ametys.data.ServerComm.callMethod({
			role: "org.ametys.cms.content.autosave.ContentBackupClientInteraction",
			methodName: "deleteContentBackup",
			parameters: [contentId],
			callback: {
 				scope: this,
				handler: this._deleteAutoBackupCb
			},
			errorMessage: false
		});
        
		if (quit)
		{
			tool.quitEditionMode ();
		}
        else
        {
            // update base data
            tool._getData(function(response) {
                tool._baseData = tool._extractDataFromResponse(response);
            });
        }
		
		tool.setDirty(false);
		tool.fireMessagesOnSuccessEdition();
	},
	
	/**
	 * Callback invoked when an automatic save is deleted.
     * @param {Object} response The XML response provided by the {@link Ametys.data.ServerComm}
     * @param {Object} params The callback parameters passed to the {@link Ametys.data.ServerComm#send} method
     * @private
	 */
    _deleteAutoBackupCb: function(response, params)
    {
        // Ignore the callback.
    }
});