/**
 * Project   : AMDA-NG
 * Name      : SearchUI.js
 * @class 	 amdaUI.SearchUI
 * @extends      Ext.container.Container 
 * @brief    Search Module UI definition (View)
 * @author CDA
 * @version $Id: SearchUI.js 2467 2014-07-10 16:06:26Z myriam $  
 */

Ext.define('amdaUI.SearchUI', 
{
	extend: 'Ext.container.Container',
	alias: 'widget.panelSearch',
	
	requires: [
	 	'amdaUI.CalculatorUI',
	 	'amdaUI.TimeSelectorUI',
	 	'extensions.SelectableTextArea',
	 	'amdaUI.ParamArgumentsPlug',
		'amdaModel.RequestParamObject'
	],    
 
	constructor: function(config) 
	{	          
		this.init(config);
		this.callParent(arguments);	
		// load object into view    
		this.loadObject();
		
		var searchArgsPlug = this.getPlugin('search-param-components-plugin');
		if (searchArgsPlug)
			searchArgsPlug.onApply = this.onApplyParameterArgs;
	},

	addTT : function(newTTName,newTTid)
	{
		this.timeSelector.addTT(newTTName,newTTid);
	},
	
	addTTs : function(TTarray) 
	{
		// set TTTab	    
		this.timeSelector.setTTTab(TTarray);
	},
        
	addParam : function(newParamName, isLeaf, needArgs, components) 
	{
		if (needArgs || components)
				this.editParameterArgs(newParamName, components);
		else
			this.addParamInEditor(newParamName);
	},
        
	addParamInEditor : function(param) 
	{
		var selection = this.constructionField.getSelection();
		this.constructionField.setValue(selection.beforeText + param + selection.afterText);
		this.constructionField.focus();
		this.constructionField.setCaretPosition(this.constructionField.getValue().length);
	},
        
	onApplyParameterArgs : function(uiScope, paramRequestObject) 
	{
		var fullParam = paramRequestObject.getParamFullName();
		uiScope.addParamInEditor(fullParam);
	},
        
	editParameterArgs: function(name, components) 
	{
		var paramObj = amdaModel.RequestParamObject.getEmptyObj();
		paramObj.paramid = name;
        	
		if (components) {
			if (components['index1']) {
				paramObj['dim1-index'] = components['index1'];
				++paramObj['type'];
			}
			
			if (components['index2']) {
				paramObj['dim2-index'] = components['index2'];
				++paramObj['type'];
			}
		}
        	
		var paramArgsPlug = this.getPlugin('search-param-components-plugin');
		if (paramArgsPlug) {
			var workinRequestParamObject = Ext.create('amdaModel.RequestParamObject', paramObj);
			paramArgsPlug.show('search-param-components-plugin', workinRequestParamObject);
		}
	},
        
	/**
	* Set Start-Stop from parameter info (Local & MyData)
	*/ 
	setTimeFromData : function(obj) 
	{																				
		if (!obj.start || !obj.stop)
			return;
		var dateStart = new Date(obj.start.replace(/[T|Z]/g,' ').replace(/\-/g,'\/')); 
		var dateStop = new Date(obj.stop.replace(/[T|Z]/g,' ').replace(/\-/g,'\/')); 
		
		this.down('form').getForm().setValues({ startDate : dateStart, stopDate : dateStop });
	},
        
	setObject : function(obj) 
	{             
		this.object = obj;  
		this.loadObject();
	},
	
	/**
	 * update this.object from form
	 */
	updateObject : function()
	{    
		// get the basic form
		var basicForm = this.formPanel.getForm();
		// get the timeSource selected
		var timeSource = this.timeSelector.getActiveTimeSource();	    
		var updateStatus = true;

		var fieldsWithoutName = basicForm.getFields().items;
		Ext.Array.each(fieldsWithoutName, function(item, index,allItems)
		{
			if(item !== this.fieldName) 
			{ 		     
				if (!item.isValid()) 
				{
					if ((timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0]) &&
							((item.name == 'startDate') || (item.name == 'stopDate') || (item.name == 'duration'))) {
								updateStatus = true;
						}
					else {
						// set update isn't allowed
						updateStatus = false;
						return false;
					}       
				}
			}
		}, this);

		if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0] // timeSource  'TimeTable'
		    && this.timeSelector.TTGrid.getStore().count() == 0) {

			Ext.Msg.show({
				title: 'Warning', msg: 'You chose Time Selection `by TimeTable` but no timeTable was added!'
				+'<br>You must add one or choose Time Selection `by Interval`', 
				icon: Ext.MessageBox.WARNING, buttons: Ext.Msg.OK
			}); 
			updateStatus = false;    
		}
		// if the update is allowed
		if (updateStatus) 
		{
		/// real object update
		// update TimeTable object with the content of form
			basicForm.updateRecord(this.object);
			this.object.set('timesrc', timeSource);
			// set valid intervals into TimeTable object
			if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0]) {	      
				this.object.set('timeTables',this.timeSelector.TTGrid.getStore().data.items);
			}
		}    
		// return the update status
		return updateStatus;	    
	},
	
	/**
		* load this.object into form
		*/
	loadObject : function()
	{
		// load object into form		
		this.formPanel.getForm().loadRecord(this.object);       
		// set object's TTs into the timeselector
		this.addTTs(this.object.get('timeTables'));	 
	},
	
	/**
	 * save method called by Save button to launch the save process
	 */
	saveProcess : function(toRename)
	{
		// if the TimeTable object has been modified	  
		if (this.object.dirty) 
		{            
			// Search module
			var searchModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.search.id);//('search-win');           
			// if the name has been modified this is a creation
			if (this.object.isModified('name'))
			{
				// if object already has an id : it's a 'rename' of an existing Condition
				if (this.object.get('id'))
				{
					// the context Node is the parent node of current edited one
					var contextNode = searchModule.linkedNode.parentNode;
					// link a new node to the TimeTableModule
					searchModule.createLinkedNode();
					// set the contextNode
					searchModule.linkedNode.set('contextNode',contextNode);
					// create a new object linked
					searchModule.createObject(this.object.getJsonValues());            
					var searchObj = searchModule.linkedNode.get('object');                           
					// synchronisation of objects		     
					this.object = searchObj; 		      
					if (toRename) searchModule.linkedNode.toRename = true;
				}               
				searchModule.linkedNode.create();
			} else {           
				searchModule.linkedNode.set('contextNode',searchModule.contextNode); 
				// this.object.fireEvent('modify');
				searchModule.linkedNode.update();
			}
		}
	},
	
	/**
	 * overwrite metod called by Save button
	 */
	overwriteProcess : function(btn)
	{	
		if (btn == 'cancel') return;	
					
		this.fieldName.clearInvalid();    
		this.saveProcess(true);		
	},
	
	/**
	 * search method called by 'Do Search' button to launch the search process
	 */
	doSearch : function()
	{	     
		var searchModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.search.id);
		searchModule.linkedNode.execute();
		// fire execution  
		//  this.object.fireEvent('execute',this.object.dirty);
	},
        
	/**
	*   Check if brackets are balanced
	*/        
	isBalanced : function(str)
	{ 
		str =  (""+str).replace(/[^()\[\]{}]/g, ""); 
		var bracket = {
						"]": "[",
						"}": "{",
						")": "("
					},
		openBrackets = [], 
		isClean = true,
		i = 0,
		len = str.length;

		for(; isClean && i<len; i++ ){                
				if( bracket[ str[ i ] ] ){
					isClean = ( openBrackets.pop() === bracket[ str[ i ] ] );
				}else{
					openBrackets.push(str[i]);
				}
		}
		if (!(isClean && !openBrackets.length)) return 'Brackets are not balanced';
			
		return true; 
	},
        
	/**
	* Update constructionField (Search Condition) in window search        
	*/     
	updateConstruct : function(oldval,newval) 
	{
		var expression = this.constructionField.value;
		oldval = oldval.replace(/[(]/g,"\\(");
		oldval = oldval.replace(/[)]/g,"\\)");	
		var reg=new RegExp(oldval, "g");
		expression = expression.replace(reg, newval);
		this.constructionField.setValue(expression);
	},

	/**
	 * Check if changes were made before closing window 
	 * @return true if changes
	 */	   
	fclose : function() 
	{
		var form = this.formPanel.getForm();
		var isDirty = form.isDirty();
		return isDirty;
	},
	
	/**
	*  Component configiration / init
	*/
	init : function(config)	
	{	  
		this.timeSelector = new amdaUI.TimeSelectorUI({id: 'SearchTimeSelector',flex: 2});

		this.fieldName = new Ext.form.field.Text({
				labelAlign: 'top', itemId: 'formParamName',
				fieldLabel: 'Request Name',
				labelPad: 0,
				name : 'name',
				width: 165,
				allowBlank : false,
				stripCharsRe: /(^\s+|\s+$)/g,
				validateOnChange: false,
				validateOnBlur: false,
				validFlag: false,
				validator : function() 
				{
					return this.validFlag;
				}
		});

		this.constructionField = new extensions.SelectableTextArea(
		{
				labelAlign: 'top',
				labelPad: 0,
				itemId: 'formSearchCondition',
				fieldLabel:'<img amda_clicktip="constructParameter" src="js/resources/images/16x16/info_mini.png"/>&nbsp;Data Mining Condition',
				allowBlank : false, blankText : 'Condition expression is required',
				name: 'expression',
				validateOnChange: false,
				validateOnBlur: false,
				validator : this.isBalanced,
				flex : 2,
				listeners :
				{
					render : function(o,op)
					{
						var me = this;
						var el = me.bodyEl;
						var dropTarget = Ext.create('Ext.dd.DropTarget', el, 
						{
							ddGroup: 'explorerTree',
							notifyEnter : function(ddSource, e, data){ },
							notifyOver  : function(ddSource, e, data)
							{ 
								if (data.records[0].get('nodeType') == 'localParam' && data.records[0].get('notyet')) {
										this.valid = false;
										return this.dropNotAllowed;   
								}
								if (((data.records[0].get('nodeType') == 'localParam')   ||
										(data.records[0].get('nodeType') == 'remoteParam') || 
										(data.records[0].get('nodeType') == 'remoteSimuParam') ||
										(data.records[0].get('nodeType') == 'derivedParam') ||
										(data.records[0].get('nodeType') == 'myDataParam') ||
										(data.records[0].get('nodeType') == 'alias')) &&
										(data.records[0].isLeaf() || data.records[0].get('isParameter'))  &&
										!data.records[0].data.disable)
								{
									this.valid = true;
									return this.dropAllowed;
								}
								
								this.valid = false;
								return this.dropNotAllowed;
							},
							notifyDrop  : function(ddSource, e, data)
							{
								if (!this.valid) return false;
															
								var nameToSent;
								var components = null;
								switch (data.records[0].get('nodeType'))
								{
									case 'localParam' :
									case 'remoteParam' :
									case 'remoteSimuParam' :    
										nameToSent = data.records[0].get('id');
										if (data.records[0].get('alias')!= "" )
											nameToSent = "#"+data.records[0].get('alias');
											var component_info = data.records[0].get('component_info');
											if (component_info && component_info.parentId) 
											{													
												if ( component_info.index1 && component_info.index2 )
												{															 
													nameToSent = component_info.parentId;
													components = [];												
													if (component_info.index1)
														components['index1'] = component_info.index1;
													if (component_info.index2)
														components['index2'] = component_info.index2;
												}	
												if ( data.records[0].get('needsArgs') )
												{															
													nameToSent = component_info.parentId;	
													if (component_info.index1)
													{
														components = [];	
														components['index1'] = component_info.index1;
													}
												}													
											}
											break;
										case 'alias' :
											nameToSent = "#"+data.records[0].get('text');
											break;
										case 'derivedParam' :
											nameToSent = "ws_"+data.records[0].get('text');
											break;
										case 'myDataParam' :
											var name = data.records[0].get('text');
											nameToSent = "wsd_"+name;
											var size = data.records[0].get('size');
											if (size &&  size > 1) {
												nameToSent += "(0)";
												myDesktopApp.warningMsg("parameter "+name+" is array of size: "+size+"<br/>Please put index");
											}
											break;
										default :
											return false;
									}
									var searchModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.search.id);
									
									if (searchModule)
										searchModule.addParam(nameToSent, data.records[0].get('leaf'), data.records[0].get('needsArgs'), components);	
									return true;
								}
						});
					}
				}
		});

		var samplingmode_store = new Ext.data.ArrayStore({
			fields: ['id', 'name'],
			data: [
				['timestep', 'Time Step'],
				['refparam', 'Ref. Parameter']
			]
		});

		this.timeStepField = new Ext.form.NumberField({
			fieldLabel: '<img amda_clicktip="resamplingStep" src="js/resources/images/16x16/info_mini.png"/>&nbsp;Time Step (sec)',
			labelAlign: 'top',
			labelPad: 0,
			blankText : 'Time Step is required',
			name : 'sampling',
			minValue : 0.001,
			decimalPrecision : 10,
			hideTrigger: true,
			width: 165,
			validateOnBlur: false,
			allowBlank: false,
			isValid: function() {
				var me = this,
					disabled = me.disabled,
					validate = me.forceValidation || !disabled;
				
				if (!me.isVisible()) {
					return true;
				}

				return validate ? me.validateValue(me.processRawValue(me.getRawValue())) : disabled;
			}
		});

		this.refParamField = new Ext.form.TextField({
			fieldLabel: '<img amda_clicktip="resamplingRefParam" src="js/resources/images/16x16/info_mini.png"/>&nbsp;Reference Param.',
			labelAlign: 'top',
			labelPad: 0,
			name : 'reference_param',
			width: 165,
			hidden: true,
			allowBlank: false,
			listeners: {
				afterrender: function(field, eOpts ){
					var paramTarget = new Ext.dd.DropTarget(field.el.dom,
						{
							ddGroup: 'explorerTree',
							notifyEnter: function(ddSource, e, data) {
							},
							notifyDrop: function(ddSource, e, data) {
								var selectedRecord = ddSource.dragData.records[0];
								switch (selectedRecord.$className) {
									case 'amdaModel.LocalParamNode'   :
									case 'amdaModel.RemoteParamNode'  :
									case 'amdaModel.RemoteSimuParamNode'  :
										if (!selectedRecord.get('isParameter') || selectedRecord.get('disable'))
											return false;
										if (selectedRecord.get('alias') != "" )
											field.setValue("#"+selectedRecord.get('alias'));
										else
											field.setValue(selectedRecord.get('id'));
										return true;
									case 'amdaModel.AliasNode'        :
										if (!selectedRecord.isLeaf())
											return false;
										field.setValue("#"+selectedRecord.get('text'));
										return true;
									case 'amdaModel.DerivedParamNode' :
										if (!selectedRecord.isLeaf())
											return false;
										field.setValue("ws_"+selectedRecord.get('text'));
										return true;
									case 'amdaModel.MyDataParamNode' :
										if (!selectedRecord.isLeaf())
											return false;
										field.setValue("wsd_"+selectedRecord.get('text'));
										return true;
									default:
										return false;
								}
								return true;
							}
						}
					);
				},
				scope: this
			},
			isValid: function() {
				var me = this,
					disabled = me.disabled,
					validate = me.forceValidation || !disabled;

				if (!me.isVisible()) {
					return true;
				}

				return validate ? me.validateValue(me.processRawValue(me.getRawValue())) : disabled;
			}
		});

		this.samplingDefContainer = new Ext.container.Container({
			border: false,
			items: [
				this.timeStepField,
				this.refParamField
			],
			width: 165
		});

		this.formPanel = new Ext.form.Panel(
		{
				region : 'center',  
				bodyStyle: { background : '#dfe8f6' },  
				border: false, buttonAlign: 'left',
				trackResetOnLoad: true,  //reset to the last loaded record
				layout : { 
					type : 'vbox',
					align: 'stretch',
					defaultMargins: {top: 5, left:5, bottom:10, right:10}
				},
				id: 'formSearch',
				defaults: {
					border: false
				},
				items : [
				{ 
					xtype: 'container',
					flex: 2.5,
					layout: {
							type: 'hbox',  
							align: 'stretch'
					},
					items: [
						{
							flex: 3,
							xtype: 'container',
							border: false,
							layout: {
								type: 'table',
								columns: 3
							},
							defaultType: 'textfield',
							defaults: {
								labelAlign: 'top',
								labelPad: 0
							},
							items: [   
								this.fieldName,
								{ xtype: 'component', width: 45},
								{
									fieldLabel: 'Last modification',
									xtype: 'displayfield',
									name : 'last_update',
									width: 165,
									renderer: function(value, field) {
										var tpl = new Ext.XTemplate('<p style="font-style:italic;color:gray;margin:0;">{date}</>');
										var mod_date = 'Not saved';
										if (value > 0)
											mod_date = Ext.Date.format(new Date(value*1000), "Y-m-d\\TH:i:s");
										return tpl.apply({date: mod_date});
									},
								},
								{
                                                                	xtype: 'combo',
									fieldLabel: 'Sampling mode',
									name: 'sampling_mode',
									queryMode: 'local',
									editable: false,
									valueField: 'id',
									displayField: 'name',
									store: samplingmode_store,
									value: samplingmode_store.first(),
									width: 165,
									listeners: {
										change: function(field, value) {
											this.timeStepField.setVisible(value != 'refparam');
											this.refParamField.setVisible(value == 'refparam');
										},
										scope: this
									}
								},
								{
									xtype:'component', width: 45
								},
								this.samplingDefContainer,
								{
									xtype :'displayfield', width: 165,
									hideLabel: true,
									fieldStyle: 'display:inline-block;text-align:right',
									value: '<b style="top: 50%;position: relative;">Data Gap&nbsp;<img amda_clicktip="dataGap" src="js/resources/images/16x16/info_mini.png"/></b>'
								},
								{
									xtype:'component', width: 45
								},
								{
									xtype: 'numberfield',  name: 'gap',
									fieldLabel: 'if no data for interval', minValue : 1,
									labelAlign: 'top', hideTrigger : true, width: 165
								},
								{
									xtype: 'textarea',
									name: 'description', 
									fieldLabel:'Description',
									width: 375, height: 70,
									colspan: 3
								}
							]	
						},   
						this.timeSelector
					]
				},
				this.constructionField
			],
			fbar: [
				{
					text: 'Do Search',
					scope : this,
					handler: function(button){
							// update object with user's values
							// if the return is true (object had been updated)
							if(this.updateObject()){
								// launch the search process                           
								this.doSearch();			   			 
							}
					}
				},
				{
					text: 'Save Request',
					scope: this,
					handler: function()
					{
						// update object with user's values 
						// if the return is true (object had been updated)
						if (this.updateObject())
						{
							var searchModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.search.id);	
							if (!searchModule)
								return;
							var me = this;
						
							searchModule.linkedNode.isValidName(this.fieldName.getValue(), function (res) {
								if (!res)
								{
									me.fieldName.validFlag = 'Error during object validation';
									myDesktopApp.errorMsg(me.fieldName.validFlag);
									me.fieldName.validate();
									return;
								}
						
								if (!res.valid)
								{
									if (res.error)
									{
										if (res.error.search('subtree') != -1) {  							
											Ext.MessageBox.show({title:'Warning', 
												msg: res.error+'<br/>Do you want to overwrite it?',
												width: 300,
												buttons: Ext.MessageBox.OKCANCEL, 
												fn : me.overwriteProcess,
												icon: Ext.MessageBox.WARNING,
												scope : me
											});
											me.fieldName.validFlag = true;
										}
										else
											me.fieldName.validFlag = res.error;
									}
									else
									{
										me.fieldName.validFlag = 'Invalid object name';
										myDesktopApp.errorMsg(me.fieldName.validFlag);
									}
									me.fieldName.validate();
									return;
								}
									
								me.fieldName.validFlag = true;
								me.fieldName.validate();
								me.saveProcess(false);
							});  
						}                              
					}
				},
				{
					text: 'Reset',
					scope : this,
					handler: function()
					{
						var searchModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.search.id);			
						searchModule.createLinkedNode();
						searchModule.createObject();
						this.setObject(searchModule.getLinkedNode().get('object'));                           
					}
				}
			] 
		});		
                
		var myConf = {
			layout: 'border',
			defaults: { layout: 'fit', border: false },
			items: 
			[
				this.formPanel,                         
				{
					xtype: 'panel', region: 'south',
					title: 'Information',
					collapsible: true,
					collapseMode: 'header',
					height: 100,
					autoHide: false,
					iconCls: 'icon-information',
					bodyStyle: 'padding:5px',
					loader: 
					{
						autoLoad: true,
						url: helpDir+'dataMiningHOWTO'
					}				 
				}  
			],
			plugins: [ 
				{ptype: 'calculator', myBtns:[], context: 'Condition'}, 
				{ptype: 'paramArgumentsPlugin', pluginId: 'search-param-components-plugin'}
			],
			listeners:{
				click: {
					element: 'el',
					fn: function(e,t) { 
						var me = t,
						text = me.getAttribute('amda_clicktip');
						if (text) {
							e.preventDefault();
							AmdaAction.getInfo({name : text}, function(res,e) {					    					   
								if (res.success) myDesktopApp.infoMsg(res.result);
							}); 
						}
					}
				}
			}
		};

		Ext.apply(this, Ext.apply(arguments, myConf));	    	    
	}
    
});