/*
 *  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 do action on workflow
 * @private
 */
Ext.define('Ametys.plugins.cms.content.actions.WorkflowAction', {
	singleton: true,
	
	/**
	 * @property {Number} _count Counter for processed contents
	 * @private
	 */
	_count: 0,
	
	/**
	 * @property {String[]} _cumulatedContentsIds Array of processed contents' ids
	 * @private
	 */
	_cumulatedContentsIds: [],
	
	/**
	 * @property {Ametys.window.DialogBox} _commentBox The popup window embedding a simple form with textarea to allow the user to enter a comment on workflow action
	 * @private
	 */
	_commentBox: null,
    
    /**
     * Action function to be called by the controller, check if it has to be confirmed.
     * Will execute the workflow action of controller on all contents stored by the controller in controller.contents properties
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     * @param {Function} [callback] The callback function to call instead of the _startAction method
     */
    doAction: function (controller, callback)
    {
        var needConfirm = controller.getInitialConfig('confirm') == "true";
        
        if (needConfirm)
        {
            var title = controller.getInitialConfig('confirm-title') || "{{i18n plugin.cms:PLUGINS_CMS_WORKFLOW_DO_ACTION_TITLE}}";
            var confirmMsg = controller.getInitialConfig('confirm-msg') || "{{i18n plugin.cms:PLUGINS_CMS_WORKFLOW_DO_ACTION_CONFIRM_MSG}}";
            
            Ametys.Msg.confirm(title,
                confirmMsg,
                function(answer)
                {
                    if (answer == 'yes')
                    {
                        Ametys.plugins.cms.content.actions.WorkflowAction._doAction(controller, callback);
                    }
                }
            );
        }
        else
        {
            Ametys.plugins.cms.content.actions.WorkflowAction._doAction(controller, callback);
        }
    },
    
    /**
     * Action function to be called by the controller.
     * Will execute the workflow action of controller on all contents stored by the controller in controller.contents properties
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     * @param {Function} [callback] The callback function to call instead of the _startAction method
     * @private
     */
    _doAction: function (controller, callback)
    {
        if (controller.getInitialConfig('comment') == "true")
        {
            this._showCommentBox (controller, callback);
        }
        else if (callback)
        {
            callback(controller, '');
        }
        else
        {
            this._startAction (controller, '');
        }
    },
	
	/**
	 * Execute the workflow action of controller on all contents stored by the controller in controller.contents properties
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the #doAction function
	 * @param {String} comment The comments writen by caller. Can be empty
	 * @private
	 */
	_startAction: function (controller, comment /*, args */)
	{
		// Controller can be a WorkflowMenu item or SmartContentController
		var actionId = controller.getInitialConfig('workflow-action-id') || controller.getWorkflowActionId();
		var contentIds = controller.contents || controller.getContentIds();
		var longRequest = controller.getConfig("long-request") || controller.getInitialConfig('long-request');
        if (!Ext.isBoolean(longRequest))
        {
            longRequest = longRequest === 'true';
        }
        
        var args = Array.prototype.slice.call(arguments, 2);
        
        var me = this;
        Ametys.cms.content.ContentDAO.getContents(contentIds, function(contents) {
            Ext.create("Ametys.message.Message", {
	            type: controller.getInitialConfig('workflow-changing-message-type') || Ametys.message.Message.WORKFLOW_CHANGING,
	            
	            targets: {
	                id: Ametys.message.MessageTarget.CONTENT,
	                parameters: { contents: contents }
	            }
	        });
            
	        for (var i=0; i < contents.length; i++)
	        {
	            var contentId = contents[i].getId();
	            
	            Ametys.data.ServerComm.send({
	                plugin: controller.getInitialConfig('workflow-action-plugin') || 'cms',
	                url: (controller.getInitialConfig('workflow-action-url') || 'do-action') + '/' + actionId,
	                parameters: {contentId: contentId, id: contentId, comment: comment, args: args}, 
	                priority: longRequest ? Ametys.data.ServerComm.PRIORITY_LONG_REQUEST : Ametys.data.ServerComm.PRIORITY_MAJOR, 
	                waitMessage: controller.getConfig("waitMessage") || controller.getInitialConfig('waitMessage') || false,
	                callback: {
	                    handler: me._workflowActionCallback,
	                    scope: me,
	                    arguments: [contentId, contents.length, controller, contents]
	                }
	            });
	        }
        });
	},
	
	/**
	 * Callback function called after #_startAction is processed.
	 * Fires Ametys.message.Message.WORKFLOW_CHANGED message for concerned contents
	 * @param {Object} response The XML response provided by the {@link Ametys.data.ServerComm}
	 * @param {Object} args The callback parameters passed to the {@link Ametys.data.ServerComm#send} method
	 * @private
	 */
	_workflowActionCallback: function (response, args)
	{
		this._cumulatedContentsIds = this._cumulatedContentsIds || [];
		this._count = this._count > 0 ? this._count : 0;
		
		this._cumulatedContentsIds.push(args[0]);
		this._count++;
		
        var controller = args[2];
        
		if (Ametys.data.ServerComm.handleBadResponse("{{i18n PLUGINS_CMS_WORKFLOW_ERROR_DESC}}", response, "Ametys.plugins.cms.content.controller.WorkflowMenu.doAction"))
        {
            // Fail: send WORKFLOW_CHANGED for all initial contents to stop refreshing of controller that listened for WORKFLOW_CHANGING
            Ext.create("Ametys.message.Message", {
                type: controller.getInitialConfig('workflow-changed-message-type') || Ametys.message.Message.WORKFLOW_CHANGED,
                
                targets: {
                    id: Ametys.message.MessageTarget.CONTENT,
                    parameters: { contents: args[3] }
                }
            });
            return;
        }
		
        
        var notificationMode = controller.getConfig("end-process-notification") || controller.getInitialConfig('end-process-notification') || 'message-box';
        
		var success = Ext.dom.Query.selectValue ('> ActionResult > success', response) == "true";
		
		var workflowErrors = Ext.dom.Query.select ('> ActionResult > workflowValidation > error', response);
		if (!success && workflowErrors.length > 0)
		{
			var errorMsg = "{{i18n PLUGINS_CMS_WORKFLOW_ERROR_DESC}}" + args[0];
			errorMsg += '<ul>';
			for (var i=0; i < workflowErrors.length; i++)
			{
				errorMsg += '<li>' + Ext.dom.Query.selectValue("", workflowErrors[i]) + '</li>';
			}
			errorMsg += '</ul>';
			
            if (notificationMode == 'message-box')
            {
                Ametys.Msg.show({
	                title: "{{i18n PLUGINS_CMS_WORKFLOW_ERROR_TITLE}}",
	                msg: errorMsg,
	                buttons: Ext.Msg.OK,
	                icon: Ext.Msg.ERROR
	            });
            }
            else
            {
                Ametys.notify({
                    type: 'error',
                    iconGlyph: 'ametysicon-letter-x5',
                    title: "{{i18n PLUGINS_CMS_WORKFLOW_ERROR_TITLE}}",
                    description: errorMsg
                });
            }
			
			return;
		}
        
        var workflowWarnings = Ext.dom.Query.select ('> ActionResult > workflowValidation > warning', response);
        if (workflowWarnings.length > 0)
        {
            var warnMsg = "{{i18n PLUGINS_CMS_WORKFLOW_WARN_DESC}}";
            warnMsg += '<ul>';
            for (var i=0; i < workflowWarnings.length; i++)
            {
                warnMsg += '<li>' + Ext.dom.Query.selectValue("", workflowWarnings[i]) + '</li>';
            }
            warnMsg += '</ul>';
            
            if (notificationMode == 'message-box')
            {
                Ametys.Msg.show({
	                title: "{{i18n PLUGINS_CMS_WORKFLOW_WARN_TITLE}}",
	                msg: warnMsg,
	                buttons: Ext.Msg.OK,
	                icon: Ext.Msg.WARNING
	            });
            }
            else
            {
                Ametys.notify({
                    type: 'warn',
                    iconGlyph: 'ametysicon-caution9',
                    title: "{{i18n PLUGINS_CMS_WORKFLOW_WARN_TITLE}}",
                    description: warnMsg
                });
            }
        }
		
		// FIXME Optimize "with-contents"
		
		var max = args[1];
		if (this._count == max)
		{
            Ametys.cms.content.ContentDAO.getContents(this._cumulatedContentsIds, function(contents) {
                
                // FIXME Fire lock changed ?
                
                Ext.create("Ametys.message.Message", {
	                type: controller.getInitialConfig('workflow-changed-message-type') || Ametys.message.Message.WORKFLOW_CHANGED,
	                
	                targets: {
	                    id: Ametys.message.MessageTarget.CONTENT,
	                    parameters: { contents: contents }
	                }
	            });
                
                var successMsg = controller.getConfig("successMsg") || controller.getInitialConfig('successMsg');
	            if (workflowWarnings.length == 0 && successMsg)
	            {
                    var contentTitles = [];
                    Ext.Array.each(contents, function(content){
                        contentTitles.push(content.getTitle());
                    });
	                Ametys.notify({
	                    type: 'info',
	                    iconGlyph: 'ametysicon-check34',
	                    title: controller.getConfig("successTitle") || controller.getInitialConfig('successTitle') || "{{i18n PLUGINS_CMS_WORKFLOW_SUCCESS_TITLE}}",
	                    description: Ext.String.format(successMsg, contentTitles)
	                });
	            }
            });
            
            this._count = 0;
            this._cumulatedContentsIds = [];
		}
	},
	
	/**
	 * This function show dialog to enter comment on workflow action
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the #doAction function
	 * @param {Function} [callback] The callback function to call after validating comment
	 * @private
	 */
	_showCommentBox: function (controller, callback)
	{
		if (this._commentBox == null)
		{
			this._commentBox = Ext.create('Ametys.window.DialogBox', {
				title: "{{i18n PLUGINS_CMS_WORKFLOW_COMMENTS_DIALOG_TITLE}}",
				icon: Ametys.getPluginResourcesPrefix('cms') + '/img/content/content_16.png',
				cls: 'text-dialog',
				
				width: 450,
				height: 250,
				scrollable: false,
				
				defaults: {
					cls: 'ametys',
					labelAlign: 'right',
					labelSeparator: '',
					labelWidth: 120
				},
				
				items: [{
							xtype: 'component',
							html: "{{i18n PLUGINS_CMS_WORKFLOW_COMMENTS_DIALOG_MESSAGE}}",
							width: '100%'
						}, 
						{
							xtype: 'textareafield',
							name: 'comment',
							itemId: 'workflow-comment',
							ametysDescription: "{{i18n PLUGINS_CMS_WORKFLOW_COMMENTS_DIALOG_TEXTAREA_DESC}}",
							width: '100%',
							height: 140
						}
				],
				
				defaultFocus: 'workflow-comment',
				closeAction: 'hide',
				buttons : [{
					text :"{{i18n PLUGINS_CMS_WORKFLOW_COMMENTS_DIALOG_OK}}",
					handler : Ext.bind(this._validateComment, this, [controller, callback])
				}, {
					text :"{{i18n PLUGINS_CMS_WORKFLOW_COMMENTS_DIALOG_CANCEL}}",
					handler: Ext.bind(function() {this._commentBox.hide();}, this) 
				}]
			});
		}
		else
		{
			this._commentBox.down('button').setHandler (Ext.bind(this._validateComment, this, [controller, callback]));
		}
		
		this._commentBox.down('#workflow-comment').setValue('');
		this._commentBox.show();
	},
	
	/**
	 * Function handler called when the 'Ok' button of #_commentBox dialog box is pressed
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the #doAction function
	 * @param {Function} [callback] The callback function
	 * @private
	 */
	_validateComment: function (controller, callback)
	{
		var comment = this._commentBox.down('#workflow-comment').getValue();
		this._commentBox.hide();
		
		if (callback)
		{
			callback(controller, comment);
		}
		else
		{
			this._startAction (controller, comment);
		}
	}
});