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

/**
 * This button allows to create a content and reference-it or create it as sub-content of the selected content (on a given metadata)
 */
Ext.define('Ametys.plugins.contentstree.AddContentToCurrentSelectionButtonController', {
	extend: "Ametys.ribbon.element.ui.ButtonController",
	
	statics: {
		/**
		 * @private
		 * The action of this controller
		 * @param {Ametys.ribbon.element.ui.ButtonController} controller The button controller
		 * @param {Boolean} state The toggle state or null
		 */
		act: function(controller, state)
		{
			var target = controller.getMatchingTargets()[0];
			
			if (target != null)
			{
				var contentId = target.getParameters().id;
				var contentPathIds = target.getParameters().contentPathIds;
                var messageType = target.getId();

				controller.serverCall("getModelItemType", [contentId, controller._getSourceAttributeRef()], Ext.bind(controller.act, controller, [contentId, messageType], true), {arguments: {contentPathIds : contentPathIds}}, true);
			}
		}
	},
	
	/**
	 * @cfg {String} source-editWorkflowActionId (required) This is the value of the edit action in the workflow of the source object. If the action is not available, the button will remain grayed.
	 */
	/**
	 * @cfg {String} source-metadata-ref (required) The attribute path to edit to add the new content. The attribute type must fit.
	 */
    /**
     * @cfg {String} [source-metadata-content-types] List of restricted content types, seperated by coma. The initial content types are deductible from the attribute.
     */
    /**
     * @cfg {Boolean} [include-private-content-types=false] Set the 'true' to allow private content types.
     */
	/**
	 * @cfg {String} target-initWorkflowActionId (required) The action identifier to initialize the new workflow instance for the new content
	 */
	/**
	 * @cfg {String} [target-workflowName] The workflow name for the new workflow instance for the new content
	 */
	/**
	 * @cfg {String} target-directEdition "true" if the newly created content should be opened in edition. See #cfg-target-editWorkflowActionId
	 */
	/**
	 * @cfg {String} target-editWorkflowActionId If #cfg-target-directEdition is "true", this have to be set the edit workflow action identifier.
	 */
    /**
     * @cfg {String} [target-openContent=true] If "false" the created content should not be open.
     */
	/**
	 * @cfg {Object} target-additionalWorkflowParameters Additional workflow parameters to be added to the server request. All request parameters will be prefixed by "workflow-".
	 */
	/**
	 * @cfg {String} action Default to "Ametys.cms.content.tree.AddContentToCurrentSelectionButtonController#act"
	 * @private
	 */
    /**
     * @cfg {String} unavailable-workflowaction-description The description when the workflow action is not available on source object.
     */
    
	constructor: function(config)
	{
		config['action'] = config['action'] || "Ametys.plugins.contentstree.AddContentToCurrentSelectionButtonController.act";
		
		this.callParent(arguments);
	},
    
    updateState: function ()
    {
        this.stopRefreshing(true);
        
        var target = this.getMatchingTargets()[0]; // multilection not supported (here assume that the number of matching targets is equals to 1)
        var availableActions = target.getParameters()['availableActions'];
        if (!Ext.Array.contains(availableActions, parseInt(this.getInitialConfig("source-editWorkflowActionId"))))
        {
            this.disable();
            this.setAdditionalDescription(this.getInitialConfig("unavailable-workflowaction-description") || this.getInitialConfig("error-description"));
        }
        else
        {
            this.enable();
            this.setAdditionalDescription();
        }
    },
    
	
	/**
	 * @private
	 * This method is called when the button is pressed and when the server sent the model-item-type
	 * @param {Object} result The result of the Ametys.cms.content.tree.AddContentToCurrentSelectionButtonController#act method
	 * @param {String} result.model-item-type Can be "content" or "sub_content"
	 * @param {String} result.contenttype The content type that is compatible. Can be null
	 * @param {String} result.language The content language
     * @param {Object} args The transmitted args
	 * @param {String} contentId The currently selected content identifier
	 * @param {String} messageType The bus message type (such as 'content')
     * @param {Object} [forceValues] A object with the values to force in creation form. Theses values only concerned the field of a creation metadata set if exists.
     * @param {String} [forceMode=hide] If forceValues is used, a String which specifies how the forced field should appear : 'hide' to hide the fields, 'readOnly' to display the fields preveting the user from changing the fields
	 * @param {Object} [initValues] A object with the initial values in creation form. Theses values only concerned the field of a creation metadata set if exists.
     */
	act: function(result, args, contentId, messageType, forceValues, forceMode, initValues)
	{
		var contentType = result["contenttype"];
		var metadataType = result["model-item-type"];
		var language = result["language"];
        
        var includePrivate = this.getInitialConfig("include-private-content-types") == "true";
		
        var contentTypes; 
        if (contentType == null) /* No restriction for the metadata content type */
        {
            contentTypes = Ametys.cms.content.ContentTypeDAO.getContentTypes()
        }
        else
        {
            contentTypes = Ametys.cms.content.ContentTypeDAO.getContentType(contentType).getDescendantsOrSelf();
        }
        
        contentTypes = contentTypes.createFiltered(function(contentType) {
            return contentType.hasRight()
                && (!contentType.isPrivate() || includePrivate)
                && !contentType.isMixin()
                && !contentType.isAbstract()
        });
        
		if (contentTypes.count() == 0)
		{
			Ext.MessageBox.show({msg: "{{i18n PLUGINS_CONTENTSTREE_ADDELEMENT_NOCONTENTTYPES}}"});
			return;
		}
        
        contentTypes = this._filterContentTypes(contentTypes.getRange());

    	var openParams = {
			contentTypes: contentTypes,
			contentLanguage: language,
			initWorkflowActionId: this.getInitialConfig("target-initWorkflowActionId"),
            initAndEditWorkflowActionId: this.getInitialConfig("target-initAndEditWorkflowActionId"),
            editWorkflowActionId: this.getInitialConfig("target-editWorkflowActionId"),
			workflowName: this.getInitialConfig("target-workflowName"),
			additionalWorkflowParameters: this._getAdditionalWorkflowParameters(contentId, messageType),
            iconCls: this.getInitialConfig("dialogIconCls"),
            icon: this.getInitialConfig("dialogIcon"),
            title: this.getInitialConfig("dialogTitle"),
            helpmessage1: this.getInitialConfig("dialogHelpMessage1"),
            helpmessage2: this.getInitialConfig("dialogHelpMessage2"),
            defaultContentTitle: this.getInitialConfig("defaultContentTitle"),
            initValues: initValues,
            forceValues: forceValues,
            forceMode: forceMode
		}

		if (metadataType == "content")
		{
    		Ametys.cms.uihelper.CreateContent.open(openParams, Ext.bind(this.act3, this, [contentId, messageType], true), this);
		}
		else 
		{
			throw new Error("The metadata type '" + metadataType + "' is unknown to add a content or sub-content in " + this.self.getName() + "#act");
		}
	},
    
    /**
     * Get the additional workflow parameters for content creation
     * @param {String} contentId The currently selected content identifier
     * @param {String} messageType The bus message type (such as 'content')
     * @return {Object} the additional workflow parameters
     */
    _getAdditionalWorkflowParameters: function(contentId, messageType)
    {
        return this.getInitialConfig("target-additionalWorkflowParameters");
    },
    
    /**
     * @private
     * Filters the result content types if content types are restricted in controller configuration
     * @param {Ametys.cms.content.ContentType[]} contentTypes The initial content types
     * @return {Ametys.cms.content.ContentType[]} the filtered content types.
     */
    _filterContentTypes: function (contentTypes)
    {
        if (this.getInitialConfig("source-metadata-content-types"))
        {
            var contentTypesIds = Ext.Array.map(contentTypes, function(contentType) {
	            return contentType.getId();
	        }, this);
        
            // Creates an array containing the content types ids we want the user to be allowed to create
	        var cfgSourceMetadataContentTypes = this.getInitialConfig("source-metadata-content-types").split(",");
	        
	        // Creates an array of Ametys.cms.content.ContentType whose ids are in the intersection of the two arrays
	        var filteredContentTypes = [];
	        Ext.Array.forEach(cfgSourceMetadataContentTypes, function(contentTypeId) {
	            var index = contentTypesIds.indexOf(contentTypeId);
	            if (index >= 0 )
	            {
	                filteredContentTypes.push(contentTypes[index]);
	            }
	            else
	            {
	                // #cfg-source-metadata-content-types contains an invalid id or an id of a content-type which do not extends the content type of #cfg-source-metadata-ref
	                // Just ignore it
	            }
	        }, this);
	        
	        
	        return filteredContentTypes;
        }
        else
        {
            // No filter to apply
            return contentTypes;
        }
    },
	
	/**
	 * @private
	 * The callback of #act2
	 * @param {String} contentId The identifier of the newly created content
	 * @param {String} parentContentId The identifier of the parent content
	 * @param {String} messageType The bus message type (such as 'content')
	 */
	act3: function(contentId, parentContentId, messageType)
	{
		var me = this,
            contentIdsToEdit = {};
        contentIdsToEdit[parentContentId] = null;
		
		Ametys.data.ServerComm.callMethod({
			role: "org.ametys.core.ui.RelationsManager",
			id: "org.ametys.cms.relations.setcontentattribute",
			methodName: "setContentAttribute",
			parameters: [
			    [contentId],
			    contentIdsToEdit,
			    [],
			    this._getSourceAttributeRef(),
			    [this.getInitialConfig("source-editWorkflowActionId")],
			    this._getAdditionalRelationsManagerParameters()
			],
			callback: {
				handler: function(response, args) {
					if (response == null)
					{
						Ametys.log.ErrorDialog.display({
							title: "{{i18n PLUGINS_CONTENTSTREE_ADDELEMENT_CREATEDNOTASSOCIATED_TITLE}}",
							text: "{{i18n PLUGINS_CONTENTSTREE_ADDELEMENT_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_CONTENTSTREE_ADDELEMENT_CREATEDNOTASSOCIATED_TEXT}}", 
                                details: detailedMsg,
                                defaultFocus: 0
                            });
                
                            Ametys.form.SaveHelper.SaveErrorDialog.showErrorDialog ("{{i18n PLUGINS_CONTENTSTREE_ADDELEMENT_CREATEDNOTASSOCIATED_TITLE}}", "", detailedMsg);
                            return;
                        }

						if (response['success'] == true)
						{
							Ext.create("Ametys.message.Message", {
								type: Ametys.message.Message.MODIFIED,
								
								targets: {
									id: messageType,
									parameters: { ids: [parentContentId]}
								},
								
								parameters: {
									major: false
								}
							});
						}
					}
					
					if (me.getInitialConfig("target-directEdition") == "true" && me.getInitialConfig("target-editWorkflowActionId"))
					{
						var editWorkflowActionId = me.getInitialConfig("target-editWorkflowActionId");
                        var viewName = me.getInitialConfig("target-view-name") || 'default-edition';
						Ametys.tool.ToolsManager.openTool('uitool-content', {id: contentId, mode: "edit", "edit-workflow-action": editWorkflowActionId, "view-name": viewName});
					}
					else if (me.getInitialConfig("target-openContent") != "false" )
					{
						Ametys.tool.ToolsManager.openTool('uitool-content', {id: contentId, mode: 'view'});
					}
				},
				arguments: null
			},
			waitMessage: true
		});
	},
	
	/**
	 * @protected
	 * Get the additional parameters to send to the relations manager
	 */
	_getAdditionalRelationsManagerParameters: function()
	{
		return {};
	},
	
	/**
	 * @private
	 * The callback of #act3
	 * @param {String} contentId The identifier of the newly created content
	 * @param {String} parentContentId The identifier of the parent content
	 * @param {String} messageType The bus message type (such as 'content')
	 */
	act4: function(contentId, parentContentId, messageType)
	{
		if (this.getInitialConfig("target-directEdition") == "true" && this.getInitialConfig("target-editWorkflowActionId"))
		{
			var editWorkflowActionId = this.getInitialConfig("target-editWorkflowActionId");
            var viewName = this.getInitialConfig("target-view-name") || 'default-edition';
			Ametys.tool.ToolsManager.openTool('uitool-content', {id: contentId, mode: "edit", "edit-workflow-action": editWorkflowActionId, "view-name": viewName});
		}
		else
		{
			Ametys.tool.ToolsManager.openTool('uitool-content', {id: contentId, mode: 'view'});
		}
	},
    
    /**
     * @protected
     * Get the source-metadata-ref configuration.
     * @return {String} Get the source metadata ref
     */
    _getSourceAttributeRef: function()
    {
        return this.getInitialConfig("source-metadata-ref");
    }
});