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

/**
 * @private
 * Archive content
 */
Ext.define('Ametys.plugins.cms.content.actions.ArchiveContentAction', {
    singleton: true,
    
    /**
     * @private
     * @property {String} archivePluginName The plugin to call when archiving
     */
    archivePluginName: 'cms',
    /**
     * @private
     * @property {String} unarchivePluginName The plugin to call when unarchiving
     */
    unarchivePluginName: 'cms',
    
    /**
     * @property {Number} _count Counter for processed contents.
     * @private
     */
    _count: 0,
    
    /**
     * @property {String[]} _cumulatedContentsIds Array of processed contents' ids.
     * @private
     */
    _cumulatedContentsIds: [],
    
    /**
     * @property {String[]} _cumulatedContentsTargets Array of processed contents' targets.
     * @private
     */
    _cumulatedContentsTargets: [],
    
    /**
     * Action which archives the selected content(s).
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The button controller.
     */
    archive: function(controller)
    {
        var contentIds = controller.getContentIds();
        if (contentIds.length > 0)
        {
            var actionId = controller.getInitialConfig()['workflow-action-id'];
            
            var callback = Ext.bind(this._canArchiveCb, this);
            
            controller.serverCall('canArchive', [contentIds], callback, { arguments: {contentIds: contentIds, targets: controller.getMatchingTargets(), actionId: actionId, controller: controller} });
        }
    },
    
    /**
     * Process the "canArchive" test results.
     * @param {Object[]} params The JSON result.
     * @param {String[]} params.referenced-contents the referenced contents 
     * @param {Object[]} args The callback arguments.
     * @param {String} args.targets the candidates for the archiving
     * @param {String} args.actionId the id of the action to be performed
     * @private
     */
    _canArchiveCb: function(params, args)
    {
        var noRightsContents = params['no-right-contents'];
        var referencedContents = params['referenced-contents'];
        
        if (noRightsContents.length > 0 || referencedContents.length > 0)
        {
            var message = "";
            if (noRightsContents.length > 0)
            {
                message += "{{i18n plugin.cms:CONTENT_ARCHIVE_NO_RIGHT}}";
	            for (var i=0; i < noRightsContents.length; i++)
	            {
	                message += (i > 0 ? ', ' : '') + noRightsContents[i].title;
	            }
	            message += ".";
            }
            
            if (referencedContents.length > 0)
            {
                if (message != '')
                {
                    message += ".<br/><br/>";
                }
                message += "{{i18n plugin.cms:CONTENT_ARCHIVE_REFERENCED_CONTENTS}}";
	            for (var i=0; i < referencedContents.length; i++)
	            {
	                message += (i > 0 ? ', ' : '') + referencedContents[i].title;
	            }
	            message += ".<br/>{{i18n plugin.cms:CONTENT_ARCHIVE_REFERENCED_CONTENTS_END}}";
            }
            
            Ametys.Msg.show({
                title: "{{i18n plugin.cms:CONTENT_ARCHIVE_LABEL}}",
                msg: message,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
        }
        else
        {
            Ametys.Msg.confirm(
                "{{i18n plugin.cms:CONTENT_ARCHIVE_LABEL}}",
                "{{i18n plugin.cms:CONTENT_ARCHIVE_CONFIRM}}",
                function(answer)
                {
                    if (answer == 'yes')
                    {
                        this.doArchive(args.contentIds, args.targets, args.actionId, args.controller);
                    }
                },
                this
            );
        }
    },
    
    /**
     * Effectively archives the selected content(s).
     * @param {String[]} contentIds The content ids.
     * @param {Object[]} contentTargets The content targets.
     * @param {String} actionId The archive action ID.
     * @param {Object} controller The controller
     */
    doArchive: function(contentIds, contentTargets, actionId, controller)
    {
        var url = 'archives/archive/' + actionId;
        
        var viewport = Ext.ComponentQuery.query('viewport')[0];
        
        this._count = 0;
        this._cumulatedContentsTargets = [];
        
        var archivedContentTargets = [];
        
        Ametys.data.ServerComm.suspend();
        for (var i=0; i < contentIds.length; i++)
        {
            var contentId = contentIds[i];
            
            var archivedContentTarget;
            for (var j=0; j < contentTargets.length; j++)
            {
                if (contentTargets[j].getParameters().id == contentId)
                {
                    archivedContentTarget = contentTargets[j];
                    archivedContentTargets.push(archivedContentTarget);
                    break;
                }
            }
            
            Ametys.data.ServerComm.send({
                plugin: this.archivePluginName,
                url: url,
                parameters: {
                    contentId: contentId
                },
                waitMessage: "{{i18n plugin.cms:CONTENT_ARCHIVE_WAITING_MESSAGE}}",
                callback: {
                    handler: this.doArchiveCallback,
                    scope: this,
                    arguments: {
                        id: contentId,
                        target: archivedContentTarget,
                        total: contentIds.length,
                        controller: controller
                    }
                }
            });
        }
        Ametys.data.ServerComm.restart();
        
    },
    
    /**
     * Callback function called when the content is archived.
     * Fires 'archived' 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
     */
    doArchiveCallback: function(response, args)
    {
        this._cumulatedContentsTargets.push(args.target);
        this._count++;
        
        if (Ametys.data.ServerComm.handleBadResponse("{{i18n plugin.cms:CONTENT_ARCHIVE_ERROR}}", response, 'Ametys.plugins.cms.content.actions.ArchiveContentAction.archive'))
        {
            return;
        }
        
        var total = args.total;
        if (this._count == total)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.ARCHIVED,
                targets: this._cumulatedContentsTargets
            });
        }
        
        // Force stop refreshing
        args.controller.stopRefreshing(true);
    },
    
    /**
     * Action which retrieves one or several content(s) from the archives.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The button controller.
     */
    unarchive: function(controller)
    {
        var contentTargets = controller.getMatchingTargets();
        
        if (contentTargets.length > 0)
        {
            Ametys.Msg.confirm(
                    "{{i18n plugin.cms:CONTENT_UNARCHIVE_LABEL}}",
                    "{{i18n plugin.cms:CONTENT_UNARCHIVE_CONFIRM}}",
                    function(answer)
                    {
                        if (answer == 'yes')
                        {
                            var actionId = controller.getInitialConfig()['workflow-action-id'];
                            this.doUnarchive(contentTargets, actionId);
                        }
                    },
                    this
            );
        }
    },
    
    /**
     * Effectively unarchives the selected content(s).
     * @param {Object[]} contentTargets The content targets.
     * @param {String} actionId The archive action ID.
     */
    doUnarchive: function(contentTargets, actionId)
    {
        var url = 'archives/unarchive/' + actionId;
        
        var viewport = Ext.ComponentQuery.query('viewport')[0];
        
        var contentIds = [];
        
        this._count = 0;
        this._cumulatedContentsIds = [];
        
        Ametys.data.ServerComm.suspend();
        for (var i=0; i < contentTargets.length; i++)
        {
            var contentId = contentTargets[i].getParameters().id;
            
            contentIds.push(contentId);
            
            Ametys.data.ServerComm.send({
                plugin: this.unarchivePluginName,
                url: url,
                parameters: {
                    contentId: contentId
                },
                waitMessage: "{{i18n plugin.cms:CONTENT_UNARCHIVE_WAITING_MESSAGE}}",
                callback: {
                    handler: this.doUnarchiveCallback,
                    scope: this,
                    arguments: {
                        id: contentId,
                        target: contentTargets[i],
                        total: contentTargets.length
                    }
                }
            });
        }
        Ametys.data.ServerComm.restart();
    },
    
    /**
     * Callback function called when the content is unarchived.
     * Fires 'unarchived' 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
     */
    doUnarchiveCallback: function(response, args)
    {
        this._cumulatedContentsIds.push(args.id);
        this._count++;
        
        if (Ametys.data.ServerComm.handleBadResponse("{{i18n plugin.cms:CONTENT_UNARCHIVE_ERROR}}", response, 'Ametys.plugins.cms.content.actions.ArchiveContentAction.unarchive'))
        {
            return;
        }
        
        var total = args.total;
        if (this._count == total)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.UNARCHIVED,
                
                targets: {
                    id: Ametys.message.MessageTarget.CONTENT,
                    parameters: { ids: this._cumulatedContentsIds }
                }
            });
        }
    },
    
    /**
     * Action which schedules the archiving of the selected content(s).
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The button controller.
     */
    schedule: function(controller)
    {
        this._scheduleContentsId = controller.getContentIds();
        if (this._scheduleContentsId.length > 0)
        {
            if (!this._scheduleDelayedInitialize(controller))
            {
                return;
            }
            
            this._scheduleInitForm(this._scheduleContentsId, controller);
            this._scheduleBox.show();
        }
    },
    
    /**
     * Inialize the archive schedule dialog box.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The button controller.
     * @return {Boolean} `true` if the dialog box was sucessfully initialized.
     * @private
     */
    _scheduleDelayedInitialize: function(controller)
    {
        if (this._scheduleInitialized)
        {
            return true;
        }
        
        // Scheduled date
        this._dateField = Ext.create('Ext.form.field.Date', {
            fieldLabel: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_DATE}}",
            ametysDescription: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_DATE_DESC}}",
            name: 'scheduledArchivingDate',
            minValue: Ext.Date.add(new Date(), Ext.Date.DAY, 1),
            submitFormat: Ext.Date.patterns.ISO8601DateTime,
            width: '90%',
            labelWidth: 100,
            cls: 'ametys',
            labelSeparator: '',
            labelAlign: 'right'
        });
        
        // Dialog box.
        this._scheduleBox = Ext.create('Ametys.window.DialogBox', {
            title: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_DIALOG_TITLE}}",
            iconCls: 'ametysicon-archive decorator-ametysicon-clock56',
            
            width: 410,
            scrollable: true,
            
            items: [{
                    xtype: 'component',
                    cls: 'a-text',
                    html: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_HINT}}"
                },
                this._dateField
            ],
            
            defaultFocus: this._dateField,
            closeAction: 'hide',
            
            referenceHolder: true,
            defaultButton: 'validate',
            
            buttons : [{
            	reference: 'validate',
                text: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_DIALOG_OK_BTN}}",
                handler: Ext.bind(this.scheduleOk, this, [controller]),
                scope: this
            }, {
                text: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_DIALOG_CANCEL_BTN}}",
                handler: this.scheduleCancel,
                scope: this
            }]
        });
        
        this._scheduleInitialized = true;
        
        return true;
    },

    /**
     * Inialize the form from a list of content IDs.
     * @param {String[]} contentIds An array of the selected content IDs.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The button controller.
     * @private
     */
    _scheduleInitForm: function (contentIds, controller)
    {
    	controller.serverCall(
      	       'getScheduledArchivingDate', [contentIds], Ext.bind (this._scheduleInitFormCb, this), null,
      		   {
      		        errorMessage: {
      		        	msg: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_ERROR}}",
      					category: "Ametys.plugins.cms.content.actions.ArchiveContentAction.schedule"
      		        }
      		   }
      	   );
    },
    
    /**
     * Callback function invoked when the scheduling information are returned.
     * @param {Object} response The JSON server response
     * @param {Object} args The callback parameters
     * @private
     */
    _scheduleInitFormCb: function(response, args)
    {
        var date = response['content']['date'];
        
        if (date)
        {
            this._dateField.setValue(Ext.Date.parse(date, Ext.Date.patterns.ISO8601DateTime));
        }
        else
        {
            this._dateField.setValue('');
        }
    },
    
    /**
     * OK button handler: send the message saving the schedule date.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The button controller.
     * @private
     */
    scheduleOk: function (controller)
    {
        if (this._dateField.isValid())
        {
        	var date = Ext.Date.format(this._dateField.getValue(), Ext.Date.patterns.ISO8601DateTime);
        	
            controller.serverCall(
         	       'setScheduledArchivingDate', [this._scheduleContentsId, date], Ext.bind (this._scheduleOkCb, this), null,
         		   {
         		        errorMessage: {
         		        	msg: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_ERROR}}",
         					category: "Ametys.plugins.cms.content.actions.ArchiveContentAction.schedule"
         		        }
         		   }
         	   );
        }
    },
    
    /**
     * Callback function invoked when the schedule date storing action has finished.
     * @param {Object} result The JSON server response
     * @param {Object} args The callback parameters
     * @private
     */
    _scheduleOkCb: function(result, args)
    {
        this._scheduleBox.hide();
        
        var failedContents = result.error;
        
        if (failedContents.length > 0)
        {
        	var message = "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_ERROR_WITH_CONTENTS}}" + '<ul>';
        	Ext.Array.each (failedContents, function (content) {
        		message += '<li>' + content + '</li>';
            });
        	message += '</ul>';
        	
        	Ametys.log.ErrorDialog.display({
                title: "{{i18n plugin.cms:PLUGINS_CMS_ARCHIVE_SCHEDULE_ERROR_TITLE}}", 
                text: message,
                category: 'Ametys.plugins.cms.content.actions.ArchiveContentAction.schedule'
            });
        }
        
        var successContents = result.success;
        if (successContents.length > 0)
        {
        	var contentIds = [];
        	
        	Ext.Array.each (successContents, function (content) {
        		contentIds.push(content);
            });
        	
        	Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.MODIFIED,
                parameters: {major: false},
                
                targets: {
                    id: Ametys.message.MessageTarget.CONTENT,
                    parameters: { ids: contentIds }
                }
            });
        }
    },
    
    /**
     * Cancel button handler: close the dialog box.
     * @param {Ext.button.Button} btn The clicked button.
     * @private
     */
    scheduleCancel: function(btn)
    {
        this._scheduleBox.hide();
    }
    
});