/*
 *  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 surveys, with its pages and questions.
 * @private
 */
Ext.define('Ametys.plugins.survey.SurveyTool', {
	extend: 'Ametys.tool.Tool',

	/**
	 * @private
	 * @property {Ametys.plugins.survey.SurveyTree} _tree The tree of this tool.
	 */
	
	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);
		Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGED, this._onMessageWorkflowChanged, this);
	},
	
	createPanel: function()
	{
		this._tree = Ext.create('Ametys.plugins.survey.SurveyTree', {
			// handle drag & drop
			viewConfig: {
                plugins: {
                    ptype: 'ametystreeviewdragdrop',
                    containerScroll: true,
                    appendOnly: false,
                    sortOnDrop: false,
                    expandDelay: 500,
                    allowContainerDrops: false,
                    setAmetysDragInfos: Ext.bind(this._getDragInfo, this),
                    setAmetysDropZoneInfos: Ext.bind(this._getDropInfo, this)
                }
            }
		});
		
		this._tree.on('selectionchange', this.sendCurrentSelection, this);
		this._tree.on('itemdblclick', this._openPreviewTool, this);
		
		return this._tree;
	},
	
	getMBSelectionInteraction: function()
	{
		return Ametys.tool.Tool.MB_TYPE_ACTIVE;
	},
	
	sendCurrentSelection: function()
	{
		var selection = this._tree.getSelectionModel().getSelection();

		if (selection != null && selection.length > 0)
		{
			var node = selection[0];
			var target = this._getMessageTargetConfiguration(node) || [];
			
			var type = node.get('type'),
				realTarget;
			if (type == 'root' || type == 'survey')
			{
				realTarget = target;
			}
			else if (type == 'page')
			{
				var surveyNode = this._tree.getStore().getNodeById(node.get('parentId'));
				
				realTarget = this._getMessageTargetConfiguration(surveyNode);
				realTarget.subtargets = target;
			}
			else if (type == 'question')
			{
				var pageNode = this._tree.getStore().getNodeById(node.get('parentId'));
				var surveyNode = this._tree.getStore().getNodeById(pageNode.get('parentId'));
				
				realTarget = this._getMessageTargetConfiguration(surveyNode);
				var subtarget = this._getMessageTargetConfiguration(pageNode);
				subtarget.subtargets = target;
				realTarget.subtargets = subtarget;
			}
		}
		
		Ext.create('Ametys.message.Message', {
			type: Ametys.message.Message.SELECTION_CHANGED,
			targets: realTarget
		});
	},
	
	/**
	 * Gets the selected language.
	 * @return {String} The selected language.
	 */
	getCurrentLanguage: function()
	{
		return this._tree.down("combobox[itemId='languages-combo']").getValue();
	},
	
	setParams: function (params)
	{
		this.callParent(arguments);
		this.showOutOfDate();
	},
	
	refresh: function()
	{
		this.showRefreshing();
		
		this._tree.getSelectionModel().select(this._tree.getRootNode());
		this._tree.refreshNode(this._tree.getRootNode(), false, Ext.bind(this.showRefreshed, this));
	},
	
	/**
     * @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 {Ametys.relation.RelationPoint} item.source The source (in the relation way) of the drag operation. 
     */
    _getDragInfo: function (item)
    {
        var targets = [];
        
        for (var i = 0; i < item.records.length; i++)
        {
        	var node = item.records[i];
        	if (node.get('type') == 'page' || node.get('type') == 'question')
			{
				targets.push(this._getMessageTargetConfiguration(node));
			}
        }
        
        if (targets.length > 0)
        {
            item.source = {
                relationTypes: [Ametys.relation.Relation.MOVE], 
                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.   
     * @param {String} dropPosition "before", "after" or "append" depending whether the dragged object (in item.target) should be inserted before, after the targetRecords, or appended to it.
     */ 
    _getDropInfo: function(targetRecords, item, dropPosition)
    {
        var targets = [];
        
        var positionInTargets = -1
        for (var i = 0; i < targetRecords.length; i++)
        {
        	var node = targetRecords[i];
        	
        	if (dropPosition == 'append')
			{
				targets.push(this._getMessageTargetConfiguration(node));
			}
        	else if (node.parentNode != null) // dropPosition == 'before' or 'after'
        	{
        		// Get node position 
        		for (var i=0; i < node.parentNode.childNodes.length; i++)
        		{
        			if (node.parentNode.childNodes[i].getId() == node.getId())
        			{
        				positionInTargets = i + (dropPosition == 'after' ? + 1 : 0);
        				break;
        			}
        		}
        		
        		targets.push(this._getMessageTargetConfiguration(node.parentNode));
        	}
        }

        if (targets.length > 0)
        {
            item.target = {
                relationTypes: [Ametys.relation.Relation.MOVE], 
                targets: targets,
                positionInTargets: positionInTargets
            };
        }
    },
    
    /**
     * @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 {
					id: Ametys.message.MessageTarget.SURVEY_ROOT,
					parameters: {}
				};
        	}
        	else if (record.get('type') == 'survey')
        	{
        		return {
					id: Ametys.message.MessageTarget.SURVEY,
					parameters: {
						id: record.getId()
					}
				};
        	}
        	else if (record.get('type') == 'page')
			{
				return {
					id: Ametys.message.MessageTarget.SURVEY_PAGE,
					parameters: {
						id: record.getId(),
						surveyId: record.get('parentId')
					}
				};
			}
			else if (record.get('type') == 'question')
			{
				var pageId = record.get('parentId');
				var surveyId = this._tree.getStore().getNodeById(pageId).get('parentId');
				return {
					id: Ametys.message.MessageTarget.SURVEY_QUESTION,
					parameters: {
						id: record.getId(),
						type: record.get('questionType'),
						pageId: pageId,
						surveyId: surveyId
					}
				};
			}
        }
    },
    
    /**
     * Selects the specified node.
     * @param {String} nodeId The node id
     * @private
     */
    _selectNode: function(nodeId)
    {
    	var node = this._tree.getStore().getNodeById(nodeId);
		this._tree.getSelectionModel().select(node);
    },
	
	/**
     * Listener on creation message.
     * @param {Ametys.message.Message} message The creation message.
     * @private
     */
	_onMessageCreated: function(message)
	{
		// Case survey
		var target = message.getTarget(Ametys.message.MessageTarget.SURVEY);
		if (target != null)
		{
			// Refresh root node
			var parentNode = this._tree.getRootNode();
			var newNodeId = target.getParameters().id;
			this._tree.refreshNode(parentNode, false, Ext.bind(function(nodeId) {
				var node = this._tree.getStore().getNodeById(nodeId);
				this._tree.getSelectionModel().select(node);
				Ext.defer(this._openPreviewTool, .1, this, [null, node]);
			}, this, [newNodeId]));
		}
		
		
		// Case page
		var target = message.getTarget(Ametys.message.MessageTarget.SURVEY_PAGE);
		if (target != null)
		{
			// Refresh parent node
			var surveyNode = this._tree.getStore().getNodeById(target.getParameters().surveyId);
			var newNodeId = target.getParameters().id;
			this._tree.refreshNode(surveyNode, false, Ext.bind(this._selectNode, this, [newNodeId]));
		}
		
		
		// Case question
		var target = message.getTarget(Ametys.message.MessageTarget.SURVEY_QUESTION);
		if (target != null)
		{
			// Refresh parent node
			var pageNode = this._tree.getStore().getNodeById(target.getParameters().pageId);
			var newNodeId = target.getParameters().id;
			this._tree.refreshNode(pageNode, false, Ext.bind(this._selectNode, this, [newNodeId]));
		}
	},
	
	/**
     * 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.SURVEY 
				|| target.getId() == Ametys.message.MessageTarget.SURVEY_PAGE
				|| target.getId() == Ametys.message.MessageTarget.SURVEY_QUESTION;
		});
		if (target != null)
		{
			var id = target.getParameters().id;
			
			// Refresh parent node
			var node = this._tree.getStore().getNodeById(id);
			var parentId = node.get('parentId');
			var parentNode = this._tree.getStore().getNodeById(parentId);
			this._tree.refreshNode(parentNode, false, Ext.bind(this._selectNode, this, [id]));
		}
	},
	
	/**
     * 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.SURVEY 
				|| target.getId() == Ametys.message.MessageTarget.SURVEY_PAGE
				|| target.getId() == Ametys.message.MessageTarget.SURVEY_QUESTION;
		});
		if (target != null)
		{
			var node = this._tree.getStore().getNodeById(target.getParameters().id);
			var parentId = node.get('parentId');
			var parentNode = this._tree.getStore().getNodeById(parentId);
			
			// Select parent node and remove the node from the store
			this._tree.getSelectionModel().select(parentNode);
			node.remove();
		}
	},
	
	/**
     * Listener on workflow changing message.
     * @param {Ametys.message.Message} message The wokflow changing message.
     * @private
     */
	_onMessageWorkflowChanged: function(message)
	{
		var target = message.getTarget(Ametys.message.MessageTarget.SURVEY);
		if (target != null)
		{
			//var node = this._tree.getStore().getNodeById(target.getParameters().id);
			this._tree.refreshNode(this._tree.getRootNode(), false);
		}
	},
	
	/**
	 * Opens the preview tool for the record.
	 * @param {Ext.view.View} view The view.
	 * @param {Ext.data.Model} record The record that belongs to the item.
	 */
	_openPreviewTool: function(view, record)
	{
		var type = record.get('type');
		switch (type) {
			case 'survey':
				var id = record.get('id');
				break;
			case 'page':
				var pageId = record.get('id');
				var id = record.get('parentId');
				break;
			case 'question':
				var questionId = record.get('id');
				var pageId = record.get('parentId');
				var id = this._tree.getStore().getNodeById(pageId).get('parentId');
				break;
			case 'root':
			default:
				return;
		}
		
		var params = {
			id: id,
			pageId: pageId,
			questionId: questionId
		};
		
		Ametys.tool.ToolsManager.openTool('uitool-survey-preview', params);
	}
	
});

Ext.define("Ametys.message.SurveyMessageTarget",{
	override: "Ametys.message.MessageTarget",
	statics: 
	{
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} SURVEY_ROOT The target type is the survey tree root, which provides the surveys.
		 */
		SURVEY_ROOT: "survey-root",
		
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} SURVEY The target type is a survey. The expected parameters are:
		 * @property {String} SURVEY.id The id of this survey.
		 */
		SURVEY: "survey",
		
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} SURVEY_PAGE The target type is a survey page. The expected parameters are:
		 * @property {String} SURVEY_PAGE.id The id of this survey page.
		 * @property {String} SURVEY_PAGE.surveyId The id of the parent survey.
		 */
		SURVEY_PAGE: "survey-page",
		
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} SURVEY_QUESTION The target type is a survey question. The expected parameters are:
		 * @property {String} SURVEY_QUESTION.id The id of this question.
		 * @property {String} SURVEY_QUESTION.type The type of the question (FREE_TEXT, MULTILINE_FREE_TEXT, SINGLE_CHOICE, MULTIPLE_CHOICE, SINGLE_MATRIX, MUTLIPLE_MATRIX).
		 * @property {String} SURVEY_QUESTION.pageId The id of the parent page.
		 * @property {String} SURVEY_QUESTION.surveyId The id of the grandparent survey.
		 */
		SURVEY_QUESTION: "survey-question"
	}
});