/*
 *  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 tool displays the dashboard.
 * Composed with a grid and a tabpanel.
 * @private
 */
 Ext.define('Ametys.plugins.odf.dashboard.DashboardTool', {
 	extend: 'Ametys.tool.Tool',
 	
 	/**
 	 * @private
 	 * @property {Object} _grids All the grids of this tool indexed by their id.
 	 */
 	
 	/**
 	 * @private
 	 * @property {Ext.panel.Panel} _mainPanel The main panel of the tool.
 	 */
 	
 	/**
 	 * @private
 	 * @property {Ext.data.Model[]} _selection The current selection.
 	 */
 	
 	/**
	 * @cfg {String} modelClass (required) The model classname for the store.
	 */
	/**
	 * @property {String} _model See {@link #cfg-modelClass}
	 * @private
	 */
 	
 	/**
	 * @cfg {String} proxyUrl (required) The URL of the proxy for the stores of the grids.
	 */
	/**
	 * @property {String} _proxyUrl See {@link #cfg-proxyUrl}
	 * @private
	 */
 	
 	/**
	 * @cfg {String} tasksUrl (required) The URL of the tasks.
	 */
	/**
	 * @property {String} _tasksUrl See {@link #cfg-tasksUrl}
	 * @private
	 */
 	
 	constructor: function(config)
 	{
 		this.callParent(arguments);
 		
 		this._model = this.getInitialConfig('modelClass');
 		this._proxyUrl = this.getInitialConfig('proxyUrl');
 		this._tasksUrl = this.getInitialConfig('tasksUrl');
 		
        Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGED, this._refreshIfNeeded, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._refreshIfNeeded, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._refreshIfNeeded, this);
 	},
 	
 	createPanel: function()
 	{ 		
 		this._mainPanel = Ext.create('Ext.panel.Panel', {
 			layout: {
                type: 'vbox',
                align: 'stretch'
            },
            border: false,
            
 			items: [
	 			{
	 				xtype: 'panel',
                    margin: '0 0 8 0',
	 				itemId: 'recent-drafts-panel',
                    border: false,
	 				ui: 'light',
	                title: '',
                    layout: 'fit',
	                minHeight: 100,
                    maxHeight: 250,
                    stateful: true,
                    stateId: this.self.getName() + "$recent-drafs",
	                items: [{
	                	xtype: 'grid',
	                	itemId: 'recent-drafts-grid',
				        scrollable: true,
                        deferRowRender: false,
				        
				        selModel: {
				        	mode: 'MULTI'
				        }
	                }]
	 			},
                {
                    split: true,
                    margin: '8 0 0 0',
                    flex: 1,
                    cls: 'ametys-form-tab-item',
                    xtype: 'tabpanel',
                    itemId: 'tabs-panel',
                    activeTab: 0,
                    deferredRender: false,
                    border: false,
                    items: [] // will be set on refresh
                }
 			]
 		});
 		
 		return this._mainPanel;
 	},
 	
	getMBSelectionInteraction: function()
	{
		return Ametys.tool.Tool.MB_TYPE_ACTIVE;
	},
	
	sendCurrentSelection: function()
	{
		var records = this._selection;
		
		var targets = [];
		if (records && records.length > 0)
		{
			targets.push({
				id: Ametys.message.MessageTarget.CONTENT,
				parameters: {
					ids: records.map(function(record){
						return record.getId();
					})
				}
			});
		}
		else
		{
			targets = [];
		}
		
		// Send the message on the bus
		Ext.create('Ametys.message.Message', {
			type: Ametys.message.Message.SELECTION_CHANGED,
			targets: targets
		});
	},
	
	/**
	 * Listener for change of selection in any grid.
	 * @param {String} selectedTaskId The id of the grid where the selection change happened.
	 * @param {Ext.data.Model} model The model.
	 * @param {Ext.data.Model[]} selected The selected records.
	 * @private
	 */
	_onSelectionChange: function(selectedTaskId, model, selected)
	{
		for (var taskId in this._grids)
		{
			if (taskId != selectedTaskId)
			{
				this._grids[taskId].getSelectionModel().deselectAll(true); // deselect all the other grids
			}
		}
		
		this._selection = Ext.isArray(selected) ? selected : [selected];
		this.sendCurrentSelection();
	},
	
	setParams: function(params)
	{
		this.callParent(arguments);
		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)
        });
	},
	
	refresh: function()
	{
		this.showRefreshing();
		
		Ametys.data.ServerComm.send({
 			plugin: 'odf',
 			url: this._tasksUrl,
 			parameters: {},
			priority: Ametys.data.ServerComm.PRIORITY_MAJOR,
			waitMessage: false,
			responseType: 'xml',
			callback: {
				handler: this._refreshCb,
				scope: this
			}
 		});
	},
	
	/**
	 * Does the real refresh after retrieving the tasks from the server.
	 * Draws and loads the grids.
	 * @param {HTMLElement} response The text response provided by the {@link Ametys.data.ServerComm}
	 * @private
	 */
	_refreshCb: function(response)
	{
		var tasks = Ext.dom.Query.selectNode('tasks', response);
		
	    this._grids = {};
        
        // Recent drafts panel
        var recentDraftPanel = this._mainPanel.items.get('recent-drafts-panel');
        var recentDraftsGrid = recentDraftPanel.items.get('recent-drafts-grid');
	    
        // Tabs panel
        var taskPanels = [];
        
	    // Retrieve the tasks
		var taskNodes = Ext.dom.Query.select("task", tasks);
		for (var i = 0; i < taskNodes.length; i++)
	    {
	        var taskId = Ext.dom.Query.selectValue('@id', taskNodes[i], '');
            var taskLabel = Ext.dom.Query.getNodeValue(taskNodes[i]);
            var max = Ext.dom.Query.selectValue('@length', taskNodes[i]);
            
            if (taskId == 'recent-drafts')
            {
                this._reconfigureRecentDraftsGrid(recentDraftsGrid, 'recent-drafts', taskLabel, max, taskNodes[i]);
                recentDraftPanel.items.add(recentDraftsGrid);
            }
            else
            {
                taskPanels.push({
                    xtype: 'panel',
                    itemId: taskId + '-panel',
                    title: taskLabel,
                    border: false,
                    layout: 'fit',
                    items: [this._drawGridPanel(taskId, taskLabel, max, taskNodes[i])]
                });
            }
	    }
	    
 		this._mainPanel.items.get('tabs-panel').removeAll();
 		for (var i = 0; i < taskPanels.length; i++)
 		{
 			this._mainPanel.items.get('tabs-panel').add(taskPanels[i]).show();
 		}
 		
 		// Load the grids
 		for (var taskId in this._grids)
		{
			this._grids[taskId].getStore().load({
				params: {
					taskId: taskId,
					login: Ametys.getAppParameter('user').login,
					lang: Ametys.getAppParameter('user').locale
				}
			});
		}
		this.showRefreshed();
	},
	
	/**
	 * Changes the store and the columns of the recent drafts grid.
	 * @param {String} grid The grid to reconfigure.
	 * @param {String} taskId The id of the task.
	 * @param {String} taskLabel The label of the task.
	 * @param {Number} max The max items to display.
     * @param {Object} taskNode The DOM representing the task
	 * @private
	 */
	_reconfigureRecentDraftsGrid: function(grid, taskId, taskLabel, max, taskNode)
	{
		var store = Ext.create('Ext.data.Store', {
			model: this._model,
 			proxy: {
 				type: 'ametys',
				plugin: 'odf',
				url: this._proxyUrl,
				reader: {
					type: 'xml',
					record: 'content'
				}
 			},
 			sorters: [{property: 'lastModified', direction: 'DESC'}],
 			taskId: taskId,
 			taskLabel: taskLabel
		});
		
		var columns = this._getRecentDraftColumnsConfig(taskNode);
		
		grid.reconfigure(store, columns);
		
		// Events
		grid.on('selectionchange', this._onSelectionChange, this, {args: [taskId]});
		grid.on('celldblclick', this._openContent, this);
		grid.getStore().on('load', this._onLoad, this, [taskId, taskLabel]);
		
	    this._grids[taskId] = grid;
	},
    
    /**
     * @protected
     * Gets the configuration of the columns for a recent drafts
     * @param {Object} taskNode The DOM representing the task
     * @return {Object[]} The configuration of the columns for a task tab
     */
    _getRecentDraftColumnsConfig: function(taskNode)
    {
        return columns = [
            {stateId: 'grid-column-title', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_CONTENT_TITLE}}", width: 270, sortable: true, dataIndex: 'title', renderer: Ametys.grid.GridColumnHelper.renderTextWithIcon},
            {stateId: 'grid-column-language', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_LANGUAGE}}", width: 60, sortable: true, dataIndex: 'language', renderer: this._renderLanguage},
			{stateId: 'grid-column-code', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_CODE}}", width: 100, sortable: true, dataIndex: 'displayCode'},
			{stateId: 'grid-column-ametyscode', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_AMETYS_CODE}}", width: 100, sortable: true, dataIndex: 'code', hidden: true},
            {stateId: 'grid-column-catalog', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_CATALOG}}", width: 120, sortable: true, dataIndex: 'catalog'},
            {stateId: 'grid-column-lastModified', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_LASTMODIFIED}}", width: 160, sortable: true, dataIndex: 'lastModified', renderer: Ametys.grid.GridColumnHelper.renderDateTime},
            {stateId: 'grid-column-workflow-step', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_WORKFLOW_STEP}}", width: 50, sortable: true, dataIndex: 'workflow-step', renderer: this._renderWorkflowStep}
        ];
    },
    
 	/**
 	 * Draws a grid for a tab.
 	 * @param {String} taskId The id of the task.
 	 * @param {String} taskLabel The label of the task.
 	 * @param {Number} max The max items to display.
     * @param {Object} taskNode the DOM representing the task
 	 * @return {Ext.grid.Panel} The grid.
 	 * @private
 	 */
 	_drawGridPanel: function(taskId, taskLabel, max, taskNode)
 	{
 		var store = Ext.create('Ext.data.Store', {
 			model: this._model,
 			proxy: {
 				type: 'ametys',
				plugin: 'odf',
				url: this._proxyUrl,
				reader: {
					type: 'xml',
					record: 'content'
				}
 			},
 			sorters: [{property: 'lastModified', direction: 'DESC'}],
 			taskId: taskId,
        	taskLabel: taskLabel
 		});
 		
 		var itemId = taskId + '-grid';
 		var grid = Ext.create('Ext.grid.Panel', {
 			itemId: itemId,
 			store: store,
 			
 			region: 'center',
 			deferRowRender: true,
 			
 			cls: 'mask-below-menu',
 			
 			selModel: {
	        	mode: 'MULTI'
	        },
	        
	        stateful: true,
	        stateId: this.self.getName() + "$" + itemId,
 			
 			columns: this._getTaskColumnsConfig(taskNode)
 		});
 		
 		// Events
 		grid.on('selectionchange', this._onSelectionChange, this, {args: [taskId]});
 		grid.on('celldblclick', this._openContent, this);
 		grid.getStore().on('load', this._onLoad, this, [taskId, taskLabel]);
	    
	    this._grids[taskId] = grid;
	    
	    return grid;
 	},
    
    /**
     * @protected
     * Gets the configuration of the columns for a task tab
     * @param {Object} taskNode The DOM representing the task
     * @return {Object[]} The configuration of the columns for a task tab
     */
    _getTaskColumnsConfig: function(taskNode)
    {
        return [
            {stateId: 'grid-column-title', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_CONTENT_TITLE}}", width: 270, sortable: true, dataIndex: 'title', renderer: Ametys.grid.GridColumnHelper.renderTextWithIcon},
            {stateId: 'grid-column-language', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_LANGUAGE}}", width: 60, sortable: true, dataIndex: 'language', renderer: this._renderLanguage},
            {stateId: 'grid-column-code', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_CODE}}", width: 100, sortable: true, dataIndex: 'displayCode'},
			{stateId: 'grid-column-ametyscode', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_AMETYS_CODE}}", width: 100, sortable: true, dataIndex: 'code', hidden: true},
            {stateId: 'grid-column-catalog', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_CATALOG}}", width: 120, sortable: true, dataIndex: 'catalog'},
            {stateId: 'grid-column-contributor', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_CONTRIBUTOR}}", width: 270, sortable: true, dataIndex: 'contributor'},
            {stateId: 'grid-column-lastModified', header: "{{i18n PLUGINS_ODF_DASHBOARD_COLUMN_LASTMODIFIED}}", width: 160, sortable: true, dataIndex: 'lastModified', renderer: Ametys.grid.GridColumnHelper.renderDateTime}
        ];
    },
 	
 	/**
 	 * Renders a workflow step.
 	 * @param {Object} value The data value for the current cell.
 	 * @param {Object} metaData A collection of metadata about the current cell.
 	 * @param {Ext.data.Model} record The record for the current row.
 	 * @return {String} The HTML for rendering the workflow step.
 	 * @private
 	 */
 	_renderWorkflowStep: function(value, metaData, record)
 	{
 		var step;
 		var iconSmall = record.get('workflow-icon-small');
	    if (iconSmall)
	    {
	        step = '<img src="'
	        + Ametys.CONTEXT_PATH
	        + iconSmall
	        + '" style="float: left; margin-right: 5px" alt="'
	        + record.get('workflow-step')
	        + '" title="'
	        + record.get('workflow-step')
	        + '"/>';
	    }
	    else
	    {
	        step = record.get('workflow-step');
	    }
	    return step;
 	},
 	
 	/**
 	 * Renders a language.
 	 * @param {Object} value The data value for the current cell.
 	 * @param {Object} metaData A collection of metadata about the current cell.
 	 * @param {Ext.data.Model} record The record for the current row.
 	 * @return {String} The HTML for rendering the workflow step.
 	 * @private
 	 */
 	_renderLanguage: function(value, metaData, record)
 	{
 		return '<img src="' + Ametys.CONTEXT_PATH + record.get('language-image') + '" style="float:left; margin-right: 5px" alt="' + value + '"/>';
 	},
 	
 	/**
 	 * Opens the selected content.
 	 * @param {Ext.view.Table} table The table.
 	 * @param {HTMLElement} td The TD element for the cell.
 	 * @param {Number} cellIndex The cell index.
 	 * @param {Ext.data.Model} record The record to open.
 	 * @private
 	 */
 	_openContent: function(table, td, cellIndex, record)
 	{
 		var id = record.get('id');
	    Ametys.tool.ToolsManager.openTool('uitool-content', {'id': id});
 	},
 	
 	/**
 	 * Listener when a store reads data.
 	 * @param {Ext.data.Store} store The store.
 	 * @param {Ext.data.Model[]} records An array of records.
 	 * @private
 	 */
 	_onLoad: function(store, records)
 	{
 		this._modifyPanelTitle(store.taskId, store.taskLabel, records.length);
 	},
 	
 	/**
 	 * Updates the title of a panel.
 	 * @param {String} taskId The id of the panel to update.
 	 * @param {String} taskLabel The new title.
 	 * @param {String} count The number to set in brackets at the end of the new title.
 	 * @private
 	 */
 	_modifyPanelTitle: function(taskId, taskLabel, count)
 	{
 		if (taskId && taskLabel)
 		{
 			var panel = this._mainPanel.getComponent(taskId + '-panel') || this._mainPanel.getComponent('tabs-panel').getComponent(taskId + '-panel');
 			if (panel != null)
 			{
 				panel.setTitle(taskLabel + ' (' + count + ')');
 			}
 		}
 	},
 	
 	/**
 	 * Listener on CONTENT message.
 	 * @param {Ametys.message.Message} message The content message.
 	 * @private
 	 */
 	_refreshIfNeeded: function(message)
 	{
 		var targets = message.getTargets(Ametys.message.MessageTarget.CONTENT);
		if (targets)
		{
			var contentIds = this._convertToId(targets);
			if (this._areInStore(contentIds))
			{
				// We are concerned by this message
				this.showOutOfDate();
			}
		}
 	},
 	
 	/**
 	 * Gives the ids of the given targets.
 	 * @param {Object[]} targets The targets.
 	 * @return {String[]} The ids.
 	 * @private
 	 */
 	_convertToId: function(targets)
 	{
 		return targets.map(function(target){
 			return target.getParameters().id;
 		}); 
 	},
 	
 	/**
 	 * Tells if one of the contentIds are currently somewhere in the tool's grids.
 	 * @param {String[]} contentIds The ids to test.
 	 * @return {Boolean} True if at least one id is in one of the stores.
 	 * @private
 	 */
 	_areInStore: function(contentIds)
 	{
 		var atLeastOneIsInStore = false;
 		Ext.each(contentIds, function(contentId) {
 			for (var key in this._grids)
 			{
 				var record = this._grids[key].getStore().getById(contentId);
 				if (record != null)
 				{
 					atLeastOneIsInStore = true;
 					return false;
 				}
 			}
 		}, this);
 		
 		return atLeastOneIsInStore;
 	}
 });