/**
 * Project  : AMDA-NG
 * Name	 : EpnTapModule.js
 * @class   amdaDesktop.EpnTapModule
 * @extends amdaDesktop.AmdaModule
 * @brief   EpnTap Module controller definition
 * @author  Nathanael Jourdane
 */

Ext.define('amdaDesktop.EpnTapModule', {

	extend: 'amdaDesktop.AmdaModule',
	requires: ['amdaUI.EpnTapUI'],
	// contentId : 'EpnTapUI',

	/** The alias name of the module view. */
	uiType: 'panelEpnTap',

	/** The text displayed on the *help button* tooltip. */
	helpTitle: 'Help on EPN-TAP Module',

	/** The name of the documentation file related to the module. */
	helpFile : 'epnTapHelp',

	/**
	Module initialisation.
	*/
	init: function() {
		this.select = Array();
		this.filter = Array();
		this.selectedServiceId = null;

		this.launcher = {
			text: this.title,
			iconCls: this.icon,
			handler: this.createWindow,
			scope: this
		};
	},

	/**
	Capitalize a name and replace underscores with spaces.
	- `name`: The string to make pretty.
	*/
	prettify: function(name) {
		return name.charAt(0).toUpperCase() + name.replace(/_/g, ' ').substr(1).toLowerCase();
	},

	/**
	Capitalize a name, replace underscores with spaces, and write it in a plurial form.
	- `name`: The string to make pretty.
	*/
	allPrettify: function(name) {
		return 'All ' + (name[name.length-1] == 's' ? name : name + 's').replace(/_/g, ' ').toLowerCase();
	},

	isDate: function(date) {
		if (date === null) {
			return false;
		}
		var dateArr = date.split('/');
		if (dateArr.length != 3 || isNaN(parseInt(dateArr[0])) || isNaN(parseInt(dateArr[1])) || isNaN(parseInt(dateArr[2])) ) {
			return false;
		}
	return true;
	},

	/****************************
	*** Service filter events ***
	****************************/

	createWindow: function (icon_id) {
		this.callParent();
		this.epnTapPanel.setSize(800, 600);

		var icons_dic = {
			'icon-mercury': ['ts', 'planet', 'mercury'],
			'icon-venus': ['ts', 'planet', 'venus'],
			'icon-earth': ['ts', 'planet', 'earth'],
			'icon-mars': ['ts', 'planet', 'mars'],
			'icon-jupiter': ['ts', 'planet', 'jupiter'],
			'icon-saturn': ['ts', 'planet', 'saturn'],
			'icon-comet': ['ts', 'comet', 'comet'],
			'icon-sw': ['ts', 'interplanetary_medium', 'all'],
			'icon-solarsystem': ['ts', 'interplanetary_medium', 'all']
		}

		var target = icons_dic[icon_id];
		// console.log("target: ", target);
		this.initWindow(target);
	},

	/**
	Trigerred after the render of `gridsPanel` (containing `servicesGrid` and `granulesGrid`). Among other things,
	initializes the `productType` combobox and the `servicesGrid` table.
	- `target`: an array of 3 values: [dataproduct_type, target_class, target_name]; or null.
	*/
	initWindow: function(target) {
		Ext.data.StoreManager.lookup('servicesStore').on('add', function() { this.updateNbResults(); }, this);
		Ext.data.StoreManager.lookup('servicesStore').load();
		Ext.data.StoreManager.lookup('metadataStore').load();

		this.productTypeCB = Ext.getCmp('epnTapProductTypeCB');
		this.targetClassCB = Ext.getCmp('epnTapTargetClassCB');
		this.targetNameCB = Ext.getCmp('epnTapTargetNameCB');
		this.timeSelector = Ext.getCmp('epnTapTimeSelector');
		this.rowsPerPageNf = Ext.getCmp('epnTapRowsPerPageNf');
		this.servicesGrid = Ext.getCmp('epnTapServicesGrid');
		this.granulesGrid = Ext.getCmp('epnTapGranulesGrid');
		this.currentPageLb = Ext.getCmp('epnTapCurrentPageLb');
		this.totalPagesLb = Ext.getCmp('epnTapTotalPagesLb');
		this.firstPageBtn = Ext.getCmp('epnTapFirstPageBtn');
		this.previousPageBtn = Ext.getCmp('epnTapPreviousPageBtn');
		this.nextPageBtn = Ext.getCmp('epnTapNextPageBtn');
		this.lastPageBtn = Ext.getCmp('epnTapLastPageBtn');
		this.epnTapPanel = this.productTypeCB.findParentByType('panelEpnTap');

		// If the EPN-TAP module is launched from the AMDA tree
		if(target) {
			// --- Select product types ---
			if (! target[0] in this.productTypeCB.getStore()) {
				alert("Sorry, product type " + target[0] + " is not found in available services.");
				return;
			}
			this.productTypeCB.select(target[0]);
			this.onProductTypeCBChanged(); // Fill target class CB

			// --- Select target class ---
			if (! target[1] in this.targetClassCB.getStore()) {
				alert("Sorry, target class " + this.pretify(target[1]) + " is not found in available services.");
				return;
			}
			this.targetClassCB.select(target[1]);
			this.onTargetClassCBChanged();

			// --- Select target name ---
			if (! target[2] in this.targetNameCB.getStore()) {
				alert("Sorry, target name " + this.pretify(target[2]) + " is not found in available services.");
				return;
			}
			this.targetNameCB.select(target[2]);
			this.onTargetNameCBChanged();

		// If the EPN-TAP module is launched from the Interop window
		} else {
			this.productTypeCB.select('all');

			// Update targetClassCB
			this.targetClassCB.getStore().add({'id': 'all', 'name': 'All target classes'});
			this.targetClassCB.select('all');
			this.targetClassCB.disable();

			// Update targetNameCB
			this.targetNameCB.getStore().add({'id': 'all', 'name': 'All target names'});
			this.targetNameCB.select('all');
			this.targetNameCB.disable();
		}
	},

	/**
	Trigerred when *the user* (not `productTypeCB.select()`) select a new item in `productTypeCB`
	(see `EpnTapUI.createProductTypeCB()`).
	Among other things, updates the `targetClassCB` combobox and the `servicesGrid` table.
	*/
	onProductTypeCBChanged: function() {
		this.targetClassCB.getStore().removeAll();
		this.targetNameCB.getStore().removeAll();
		this.targetNameCB.disable();

		if (this.productTypeCB.value == 'all') {
			this.targetClassCB.disable();
		} else {
			Ext.data.StoreManager.lookup('metadataStore').filter('dataproduct_type', this.productTypeCB.value)
			var targetClasses = Ext.data.StoreManager.lookup('metadataStore').collect('target_class');

			if (targetClasses.length == 1) {
				this.targetClassCB.getStore().add({'id': targetClasses[0], 'name': this.prettify(targetClasses[0])});
				this.targetClassCB.disable();
				this.targetClassCB.select(this.targetClassCB.getStore().getAt(0)['internalId']);
			} else {
				this.targetClassCB.getStore().add({'id': 'all', 'name': this.allPrettify(productTypeDict[this.productTypeCB.value])});
				for (var i = 0; i < targetClasses.length; i++) {
					this.targetClassCB.getStore().add({'id': targetClasses[i], 'name': this.prettify(targetClasses[i])});
				}
				this.targetClassCB.select('all');
				this.targetClassCB.enable();
			}
		}
		this.targetNameCB.getStore().add({'id': 'all', 'name': 'All target names'});
		this.targetNameCB.select('all');
		this.updateNbResults();
	},

	/**
	Trigerred when *the user* (not `targetClassCB.select()`) select a new item in `targetClassCB` (see
	`EpnTapUI.createTargetClassCB()`).
	Among other things, updates the `targetNameCB` combobox and the `servicesGrid` table.
	*/
	onTargetClassCBChanged: function() {
		this.targetNameCB.getStore().removeAll();

		if (this.targetClassCB.value == 'all') {
			this.targetNameCB.getStore().add({'id': 'all', 'name': 'All target names'});
			this.targetNameCB.select('all');
			this.targetNameCB.disable();
		} else {
			Ext.data.StoreManager.lookup('metadataStore').filter('target_class', this.targetClassCB.value);
			var targetNames = Ext.data.StoreManager.lookup('metadataStore').collect('target_name');
			if (targetNames.length == 1) {
				this.targetNameCB.getStore().add({'id': targetNames[0], 'name': this.prettify(targetNames[0])});
				this.targetNameCB.select(this.targetNameCB.getStore().getAt(0)['internalId']);
				this.targetNameCB.disable();
			} else {
				this.targetNameCB.getStore().add({'id': 'all', 'name': this.allPrettify(this.targetClassCB.value)});
				for (var i = 0; i < targetNames.length; i++) {
					this.targetNameCB.getStore().add({'id': targetNames[i], 'name': this.prettify(targetNames[i])});
				}
				this.targetNameCB.select('all');
				this.targetNameCB.enable();
			}
		}
		this.updateNbResults();
	},

	/**
	Trigerred when *the user* (not `targetClassCB.select()`) select a new item in `targetNameCB`
	(see `EpnTapUI.createTargetNameCB()`).
	Updates the `servicesGrid` table.
	*/
	onTargetNameCBChanged: function() {
		this.updateNbResults();
	},

	/**
	Trigerred when the value of `rowsPerPageNf` is updated (see `EpnTapUI.createRowsPerPageNf()`). Do nothing yet, used
	for debug purposes only.
	*/
	onRowsPerPageChanged: function() {
		// console.log("rows per page: " + this.productTypeCB);
	},

	/*********************
	*** Buttons events ***
	*********************/

	/**
	Disable or enable the navigation buttons (see `EpnTapUI.createNavigationPanel()`).
	*/
	disableNavBtns: function(firt, previous, next, last) {
		Ext.getCmp('epnTapFirstPageBtn').setDisabled(firt);
		Ext.getCmp('epnTapPreviousPageBtn').setDisabled(previous);
		Ext.getCmp('epnTapNextPageBtn').setDisabled(next);
		Ext.getCmp('epnTapLastPageBtn').setDisabled(last);
	},

	/**
	Trigerred when the `firstPageBtn` button is clicked (see `EpnTapUI.createNavigationPanel()`). Among other things,
	send a new query and fill `granulesGrid`.
	*/
	onFirstPageBtnClicked: function() {
		var newPageNumber = 1;
		var limit = Number(this.rowsPerPageNf.value);
		var offset = 0;
		var selectedServiceURL = Ext.data.StoreManager.lookup('servicesStore').getById(this.selectedServiceId)['accessurl'];

		this.wait();
		this.disableNavBtns(true, true, false, false);
		this.currentPageLb.setText('' + newPageNumber);
		AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules);
	},

	/**
	Trigerred when the `previousPageBtn` button is clicked (see `EpnTapUI.createNavigationPanel()`). Among other things,
	send a new query and fill `granulesGrid`.
	*/
	onPreviousPageBtnClicked: function() {
		var newPageNumber = Number(this.currentPageLb.text) - 1;
		var limit = Number(this.rowsPerPageNf.value);
		var offset = (newPageNumber-1) * limit;
		var selectedServiceURL = Ext.data.StoreManager.lookup('servicesStore').getById(this.selectedServiceId)['accessurl'];

		this.wait();
		this.currentPageLb.setText('' + newPageNumber);
		var isFirstPage = this.currentPageLb.text === '1';
		this.disableNavBtns(isFirstPage, isFirstPage, false, false);
		AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules);
	},

	/**
	Trigerred when the `nextPageBtn` button is clicked (see `EpnTapUI.createNavigationPanel()`). Among other things,
	send a new query and fill `granulesGrid`.
	*/
	onNextPageBtnClicked: function() {
		var newPageNumber = Number(this.currentPageLb.text) + 1;
		var limit = Number(this.rowsPerPageNf.value);
		var offset = (newPageNumber-1) * limit;
		var selectedServiceURL = Ext.data.StoreManager.lookup('servicesStore').getById(this.selectedServiceId)['accessurl'];

		this.wait();
		this.currentPageLb.setText('' + newPageNumber);
		var isLastPage = this.currentPageLb.text == this.totalPagesLb.text;
		this.disableNavBtns(false, false, isLastPage, isLastPage);
		AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules);
	},

	/**
	Trigerred when the `lastPageBtn` button is clicked (see `EpnTapUI.createNavigationPanel()`). Among other things,
	send a new query and fill `granulesGrid`.
	*/
	onLastPageBtnClicked: function() {
		var newPageNumber = Number(this.totalPagesLb.text);
		var limit = Number(this.rowsPerPageNf.value);
		var offset = (newPageNumber-1) * limit;
		var selectedServiceURL = Ext.data.StoreManager.lookup('servicesStore').getById(this.selectedServiceId)['accessurl'];

		this.wait();
		this.currentPageLb.setText('' + newPageNumber);
		this.disableNavBtns(false, false, true, true);
		AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules);
	},

	/*******************
	*** Grids events ***
	*******************/

	/**
	Trigerred when a row is clicked in `servicesGrid` table (see `EpnTapUI.createServicesGrid()`). Among other things,
	send a new query and fill `granulesGrid`.
	*/
	onServiceSelected: function(selectedServiceId) {
		// console.log("Selected service " + selectedServiceId);
		this.wait();
		this.selectedServiceId = selectedServiceId;
		this.select = Array();

		var selectedService = Ext.data.StoreManager.lookup('servicesStore').findRecord('id', selectedServiceId).data;
		console.log(selectedService);
		if (selectedService == null) {
			throw this.selectedServiceId + ' not found in the list of services.';
			return;
		}

		var columns = selectedService['columns'].split(',');
		for (var ic=0 ; ic<this.granulesGrid.columns.length ; ic++) {
			if (columns.indexOf(this.granulesGrid.columns[ic].dataIndex) != -1) {
				this.select.push(this.granulesGrid.columns[ic].dataIndex);
			}
		}
		this.filter = Array(
			this.productTypeCB.value === 'all' ? null : this.productTypeCB.value, // product type
			this.targetNameCB.value === 'all' ? null : this.targetNameCB.value, // target name
			Ext.Date.format(this.timeSelector.getStartTime(), 'd/m/Y H:i:s'), // start time
			Ext.Date.format(this.timeSelector.getStopTime(), 'd/m/Y H:i:s') // stop time
		);

		// console.log(selectedServiceId, selectedService['access_url'], this.filter);
		AmdaAction.epnTapGetNbRows(selectedServiceId, selectedService['access_url'], this.filter, this.updateNbRows);
		AmdaAction.epnTapGetGranules(selectedServiceId, selectedService['access_url'], this.filter, this.select, this.rowsPerPageNf.value, 0, this.fillGranules);
	},

	/**
	Trigerred when a row is clicked in `granulesGrid` table (see `EpnTapUI.createGranulesGrid()`). Do nothing yet, used
	for debug purposes only.
	*/
	onGranuleSelected: function(granule) {
		// console.log('selected granule: ', granule);
	},

	/**********************
	*** Other functions ***
	**********************/

	/**
	Update the nb_result field of the services store (see `EpnTapUI.servicesStore`), according to the field values in `serviceFilterPanel`.
	*/
	updateNbResults: function() {
		var productType = Ext.getCmp('epnTapProductTypeCB').value;
		var targetClass = Ext.getCmp('epnTapTargetClassCB').value;
		var targetName = Ext.getCmp('epnTapTargetNameCB').value;
		var metadataStore = Ext.data.StoreManager.lookup('metadataStore');
		var servicesStore = Ext.data.StoreManager.lookup('servicesStore');
		var timeSelector = Ext.getCmp('epnTapTimeSelector');

		if(productType === 'all' && !this.launchedFromTree ) {
			var filter = [];
		} else if(targetClass === 'all') {
			var filter = [
				{property: "dataproduct_type", value: productType}
			];
		} else if(targetName === 'all') {
			var filter = [
				{property: "dataproduct_type", value: productType},
				{property: "target_class", value: targetClass}
			];
		} else {
			var filter = [
				{property: "dataproduct_type", value: productType},
				{property: "target_class", value: targetClass},
				{property: "target_name", value: targetName}
			];
		}

		servicesStore.each(function(record, idx) {
			metadataStore.filter(filter.concat({property: 'service_id', value: record.get('id')}));
			record.set('nb_results', metadataStore.sum('nb_results'));
			metadataStore.clearFilter();
		});
		servicesStore.sort('nb_results', 'DESC');

		var timeMin = metadataStore.min('time_min');
		var timeMax = metadataStore.max('time_max');
		timeSelector.setLimits(timeMin, timeMax);
		timeSelector.setInterval(timeMin, timeMax);
	},

	/**
	Callback function, called from the PHP script when the query result is received, when a service is selected.

	Among other things, update the `epnTapCurrentPageLb` label (see `EpnTapUI.createNavigationPanel()`).
	*/
	updateNbRows: function(nb_results) {
		var totalPages = Math.ceil(Number(nb_results) / Ext.getCmp('epnTapRowsPerPageNf').value);

		Ext.getCmp('epnTapCurrentPageLb').setText(totalPages == 0 ? '-' : '1');
		Ext.getCmp('epnTapTotalPagesLb').setText(totalPages == 0 ? '-' : totalPages);

		Ext.getCmp('epnTapPreviousPageBtn').setDisabled(true);
		Ext.getCmp('epnTapFirstPageBtn').setDisabled(true);
		Ext.getCmp('epnTapNextPageBtn').setDisabled(totalPages <= 1);
		Ext.getCmp('epnTapLastPageBtn').setDisabled(totalPages <= 1);
	},

	/**
	Callback function, called from the PHP script when the query result is received, when a service is selected or a
	navigation button is clicked.

	Among other things, fill the `epnTapGranulesGrid` table (see `EpnTapUI.granulesStore`).
	*/
	fillGranules: function(granules) {
		if (granules["error"] != null) {
			console.log('Can not get request response:', granules["error"]);
		} else {
			try {
				Ext.getCmp('epnTapGranulesGrid').getStore().removeAll();
				Ext.getCmp('epnTapGranulesGrid').getStore().add(granules);
			} catch( e ) {
				console.log('Can not add granules: ' + e);
			}
		}
		Ext.getCmp('epnTapServicesGrid').setDisabled(false);
		Ext.getCmp('epnTapGranulesGrid').setDisabled(false);
		Ext.getCmp('epnTapServicesGrid').getEl().setStyle('cursor', 'default'); // CSS is correctly changed but without visible result.
	},

	/**
	Called before to send a query. Set the EpnTap panel in "waiting mode", informing to the user that a request is
	processing. The altered elements are resetted in `fillGranules()`.
	*/
	wait: function() {
		this.servicesGrid.getEl().setStyle('cursor', 'wait');  // CSS is correctly changed but without visible result.
		this.servicesGrid.setDisabled(true);
		this.granulesGrid.setDisabled(true);
	}

});