/*
 *  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 a tree with datasources types, datasources, and datasources queries.
 * @private
 */
Ext.define('Ametys.plugins.externaldata.DataSourcesTool', {
	extend: 'Ametys.tool.Tool',
	
	/**
	 * @property {Ext.tree.Panel} _tree The tree of this tool
	 * @private
	 */
	
	constructor: function(config)
	{
		this.callParent(arguments);
		
		Ametys.message.MessageBus.on(Ametys.message.Message.CREATED, this._onMessageCreated, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onMessageModified, this);
		Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onMessageDeleted, this);
	},
	
	createPanel: function()
	{
		this._tree = Ext.create('Ametys.plugins.externaldata.DataSourcesTree', {});
		
		this._tree.on('selectionchange', this._onSelectionChange, this);
		
		return this._tree;
	},
	
	getMBSelectionInteraction: function() {
		return Ametys.tool.Tool.MB_TYPE_ACTIVE;
	},
	
	sendCurrentSelection: function()
	{
		var realTarget = [];
		
		var selection = this._tree.getSelection();
		if (selection != null && selection.length > 0)
		{
			var node = selection[0],
				type = node.get('type'),
				target = this._getMessageTargetConfiguration(node) || [];
			
			if (type == 'root' || type == 'dataSourceType')
			{
				realTarget = target;
			}
			else if (type == 'datasource')
			{
				var dataSourceTypeNode = this._tree.getStore().getNodeById(node.get('parentId'));
				
				realTarget = this._getMessageTargetConfiguration(dataSourceTypeNode);
				realTarget.subtargets = target;
			}
			else if (type == 'query')
			{
				var dataSourceNode = this._tree.getStore().getNodeById(node.get('parentId'));
				var dataSourceTypeNode = this._tree.getStore().getNodeById(dataSourceNode.get('parentId'));
				
				realTarget = this._getMessageTargetConfiguration(dataSourceTypeNode);
				var subtarget = this._getMessageTargetConfiguration(dataSourceNode);
				subtarget.subtargets = target;
				realTarget.subtargets = subtarget;
			}
		}

		Ext.create('Ametys.message.Message', {
			type: Ametys.message.Message.SELECTION_CHANGED,
			targets: realTarget
		});
	},
	
	setParams: function(params)
	{
		this.showOutOfDate();
        this.callParent(arguments);
	},
	
	refresh: function()
	{
		this.showRefreshing();
		
		this._tree.getStore().load({
			scope: this,
			callback: Ext.bind(this._refreshCb, this)
		});
	},
	
	/**
	 * Callback function after the tool was refreshed. Expands the nodes.
	 * @private
	 */
	_refreshCb: function()
	{
		this.showRefreshed();
		Ext.defer(this._tree.expandNode, 200, this._tree, [ this._tree.getRootNode(), true, null ]);
	},
	
	/**
     * @private
     * Get the target configuration object for given record
     * @param {Ext.data.Model} record The tree record to convert to its Ametys.message.MessageTarget configuration
     * @return {Object} The configuration to create a Ametys.message.MessageTarget. Can be null, if the record is null or not relevant to be a messagetarget.
     */
    _getMessageTargetConfiguration: function (record)
    {
        if (record == null)
        {
            // Empty selection
            return null;
        }
        else
        {
        	if (record.get('type') == 'root')
        	{
        		return null;
        	}
        	else if (record.get('type') == 'dataSourceType')
        	{
        		return {
					id: Ametys.message.MessageTarget.EXTERNAL_DATASOURCE_TYPE,
					parameters: {
						id: record.getId(),
						type: record.get('dataSourceType')
					}
				};
        	}
        	else if (record.get('type') == 'datasource')
			{
				return {
					id: Ametys.message.MessageTarget.EXTERNAL_DATASOURCE,
					parameters: {
						id: record.getId(),
						dataSourceType: record.get('dataSourceType')
					}
				};
			}
			else if (record.get('type') == 'query')
			{
				return {
					id: Ametys.message.MessageTarget.EXTERNAL_DATASOURCE_QUERY,
					parameters: {
						id: record.getId(),
						dataSourceType: record.get('dataSourceType')
					}
				};
			}
        }
    },
	
	/**
	 * Listener for change of selection in the tree.
	 * @param {Ext.selection.Model} selectionModel The tool selection model
	 * @param {Ext.data.Model[]} selected The selected records.
	 * @private
	 */
	_onSelectionChange: function(selectionModel, selected)
	{
		if (selected != null)
		{
			this.sendCurrentSelection();
		}
	},
	
	/**
     * Listener on creation message.
     * @param {Ametys.message.Message} message The creation message.
     * @private
     */
	_onMessageCreated: function(message)
	{
		var target = message.getTarget(Ametys.message.MessageTarget.EXTERNAL_DATASOURCE);
		if (target != null)
		{
			// Refresh parent node
			var parentId = target.getParameters().dataSourceType;
			var parentNode = this._tree.getStore().getNodeById(parentId);
			this._tree.refreshNode(parentNode, true);
		}
		
		var target = message.getTarget(Ametys.message.MessageTarget.EXTERNAL_DATASOURCE_QUERY);
		if (target != null)
		{
			// Refresh parent node
			var parentId = target.getParameters().parentId;
			var parentNode = this._tree.getStore().getNodeById(parentId);
			this._tree.refreshNode(parentNode, true);
		}
	},
	
	/**
     * Listener on edition message.
     * @param {Ametys.message.Message} message The edition message.
     * @private
     */
	_onMessageModified: function(message)
	{
		var target = message.getTarget(function(target) {return target.getId() == Ametys.message.MessageTarget.EXTERNAL_DATASOURCE
															|| target.getId() == Ametys.message.MessageTarget.EXTERNAL_DATASOURCE_QUERY;});
		if (target != null)
		{
			var node = this._tree.getStore().getNodeById(target.getParameters().id);
			var parentId = node.get('parentId');
			var parentNode = this._tree.getStore().getNodeById(parentId);
			this._tree.refreshNode(parentNode, true);
			this._tree.getSelectionModel().select(node);
		}
	},
	
	/**
     * Listener on deletion message.
     * @param {Ametys.message.Message} message The deletion message.
     * @private
     */
	_onMessageDeleted: function(message)
	{
		var target = message.getTarget(function(target) {return target.getId() == Ametys.message.MessageTarget.EXTERNAL_DATASOURCE
															|| target.getId() == Ametys.message.MessageTarget.EXTERNAL_DATASOURCE_QUERY});
		if (target != null)
		{
			var node = this._tree.getStore().getNodeById(target.getParameters().id);
			var parentNode = this._tree.getStore().getNodeById(node.get('parentId'));
			
			// Select parent node and remove the node from the store
			this._tree.getSelectionModel().select(parentNode);
			node.remove();
		}
	}
	
});

Ext.define("Ametys.message.DataSourceMessageTarget", {
	override: "Ametys.message.MessageTarget",
	
	statics:
	{
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} EXTERNAL_DATASOURCE The target type is a datasource. The expected parameters are:
		 * @property {String} EXTERNAL_DATASOURCE.id The id of this datasource.
		 * @property {String} EXTERNAL_DATASOURCE.dataSourceType The type of datasource.
		 */
		EXTERNAL_DATASOURCE: "external-datasource",
		
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} EXTERNAL_DATASOURCE_TYPE The target type is a datasource type. The expected parameters are:
		 * @property {String} EXTERNAL_DATASOURCE_TYPE.id The id of this datasource type.
		 * @property {String} EXTERNAL_DATASOURCE_TYPE.type The type of this datasource type.
		 */
		EXTERNAL_DATASOURCE_TYPE: "external-datasource-type",
		
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} EXTERNAL_DATASOURCE_QUERY The target type is a datasource query. The expected parameters are:
		 * @property {String} EXTERNAL_DATASOURCE_QUERY.id The id of this query.
		 * @property {String} EXTERNAL_DATASOURCE_QUERY.dataSourceType The type of the datasource associated to this query.
		 */
		EXTERNAL_DATASOURCE_QUERY: "external-datasource-query"
	}
});