/**
 * 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) {
											if (data.records[0].get('predefinedArgs')) {
												searchModule.parseTemplatedParam(nameToSent, function (param_info) {
													searchModule.addParam(param_info.paramid, data.records[0].get('leaf'), true, components, param_info.template_args);
												});
											}
											else {
												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));
		}

	});