/*

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

/**
 * This tool displays the elements of a cart
 * @private
 */
Ext.define('Ametys.plugins.cart.tool.CartTool', {
	extend: "Ametys.tool.Tool",
	
	statics: {
		/**
		 * @property {Number} PAGE_SIZE
		 * @readonly
		 * @static
		 * The number of records to display by 'page'
		 */
		PAGE_SIZE: 10,
        
        renderURL: function(value, metaData, record)
        {
            return value ? `<a href="${value}">${value}</a>` : '';
        }
	},
	
	/**
	 * @property {Ext.grid.Panel} grid The grid panel displaying the carts
	 * @private
	 */	
	/**
	 * @property {String} _cartId The id of the cart
	 * @private
	 */
	/**
	 * @property {Ext.data.Store} store The store for cart's elements
	 * @private
	 */
	
	constructor: function(config)
	{
		this.callParent(arguments);
		
		Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onDeleted, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onCartModified, this);
	},
	
	setParams: function(params)
	{
		this.callParent(arguments);
		
		this._cartId = params['id'];
		this.refresh();
		
    	// Register the tool on the history tool
		var toolId = this.getFactory().getId();
	    var toolParams = this.getParams();

        Ametys.navhistory.HistoryDAO.addEntry({
			id: this.getId(),
			label: this.getTitle(),
			description: this.getDescription(),
			iconSmall: this.getSmallIcon(),
			iconMedium: this.getMediumIcon(),
			iconLarge: this.getLargeIcon(),
			type: Ametys.navhistory.HistoryDAO.TOOL_TYPE,
			action: Ext.bind(Ametys.tool.ToolsManager.openTool, Ametys.tool.ToolsManager, [toolId, toolParams], false)
        });
	},
	
	getMBSelectionInteraction: function() 
	{
		return Ametys.tool.Tool.MB_TYPE_ACTIVE;
	},
	
	/**
	 * Create the carts grid. Grouped by type.
	 */
	createPanel: function()
	{
		this.store = this.createStore();
		
		this.grid = Ext.create("Ext.grid.Panel", { 
			store: this.store,
			stateful: true,			
			stateId: this.self.getName() + "$grid",		
			scrollable: true,
			
			columns: [
			      {stateId: 'grid-column-title', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_TITLE}}", flex: 1, sortable: true, dataIndex: 'title', renderer: Ametys.grid.GridColumnHelper.renderTextWithIcon},
                  {stateId: 'grid-column-description', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_DESCRIPTION}}", flex: 1, sortable: true, hidden: true, dataIndex: 'description'},
                  {stateId: 'grid-column-creator', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_CREATOR}}", hidden: false, width: 140, sortable: true, dataIndex: 'creator', renderer: Ametys.grid.GridColumnHelper.renderUser}, 
                  {stateId: 'grid-column-creation', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_CREATION}}", hidden: false, width: 140, sortable: true, dataIndex: 'creation', renderer: Ametys.grid.GridColumnHelper.renderDateTime},
			      {stateId: 'grid-column-contributor', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_LASTCONTRIBUTOR}}", hidden: false, width: 140, sortable: true, dataIndex: 'lastContributor', renderer: Ametys.grid.GridColumnHelper.renderUser}, 
		          {stateId: 'grid-column-lastmodified', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_LASTMODIFICATION}}", hidden: false, width: 140, sortable: true, dataIndex: 'lastModification', renderer: Ametys.grid.GridColumnHelper.renderDateTime},
		          {stateId: 'grid-column-workflow', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_WORKFLOWSTEP}}", hidden: false, width: 120, sortable: true, dataIndex: 'workflowStep', renderer: Ametys.plugins.cms.search.SearchGridHelper.renderWorkflowStep},
                  {stateId: 'grid-column-queryType', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_QUERY_TYPE}}", width: 120, sortable: true, dataIndex: 'queryType', renderer: Ametys.plugins.queriesdirectory.tree.QueriesTree.renderType},
                  {stateId: 'grid-column-documentation', header: "{{i18n PLUGINS_CART_UITOOL_CART_COLUMN_DOCUMENTATION}}", width: 120, sortable: true, dataIndex: 'documentation', renderer: Ametys.plugins.cart.tool.CartTool.renderURL},
		    ],
		    
		    selModel : {
		    	mode: 'MULTI'
		    },
		    
		    features: [{
		    	ftype:'grouping', 
		    	groupHeaderTpl: '{name} ({rows.length})',
		    	enableGroupingMenu: false
		    }],
		    
		    viewConfig: {
		    	plugins: [{
		            ptype: 'ametysgridviewdragdrop',
		            dragTextField: 'title',
		            setAmetysDragInfos: Ext.bind(this.getDragInfo, this),
		            setAmetysDropZoneInfos: Ext.bind(this.getDropInfo, this)
		        }]
		    },
		    
		    
		    dockedItems: [
		        {
		        	xtype: 'toolbar',
		        	dock: 'bottom',
		        	items: ['->', { 
		        		xtype: 'tbtext', 
		        		text: '',
		        		tpl: Ext.create('Ext.XTemplate', 
		        				"<tpl if='nb == 0'>",
		        				"{{i18n PLUGINS_CART_UITOOL_CART_TPL_NO_ELEMENT}}",
		        				"</tpl>", 
		        				"<tpl if='nb == 1'>",
		        				"{{i18n PLUGINS_CART_UITOOL_CART_TPL_ONE_ELEMENT}}",
		        				"</tpl>", 
		        				"<tpl if='nb != 1 && nb != 0'>",
		        				"{{i18n PLUGINS_CART_UITOOL_CART_TPL_NB_ELEMENTS_1}} {nb} {{i18n PLUGINS_CART_UITOOL_CART_TPL_NB_ELEMENTS_2}}",
		        				"</tpl>" 
		        				)
		        	}]
		        }
		    ],
		    
		    listeners: {		   	 	
		   	 	'selectionchange': Ext.bind(this.sendCurrentSelection, this)
		    }
		});
		
		this.grid.on('itemdblclick', Ext.bind(this._openCartElement, this));
		
		return this.grid;
	},
	
	/**
	 * @private
	 * This event is thrown by the getDragData to add the 'source' of the drag.
	 * @param {Object} item The default drag data that will be transmitted. You have to add a 'source' item in it: 
	 * @param {Object} item.source The source (in the relation way) of the drag operation. A Ametys.relation.RelationPoint config. 
	 */
	getDragInfo: function(item)
	{
		var targets = this._getSelectedTargets();
		
		if (targets && targets.length > 0)
		{
			item.source = {
					relationTypes: [Ametys.relation.Relation.REFERENCE], 
					targets: targets
			};
		}
	},
	
	/**
	 * @private
	 * This event is thrown before the beforeDrop event and create the target of the drop operation relation.
	 * @param {Ext.data.Model[]} targetRecords The target records of the drop operation.
	 * @param {Object} item The default drag data that will be transmitted. You have to add a 'target' item in it: 
	 * @param {Object} item.target The target (in the relation way) of the drop operation. A Ametys.relation.RelationPoint config. 
	 */	
	getDropInfo: function(targetRecords, item)
	{
		var targets = this._getTargets(targetRecords);

		if (targets.length > 0)
		{
			item.target = {
				relationTypes: [Ametys.relation.Relation.REFERENCE], 
				targets: targets
			};
		}
		else
		{
			item.target = {
					relationTypes: [Ametys.relation.Relation.REFERENCE], 
					targets: {
		  	      		id: 'cart',
		  	      		parameters: {
		  	      			id: this._cartId
		  	      		}
					}
				};
		}
	},
	
	/**
	 * Returns the CartElement store
	 * @return {Ext.data.Store} The cart element store
	 */
	createStore: function()
	{
		return Ext.create('Ext.data.Store', {
			model: 'Ametys.plugins.cart.tool.CartTool.CartElementEntry',
			sorters: [{property: 'title', direction:'ASC'}],
			proxy: {
				type: 'ametys',
				plugin: 'cart',
				url: 'cart/elements.json',
				reader: {
					type: 'json',
					rootProperty: 'cartElements',
					totalProperty: 'total'
				}
			},
			autoLoad: false,
			pageSize: this.self.PAGE_SIZE,
			
			groupField: 'group',
			listeners: {
				 'beforeload': {fn: this._onBeforeLoad, scope: this},
				 'load': {fn: this._onLoad, scope: this}
			}
				
		});
	},
	
	/**
	 * Function before loading the store.
	 * @param {Ext.data.Store} store The store
	 * @param {Ext.data.operation.Operation} operation The object that will be passed to the Proxy to load the store
	 * @private
	 */
	_onBeforeLoad: function (store, operation)
	{
		operation.setParams(operation.getParams() || {});
		//Adding the cartId as a HTTP parameter for the store's proxy
		operation.setParams({
			cartId: this._cartId
		});
	},
	
	/**
	 * Function called after loading the store.
	 * @param {Ext.data.Store} store The store
	 * @param {Ext.data.Model[]} records The loaded records
     * @param {boolean} success Is the load a success
	 * @private
	 */
	_onLoad: function (store, records, success)
	{
        if (success)
        {
			var tbtext = this.grid.getDockedItems('toolbar[dock="bottom"]')[0].down('tbtext');
			tbtext.update({nb: records.length});
        }
	},
	
	/**
	 * @private
	 * Convert records to targets 
	 * @param {Ext.data.Model[]} records The record to convert 
	 * @return {Object[]} An array of Ametys.message.MessageTarget configurations.
	 */
	_getTargets: function(records)
	{
		var elmtTargets = [];
		
   		Ext.each (records, function (record) {
   			var type = record.get('type');
   			
   			if (type === 'content')
   			{
	   			elmtTargets.push({
	   				id: type,
	   				parameters: {
	   					ids: [record.get('elmtId')]
	   				}
	   			});
   			}
   			else if (type === 'resource')
   			{
	   			elmtTargets.push({
	   				id: type,
	   				parameters: {
	   					ids: [record.get('elmtId')]
	   				}
	   			});
   			}
   		});
   		
   		return elmtTargets;
	},
	
	/**
	 * @private
	 * Get the current selected elements as message target configuration
	 * @return {Object[]} An array of Ametys.message.MessageTarget configurations.
	 */
	_getSelectedTargets: function()
	{
		return this._getTargets(this.grid.getSelectionModel().getSelection());
	},
	
	sendCurrentSelection: function()
	{
		var subtargets = this._getSubtargetsByType();
		
   		/*Ext.each (this.grid.getSelectionModel().getSelection(), function (record) {
   			elmtTargets.push({
   				type: 'cartElement',
   				parameters: {
   					id: record.get('elmtId'),
   					cartElementType: record.get('type')
   				}
   			});
   		});*/
   		
   		Ext.create("Ametys.message.Message", {
  	        type: Ametys.message.Message.SELECTION_CHANGED,
  	        targets: {
  	          id: Ametys.message.MessageTarget.CART,  	      	  
  	      	  parameters: {
  	      		  id: this._cartId
  	      	  },
  	      	  subtargets: subtargets
   			}
    	});   		
	},

	/**
	 * @private
	 * Get the subtargets configuration to create a message bus, based upon current grid selection
	 * @return {Object} The configuration to create a subtarget bus message. With 'type' and 'parameters' properties.
	 */
	_getSubtargetsByType: function ()
	{
		var types = {};
		
		Ext.each (this.grid.getSelectionModel().getSelection(), function (record) {
			var type = record.get('type');
			if (!types[type])
			{
				types[type] = [];
			}
			
			types[type].push(record.get('elmtId'));
   		});
		
		var subtargets = [];
		for (var type in types)
		{
			if (type == 'cartQuery' || type == 'cartQueryFromDirectory')
			{
				var queries = types[type];
				for (var i=0; i < queries.length; i++)
				{
					subtargets.push({
		   				id: type,
		   				parameters: {
		   					id: queries[i]
		   				}
		   			});
				}
			}
			else
			{
				subtargets.push({
	   				id: type,
	   				parameters: {
	   					ids: types[type]
	   				}
	   			});
			}
			
		}
		return subtargets;
	},
	
	/**
	 * Reload the store on refresh
	 */
	refresh: function()
	{
		this.callParent(arguments);
		
		this.grid.store.load({callback: Ext.bind(this._updateInfos, this)});
	},
	
	/**
	 * Update tool information
	 * @private
	 */
	_updateInfos: function (records, operation, success)
	{
		var result = Ext.JSON.decode(Ext.dom.Query.selectValue("", operation.getResponse()));
		
        if (result['unknown-cart'])
        {
            var details = '';
            var params = this.getParams();
            for (var name in params)
            {
                details += name + " : " + params[name] + '\n';
            }
            
            Ametys.log.ErrorDialog.display({
                title: "{{i18n PLUGINS_CART_UITOOL_CART_NOT_FOUND}}",
                text: "{{i18n PLUGINS_CART_UITOOL_CART_NOT_FOUND_ERROR}}",
                details: details,
                category: this.self.getName()
            });
             
            this.close();
            return;
        }
        
		this.setTitle(result.label);
		this.setDescription(result.description);
		
		this.showUpToDate();
		
		// Save in navigation history
   		var toolId = this.getFactory().getId();
		var toolParams = this.getParams();
		
		Ametys.navhistory.HistoryDAO.addEntry({
			id: this.getId(), 
			objectId: this._cartId,
			label: this.getTitle(),
			description: this.getDescription(), 
			iconSmall: this.getSmallIcon(),
   			iconMedium: this.getMediumIcon(),
   			iconLarge: this.getLargeIcon(),
   			type: Ametys.navhistory.HistoryDAO.TOOL_TYPE,
			action: function () {Ametys.tool.ToolsManager.openTool(toolId, toolParams)}
		});
	},
	
	/**
	 * Manage CartElement doubleclick
	 * @param {Ext.view.View} view The view
	 * @param {Ext.data.Model} record The record that belongs to the item
	 * @param {HTMLElement} item The item's element
	 * @param {Number} index The item's index 
	 */	
	_openCartElement: function(view, record, item, index)
	{
		var type = record.get('type');
		
		if (type === 'resource')
		{
			// Download resource file
			Ametys.explorer.resources.actions.File.download(record.get('elmtId'));
		}
		else if (type === 'content')
		{
			// Open content tool
			Ametys.tool.ToolsManager.openTool('uitool-content', {'id': record.get('elmtId')});
		}	
		else if (type === 'cartQuery' || type === 'cartQueryFromDirectory')
		{
			// Open search tool
			var query = Ext.JSON.decode(record.get('queryContent'));
			
			var toolId = query.toolId;
			var toolParams = query.toolParams || {};
			
            toolParams.solrSearchToolId = record.get('elmtId');
            toolParams.scriptToolId = record.get('elmtId');
            if (type === 'cartQueryFromDirectory')
            {
                toolParams.queryId = record.get('elmtId');
            }
            
			Ametys.tool.ToolsManager.openTool(toolId, toolParams);
		}
	},

	/**
	 * Listener when cart has been modified.
	 * Will set the tool in "out of date" mode.
	 * @param {Ametys.message.Message} message The modified message.
	 * @private
	 */
	_onCartModified: function(message)
	{
		var me = this;
		var targets = message.getTargets(function (target) {return 'cart' == target.getId() && target.getParameters().id === me._cartId;});
		
		if (targets && targets.length > 0)
		{				
			this.showOutOfDate();   
			return;
		}
		
		var elementTargets = message.getTargets(function (target) {
            return me._isSupportedTarget(target);
        });
        
		if (elementTargets.length > 0)
		{
			for (var i=0; i < elementTargets.length; i++)
			{
				var elementId = elementTargets[i].getParameters().id;
				if (this.store.findExact('elmtId', elementId) != -1)
				{
					this.showOutOfDate();         
					return;
				}
			}
		}
	},
	
	/**
	 * Listener when cart or cart'elements has been deleted.
	 * Will close the tool or remove the records if present
	 * @param {Ametys.message.Message} message The deletion message.
	 * @private
	 */
	_onDeleted: function(message)
	{
		var me = this;
		var targets = message.getTargets(function (target) {return 'cart' == target.getId() && target.getParameters().id === me._cartId;});
		
		if (targets && targets.length > 0)
		{				
			this.close();
			return;
		}
		
		targets = message.getTargets(function (target) {
            return ('cartElement' == target.getId() && target.getParameters().cartId === me._cartId) || me._isSupportedTarget(target);
        });
		
		if (targets && targets.length > 0)
		{		
			var records = [];
			for (var i=0; i < targets.length; i++)
			{
				var record = this.store.findExact('elmtId', targets[i].getParameters().id);
				if (record != null)
				{
					records.push(record);
				}
			}
            
            if (records.length > 0)
            {
    			this.store.remove(records);
    			
    			var tbtext = this.grid.getDockedItems('toolbar[dock="bottom"]')[0].down('tbtext');
			    tbtext.update({nb: this.store.getCount()});
            }
		}
	},
    
    /**
     * True if the target is supported
     * @param {Object} target The target.
     * @private
     */
    _isSupportedTarget(target)
    {
        return 'content' == target.getId()
            || 'resource' == target.getId()
            || 'query' == target.getId();
    }
	
});