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

/**
 * This tool displays the consistency report for a content
 * @private
 */
Ext.define('Ametys.plugins.cms.content.tool.ConsistencyTool', {
	extend: "Ametys.tool.SelectionTool",
	
	statics: {
		/**
		 * @property
		 * @private
		 * @static {Object} The tips
		 */
		_tips: {
				'unknown': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_UNKNOWN}}",
				'success': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_SUCCESS}}",
				'unauthorized': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_UNAUTHORIZED}}",
				'not-found': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_NOT_FOUND}}",
				'server-error': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_SERVER_ERROR}}",
				'detail-message': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_MESSAGE_DETAILS}}"
		}
	},
	
	/**
	 * @property {Ext.Template} pathTpl The template used to display the metadata path for each group of consistencies. Defaults to '<h2>{0}</h2>'
	 */
	pathTpl: Ext.create('Ext.XTemplate', '<p class="metadata-path"><strong>{0}</strong></p>'),
	
	/**
	 * @property {Ext.Template} linkTpl The template used for displaying link. Defaults to '<p><img title="{type}" src="{icon}"/>{link}</p>'
	 */
	linkTpl: Ext.create('Ext.XTemplate', '<p><span class="{iconCls}" title="{type}<tpl if="message">.\n{message}</tpl>"></span>{link}</p>'),
	
	/**
     * @private
     * @property {Boolean} _showAllLinks true to show only broken links
     */
    _showAllLinks: false,
	
     /**
     * @cfg {String} showAllLinksButtonIconCls The separated CSS classes to apply to button to show all links
     */
    showAllLinksButtonIconCls: 'ametysicon-code-html-link',
    
    /**
     * @cfg {String} showAllLinksButtonTooltip Tooltip of the button to show all links
     */
    showAllLinksButtonTooltip: "{{i18n UITOOL_CONSITENCY_SHOW_ALL_LINKS}}",
    
    /**
     * @cfg {String} showOnlyBrokenLinksButtonIconCls The separated CSS classes to apply to button to hide sucessful links
     */
    showOnlyBrokenLinksButtonIconCls: 'ametysicon-code-html-link-broken',
    /**
     * @cfg {String} showOnlyBrokenLinksButtonTooltip Tooltip of the button to hide empty sucessful links
     */
    showOnlyBrokenLinksButtonTooltip: "{{i18n UITOOL_CONSITENCY_SHOW_ONLY_BROKEN_LINKS}}",
	
	constructor: function(config)
	{
		this.callParent(arguments);
		
		Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGED, this._onEdited, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onDeleted, this);
	},
	
	createPanel: function()
	{
        return Ext.create('Ext.Panel', {
            border: false,
            scrollable: false,
            cls: 'consistency-tool',
            layout: 'card',
            activeItem: 0,
            items: [{
                        xtype: 'component',
                        cls: 'a-panel-text-empty',
                        html: '',
                        hidden: true
                    },
                    {
                        flex: 1,
                        border: false,
                        scrollable: true,
                        xtype: 'panel',
                        itemId: 'content-links',
                        html: '',
                        bodyStyle: {
                            padding: '5px'
                        },
                        dockedItems:  this._getTopPanel()
                    }
            ]
        });
	},
	
	/**
     * @protected
     * Get the top panel for hint and actions
     * @return {Ext.Panel} the top panel
     */
    _getTopPanel: function ()
    {
        return Ext.create({
            dock: 'top',
            xtype: 'container',
            layout: {
                type: 'hbox',
                align: 'middle'
            },
            cls: 'top',
            items: [
                {
                    // hint
                    xtype: 'component',
                    itemId: 'content-info',
                    cls: 'hint',
                    html: '',
                    flex: 1
                },
                {
                    // show only broken links
                    xtype: 'button',
                    iconCls: this.showAllLinksButtonIconCls,
                    tooltip: this.showAllLinksButtonTooltip,
                    scope: this,
                    enableToggle: true,
                    toggleHandler: this.showAllLinks,
                    cls: 'a-btn-light'
                }
            ]
        });
    },
    
    showAllLinks: function(btn, state)
    {
        this._showAllLinks = state;
        
        if (this._showAllLinks)
        {
            btn.setIconCls(this.showOnlyBrokenLinksButtonIconCls);
            btn.setTooltip(this.showOnlyBrokenLinksButtonTooltip)
        }
        else
        {
            btn.setIconCls(this.showAllLinksButtonIconCls);
            btn.setTooltip(this.showAllLinksButtonTooltip);
        }

        this.refresh();
    },
    
    setParams: function (params)
    {
        this.callParent(arguments);
        this.refresh();
    },
	
	refresh: function (manual)
	{
		this.showRefreshing();
        
		var contentTarget = this.getCurrentSelectionTargets().length > 0 ? this.getCurrentSelectionTargets()[0] : null;
		if (contentTarget != null)
		{
			this._contentId = contentTarget.getParameters().id;
			
            var params = {contentsId: [this._contentId]};
			
			Ametys.data.ServerComm.send({
				plugin: 'cms',
				url: 'consistency/check.xml',
				parameters: params, 
				priority: Ametys.data.ServerComm.PRIORITY_LONG_REQUEST, 
				callback: {
					handler: this._refreshCallback,
					scope: this,
					arguments: [this._contentId]
				}
			});
		}
		else
		{
            // Nothing to do.
            // Do not use the noSelectionMatch method to avoid erasing the current message
            this.showRefreshed();
		}
	},
	
	/**
	 * @private
	 * This function is called after check links is processed. Update the tool.
	 */
	_refreshCallback : function (response, args)
	{
		var contentId = args[0];
		
		var currentTarget = this.getCurrentSelectionTargets().length > 0 ? this.getCurrentSelectionTargets()[0] : null;
		if (currentTarget == null || currentTarget.getParameters().id != contentId)
		{
			// too late => discard (another content has been selected)
			return;
		}
		
		if (Ametys.data.ServerComm.handleBadResponse("{{i18n UITOOL_CONSISTENCY_ERROR}} '" + contentId + "'", response, 'Ametys.plugins.cms.content.tool.ConsistencyTool'))
        {
            this.showRefreshed();
            return;
        }
		
		var html = '';
		
		// If we only want to see the broken links, then set the "sucessType" to an empty string in order to not get the valid links
        var successTypeOrEmpty = "";
		if (this._showAllLinks)
        {
            // If we want all the links, set the sucessType to "sucess" in order to retrieve the valid links
            successTypeOrEmpty = "> success";
        }
		
		var contents = Ext.dom.Query.select("contents/content", response);
		for (var i = 0; i < contents.length; i++)
		{
			var content = contents[i];
			
			if (Ext.dom.Query.selectDirectElements("no-right", content).length != 0)
			{
                var panel = this.getContentPanel().items.get(0);
                panel.update(this.getInitialConfig("selection-description-noright"));
                this.getContentPanel().getLayout().setActiveItem(0);
            }
			else
			{
                this.getContentPanel().down("#content-info").update((this._showAllLinks ? "{{i18n UITOOL_CONSISTENCY_HINT_TEXT}}" : "{{i18n UITOOL_CONSISTENCY_HINT_TEXT2}}") + '<b>' + Ext.String.escapeHtml(content.getAttribute("title")) + '</b>');
                
    			// Preparing metadata definition labels
    			var metadataDef2Labels = {};
    			var metadataDefinitions = Ext.dom.Query.select("> metadata-definition", content),
    				metadataDefinition;
    			for (var j = 0; j < metadataDefinitions.length; j++)
    			{
    				metadataDefinition = metadataDefinitions[j];
    				metadataDef2Labels[Ext.dom.Query.selectValue('@path', metadataDefinition)] = {
    					label: Ext.dom.Query.selectValue('', metadataDefinition),
    					isRepeater: Ext.dom.Query.selectValue('@is-repeater', metadataDefinition) == 'true'
    				};
    			}
    			
                var consistenciesArray = Ext.Array.merge(Ext.dom.Query.select("> unknown", content), 
                                                    Ext.dom.Query.select("> not-found", content), 
                                                    Ext.dom.Query.select("> unauthorized", content),
                                                    Ext.dom.Query.select("> server-error", content));
                if (successTypeOrEmpty != "")
                {
                    consistenciesArray = Ext.Array.merge(Ext.dom.Query.select(successTypeOrEmpty, content),
                                                        consistenciesArray)
                }
    			
    			var consistencies = consistenciesArray, consistency, path, consistenciesByPath = {};
    			for (var j = 0; j < consistencies.length; j++)
    			{
    				consistency = consistencies[j];
    				
    				path = Ext.dom.Query.selectValue('@path', consistency);
    				consistenciesByPath[path] = consistenciesByPath[path] || [];
    				consistenciesByPath[path].push(consistency);
    			}
    			
    			// Loop on consistency grouped by path;
    			var type, parts, currentPath, fullLabel, labelInfo, label;
    			Ext.Object.each(consistenciesByPath, function(path, consistencies) {
    				
    				// Evaluate metadata path label.
    				parts = path.split('/'), currentPath = '', fullLabel = [];
    				Ext.Array.forEach(parts, function(part) {
                        currentPath += (currentPath ? '/' : '') + part;
                        labelInfo = metadataDef2Labels[currentPath] || {};
                        fullLabel.push(labelInfo.label || '');
    				});
    				
    				html += this.pathTpl.applyTemplate([fullLabel.join(' > ')]);
    				
    				Ext.Array.forEach(consistencies, function(consistency) {
    					type = consistency.nodeName;
    					
    					var values = {
    						link: Ext.dom.Query.selectValue("> label", consistency),
    						type: Ametys.plugins.cms.content.tool.ConsistencyTool._tips[type],
    						iconCls: this._getIconCls(type)
    					};
    					
    					if (type == "server-error")
    					{
                            var message = Ext.dom.Query.selectValue("> message", consistency);
                            if (message)
                            {
                                values['message'] = Ametys.plugins.cms.content.tool.ConsistencyTool._tips['detail-message'] + message;
                            }
                        }
    					
    					html += this.linkTpl.applyTemplate(values);
    				}, this);
    			}, this);
                
                if (html == '')
		        {
		            html = this._showAllLinks ? "{{i18n UITOOL_CONSISTENCY_NOLINKS}}" : "{{i18n UITOOL_CONSISTENCY_NOBROKENLINKS}}";
		        }
                
                this.getContentPanel().down("#content-links").update(html);
                this.getContentPanel().getLayout().setActiveItem(1);
            }
		}
		
		this.showRefreshed();
	},
    
    /**
     * @private
     * Get the separated CSS classes to apply to the link 
     * @param {String} type The type of the link
     * @return {String} The CSS classes
     */
    _getIconCls: function (type)
    {
        switch (type)
        {
            case "success":
                return "ametysicon-check34 link-glyph link-ok";
            case "unknown":
                return "ametysicon-question13 link-glyph link-warn";  
            case "server-error":
                return "ametysicon-letter-x5 link-glyph link-error";
            case "not-found":
                return "ametysicon-alert9 link-glyph link-error"; 
            case "unauthorized":
                return "ametysicon-forbidden1 link-glyph link-error";
            default:
                return "";
        }
    },
	
	setNoSelectionMatchState: function (message)
	{
        this.callParent(arguments);
        
        var panel = this.getContentPanel().items.get(0);
        panel.update(message);
        this.getContentPanel().getLayout().setActiveItem(0);
        
        this._contentId = null;
	},
	
	/**
	 * Listener on {@link Ametys.message.Message#WORKFLOW_CHANGED} message. If the current
	 * content is concerned, the tool will be out-of-date.
	 * 
	 * @param {Ametys.message.Message} message The workflow changed message.
	 * @protected
	 */
	_onEdited: function (message)
	{
		if (this.getTargetsInCurrentSelectionTargets(message).length > 0)
		{
			this.showOutOfDate();
		}
	},
	
	/**
	 * Listener on {@link Ametys.message.Message#DELETED} message. If the current content is concerned, the tool will be set in no selection mode.
	 * @param {Ametys.message.Message}  message The deleted message.
	 * @protected
	 */
	_onDeleted: function (message)
	{
		if (this.getTargetsInCurrentSelectionTargets(message).length > 0)
		{
			this.setNoSelectionMatchState("{{i18n UITOOL_CONSISTENCY_SELECT_CONTENT}}");
		}
	}
	
});