/*
 *  Copyright 2015 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 is a relation handler between:
 * * source : tag
 * * destination : page or content
 * 
 * E.g. when you drag a tag to a content or a page
 * @private
 */
Ext.define('Ametys.plugins.web.tag.relations.SetTagsRelationHandler', {
	extend: 'Ametys.relation.RelationHandler',
	
	/** 
	 * @protected
	 * @property {RegExp} sourceTargetType The message target type (of type tag) of the source to handle
	 */
	sourceTargetType: /^tag$/,
	
	/**
	 * @protected
	 * @property {RegExp} destTargetType The message target type (of type content or page) of the target to handle
	 */
	destTargetType: /^(page|content)$/,

	/**
	 * @private
	 * Revert the #targetType test
	 * @param {Object/Ametys.message.MessageTarget} target The target to test
	 * @return {Boolean} True if the target type does not match #targetType
	 */
	_nonMatchingSource: function(target)
	{
		return !this.sourceTargetType.test(target.isMessageTarget ? target.getId() : target.id)
	},
	
	/**
	 * @private
	 * Revert the #targetType test
	 * @param {Object/Ametys.message.MessageTarget} target The target to test
	 * @return {Boolean} True if the target type does not match #targetType
	 */
	_nonMatchingDest: function(target)
	{
		return !this.destTargetType.test(target.isMessageTarget ? target.getId() : target.id)
	},

	supportedRelations: function(source, target)
	{
		var sourceContentTargets = Ametys.message.MessageTargetHelper.findTargets(source.targets, this.sourceTargetType, 1);
		if (sourceContentTargets.length != 1 || Ametys.message.MessageTargetHelper.findTargets(source.targets, Ext.bind(this._nonMatchingSource, this), 1).length > 0)
		{
			return [];
		}

		var destContentTargets = Ametys.message.MessageTargetHelper.findTargets(target.targets, this.destTargetType, 1);
		if (destContentTargets.length != 1 || Ametys.message.MessageTargetHelper.findTargets(target.targets, Ext.bind(this._nonMatchingDest, this), 1).length > 0)
		{
			return [];
		}

		var relations = [ 
		    Ext.create('Ametys.relation.Relation', {
    			type: Ametys.relation.Relation.REFERENCE,
    			label: "{{i18n PLUGINS_WEB_RELATIONS_SETTAG_LABEL}}",
    			description: "{{i18n PLUGINS_WEB_RELATIONS_SETTAG_DESCRIPTION}}",
    			smallIcon: null,
    			mediumIcon: null,
    			largeIcon: null
    		})
		];
			
		return relations;
	},

	/**
	 * @protected
	 * Do the #link work but based only on targets array
	 * The method is called to link source to target using the given relation. 
	 * This operation can be asynchronous and will call callback at the end.
	 * In most cases this implementation will send a Ametys.message.Message to inform the UI that the operation was done.
	 * @param {Ametys.message.MessageTarget[]} sourceTargets The source point of the link operation. Targets are assumed to be ready.
	 * @param {Ametys.message.MessageTarget} target The end point of the link operation. Targets are assumed to be ready.
	 * @param {Function} callback The callback to call when operation has ended. 
	 * @param {Boolean} callback.success True if the operation was successful
	 */
	_link: function(sourceTargets, target, callback)
	{
		var tagNames = [];
		Ext.Array.forEach(Ametys.message.MessageTargetHelper.findTargets(sourceTargets, this.sourceTargetType, 1), function(target) {
			tagNames.push(target.getParameters().name);
		});

		var pageTargets = (target.getId() == Ametys.message.MessageTarget.PAGE ? [ target.getParameters().id ] : []);
		var contentTargets = (target.getId() == Ametys.message.MessageTarget.CONTENT ? [ target.getParameters().id ] : []);
		if (pageTargets.length > 0)
		{
			Ametys.data.ServerComm.callMethod({
	            role: "org.ametys.web.repository.page.PageDAO", 
	            methodName: 'tag', 
	            parameters: [ pageTargets, tagNames, 'INSERT', Ametys.getAppParameters() ],
	            waitMessage: true,
	            callback: {
	                handler: this._linkCb,
	                scope: this,
	                arguments: [ callback, "page" ]
	            }
        	});
		}
		else if (contentTargets.length > 0)
		{
			Ametys.data.ServerComm.callMethod({
	            role: "org.ametys.cms.repository.ContentDAO", 
	            methodName: 'tag', 
	            parameters: [ contentTargets, tagNames, 'INSERT', Ametys.getAppParameters() ],
	            waitMessage: true,
	            callback: {
	                handler: this._linkCb,
	                scope: this,
	                arguments: [ callback, "content" ]
	            }
	        });
		}
	},
	
	link: function(source, target, callback, relationType)
	{
		this._link(source.getTargets(), target.getTarget(), callback);
	},
	
	/**
	 * @private
	 * Callback of the link operation. That will call the initial callback.
	 * @param {Object} response The response from the server
     * @param {Object[]} args Transmitted arguments
	 * @param {Function} args.0 The callback to call when operation has ended. 
	 * @param {boolean} args.0.sucess True if the operation was successful
     * @param {"page"/"content"} args.1 the linking type
	 */
	_linkCb: function(response, args)
	{
		if (args[1] == "page")
		{
	        var pages = response["allright-pages"];

	        if (pages != null && pages.length > 0)
	        {
	            this._sendMessageModified(Ametys.message.MessageTarget.PAGE, pages);
	        }
		}
		else if (args[1] == "content")
		{
	        var contents = response["allright-contents"];

	        if (contents != null && contents.length > 0)
	        {
	            this._sendMessageModified(Ametys.message.MessageTarget.CONTENT, contents);
	        }
		}

        var noRightsPages = response["noright-pages"] || [];
        var noRightsContents = response["noright-contents"] || [];
        var invalidTags = response["invalid-tags"] || [];
        
		if (noRightsPages.length > 0 || noRightsContents.length > 0 || invalidTags.length > 0)
		{
            var msg = "";
            if (noRightsPages.length > 0)
            {
                msg += "{{i18n PLUGINS_WEB_RELATIONS_SETTAG_PAGE_NO_RIGHT_ERROR}}";
                msg += "<ul>";
                for (var page of noRightsPages)
                {
                    msg += "<li>" + page.title + "</li>";
                }
                msg += "</ul>";
            }
            
            if (noRightsContents.length > 0)
            {
                msg += "{{i18n PLUGINS_WEB_RELATIONS_SETTAG_CONTENT_NO_RIGHT_ERROR}}";
                msg += "<ul>";
                for (var content of noRightsContents)
                {
                    msg += "<li>" + content.title + "</li>";
                }
                msg += "</ul>";
            }
            
            if (invalidTags.length > 0)
            {
                msg += "{{i18n PLUGINS_WEB_RELATIONS_SETTAG_INVALID_TAGS_ERROR}}<br/>";
                msg += invalidTags.join(', ');
            }
            
            Ametys.Msg.show({
            	title: "{{i18n PLUGINS_WEB_RELATIONS_SETTAG_INVALID_TAGS_TITLE}}",
                msg: msg,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
		}

        if (Ext.isFunction(args[0]))
        {
			args[0](response["invalid-tags"].length > 0);
		}
    },

    /**
     * @private
     * Send the target modified message
     * @param  {String} messageTargetType The message target type
     * @param  {Ametys.message.MessageTarget} messageTargets The message targets
     */
    _sendMessageModified: function(messageTargetType, messageTargets)
    {
        var i;
        var ids = [];

        for (i = 0; i < messageTargets.length; i++) 
        {
            ids.push(messageTargets[i].id);
        }

        if (ids.length > 0)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.MODIFIED,
                targets:  {
                    id: messageTargetType,
                    parameters: {ids: ids}
                }
            });
        }
    },
});