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

/**
 * @private
 * This class control a ribbon menu representing the workflow state.
 * It HAS to be used in conjunction with the java org.ametys.cms.clientsideelement.WorkflowStepsClientSideElement
 */
Ext.define('Ametys.plugins.cms.content.controller.WorkflowMenu', {
	extend: 'Ametys.ribbon.element.ui.ButtonController',

    /**
     * @property {String} workflowItems The name of items concerned by this workflow
     */
    workflowItems: 'contents',
    
	/**
	 * @property {Boolean} _visible The current visible state for the menu
	 * @private
	 */
	
	constructor: function (config)
	{
        config['toggle-enabled'] = true;
        
		this.callParent(arguments);
		
		this._visible = true;
		
        Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGING, this._onWorkflowChanging, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.LOCK_CHANGED, this.refreshIfMatchingMessage, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGED, this._onWorkflowChanged, this);
	},
    
    /**
     * @private
     * Listener on workflow changing. Set buttons in refreshing state
     * @param {Ametys.message.Message} message The bus message
     */
    _onWorkflowChanging: function (message)
    {
        if (this.updateTargetsInCurrentSelectionTargets (message))
        {
            this.refreshing();
        }
    },
    
    /**
     * @private
     * Listener on workflow changed. Stop the refreshing state and refresh
     * @param {Ametys.message.Message} message The bus message
     */
    _onWorkflowChanged: function (message)
    {
        if (this.updateTargetsInCurrentSelectionTargets (message))
        {
            this.stopRefreshing();
            this.refresh(true);
        }
    },  
    
    updateState: function()
    {
        this.stopRefreshing(true);
            
        this._getWorkflowState(this.getMatchingTargets());
    },
	
	/**
	 * Get the lock state of given targets
	 * @param targets The content targets
	 * @private
	 */
	_getWorkflowState: function (targets)
	{
        var workflowName = this.getInitialConfig("workflow-name");
        
        // Avoid workflow button to be updated if the content is not of the concerned workflow
        var matchingTargets = Ext.Array.filter(targets, function (target) {
            return !target.getParameters().workflowName || target.getParameters().workflowName == workflowName;
        }, this);
        
        if (matchingTargets.length > 0)
        {
            this.disable();

            var result = this._calculateStatus(targets);
            this._getWorkflowStateCb(result);
        }
        else
        {
            // There is no target matching the concerned workflow, hide button
            this._hide();
        }

	},

    /**
     * @protected
     * Simulation of getStatus server side, done only client-side.
     * In cases where the server side still needs to be called, see Ametys.plugins.cms.content.controller.SmartContentController#_getStatus
     * @param {Object[]} targets see Ametys.ribbon.element.ui.CommonController#getMatchingTargets
     * @return {Object} a map of arrays representing contents in different states. default is unmodifiable-contents, locked-contents, noright-contents, invalidworkflowaction-contents,invalidworkflowstep-contents, allright-contents  
     */
    _calculateStatus: function(targets)
    {
        var result = {};
        result["contents"] = [];
        var invalidWorkflowForAllContents = true;

        Ext.Array.each(targets, function(matchingTarget)
            {
                var parameters = matchingTarget.getParameters();
                if (parameters && parameters.content)
                {
                    var content = parameters.content;
                    if (this.getInitialConfig("workflow-name") == content.getWorkflowName())
                    {
                        invalidWorkflowForAllContents = false;
                        if (content.getWorkflowSteps() != null && content.getWorkflowSteps().indexOf(this.getInitialConfig("workflow-step")) >= 0)
                        {
                            var contentParams = {};
                            contentParams["id"] = content.getId();
                            contentParams["title"] = content.getTitle();
                            var description;

                            if (content.getLocked() && !this._isLockOwner(content))
                            {
                                var i18nStr = "{{i18n plugin.cms:CONTENT_WORKFLOW_LOCKED_DESCRIPTION}}";
                                var lockOwner = content.getLockOwner();
                                var fullName = lockOwner != null ? lockOwner.fullname : "";
                                var login = lockOwner != null ? lockOwner.login : "Anonymous";
                                description = Ext.String.format(i18nStr, content.getTitle(), fullName, login);
                            }
                            else
                            {
                                var i18nStr = "{{i18n plugin.cms:CONTENT_WORKFLOW_DESCRIPTION}}";
                                description = Ext.String.format(i18nStr, content.getTitle());
                            }
                            contentParams["description"] = description;

                            contentParams["locked"] = content.getLocked();

                            var availableActions = content.getAvailableActions();
                            contentParams["actions"] = availableActions;

                            result["contents"].push(contentParams);
                        }
                    }
                }
            }, this);
        if (invalidWorkflowForAllContents)
        {
            result["invalidWorkflow"] = true;
        }
        return result;
    },

    /**
     * @private
     * Is the given locked content, locked by the current user?
     * @param {Ametys.cms.content.Content} content A locked content
     * @return {Boolean} true is the current user is the locker.
     */
    _isLockOwner: function (content)
    {
        var currentUser = Ametys.getAppParameter('user');
        var lockOwner = content.getLockOwner();
        return currentUser.login === lockOwner.login && currentUser.population === lockOwner.populationId;
    },
	
	/**
	 * @private
	 * Callback function called after retrieving the workflow state of content targets
	 * @param params The JSON result 
	 */
	_getWorkflowStateCb: function (params)
	{
		if (params && params[this.workflowItems].length > 0)
		{
			// Workflow actions of menu items
			var hasActionEnabled = false;
			
			var menuitems = this.getInitialConfig("menu-items") ? this.getInitialConfig("menu-items") : [];
			if (menuitems.length > 0)
			{
				var menuActions = {};
				
				for (var i=0; i < menuitems.length; i++)
				{
					var item = Ametys.ribbon.RibbonManager.getUI(menuitems[i]);
					var actionId = item.getInitialConfig("workflow-action-id");
					menuActions[actionId] = [];
				}
				
				var contents = params[this.workflowItems];
				for (var i=0; i < contents.length; i++)
				{
					var actions = contents[i].actions;
					
					for (var actionId in menuActions)
					{
						if (Ext.Array.contains (actions, parseInt(actionId)))
						{
							menuActions[actionId].push(contents[i].id);
						}
					}
				}
				
				for (var i=0; i < menuitems.length; i++)
				{
					var item = Ametys.ribbon.RibbonManager.getUI(menuitems[i]);
					var actionId = item.getInitialConfig("workflow-action-id");
					var multiSelectionEnabled = item.getInitialConfig("selection-enable-multiselection") != "false";
                    
					if (menuActions[actionId].length > 0 && (multiSelectionEnabled || contents.length == 1))
					{
						item.enable();
						item[this.workflowItems] = menuActions[actionId];
						hasActionEnabled = true;
					}
					else
					{
						item.contents = [];
						item.disable()
					}
				}
			}
			
			var description = this._getTooltipDescription (this.getInitialConfig("description"), params);
			if (!hasActionEnabled && menuitems.length > 0)
			{
				description += '<br/><br/>';
				description += this.getInitialConfig("noaction-available-description");
			}
			this.setDescription (description);
			this.toggle(true);
			this._show();
			this[hasActionEnabled || menuitems.length == 0 ? 'enable' : 'disable'](); // enable or disable
		}
		else
		{
			this.setDescription (this.getInitialConfig("description") + '<br/><br/>' + this.getInitialConfig("selection-description-nomatch"));
			this.toggle(false);
			this.disable();
			this[params.invalidWorkflow ? '_hide' : '_show'](); // hide or show
		}
	},
	
	/**
	 * Show all controlled ui
	 */
	_show: function()
	{
		if (!this._visible)
		{
			this._visible = true;
			
			this.getUIControls().each(function (controller) {
				controller.show();
			});
		}
	},
	
	/**
	 * Hide all controlled ui
	 */
	_hide: function()
	{
		if (this._visible)
		{
			this._visible = false;
			
			this.getUIControls().each(function (controller) {
				controller.hide();
			});
		}
	},
	
	/**
	 * @private
	 * Get the tooltip description according to workflow state of the current selection
	 * @return The description
	 */
	_getTooltipDescription: function (description, params)
	{
		var contents = params["contents"];
		if (contents.length > 0)
		{
			if (description != "")
			{
				description += "<br/><br/>";
			}
			
			description += this.getInitialConfig("contentselected-start-description");
			for (var i=0; i < contents.length; i++)
			{
				if (i != 0) 
				{
					description += ", ";
				}
				description += contents[i].description;
			}
			description += this.getInitialConfig("contentselected-end-description");
		}
		
		return description;
	}
});