
const Module = require('./module');
const Tpl = require('./gui.xml').default;
const kebabToCamel = require('vn/string-util').kebabToCamel;
const routes = require('../../import').routes;
require('./gui.scss');

module.exports = new Class({
	Extends: Vn.Component,
	Properties: {
		conn: {
			type: Db.Connection
			,set(x) {
				this.link({_conn: x}, {'loading-changed': this._onConnLoadChange });
			}
			,get() {
				return this._conn;
			}
		}
	}

	,forms: {}
	,activeForm: null
	,activeCss: null
	,requestedForm: null
	,menuShown: false
	,menuOptions: {}
	,choosedOption: null
	,_shown: false
	,_scrollTimeout: null
	,_navbarVisible: true

	,initialize(props) {
		this.loadTemplateFromString(Tpl);
		this.loadingCount = 0;

		this.$.background.onclick = function() {};

		this.$.leftPanel.addEventListener('click', function(event) {
			event.stopPropagation();
		});

		Vn.Component.prototype.initialize.call(this, props);
	}
	
	,async show() {
		if (this._shown) return;
		this._shown = true;

		this.doc.body.appendChild(this.node);
		Htk.Toast.pushTop(this.$.formHolder);

		await this.refreshUserData();
		Vn.Node.setText(this.$.userName, this.user.nickname);

		const resultSet = await this._conn.execQuery(
			 'SELECT defaultForm FROM config;'
			+'SELECT url FROM imageConfig;'
			+'SELECT dbproduccion FROM vn.config;'
			+'SELECT productionDomain, testDomain FROM config;'
		);

		// Retrieving configuration parameters

		Vn.Config.defaultForm = resultSet.fetchValue();
		Vn.Config.imageUrl = resultSet.fetchValue();

		// Retrieving configuration parameters

		const isTesting = !resultSet.fetchValue();

		if (isTesting) {
			this.$.devInfo.style.display = 'block';
			this.$.version.textContent = Vn.Cookie.get('vnVersion');
		}

		// Retrieving configuration parameters

		const res = resultSet.fetchObject();

		if (res && res.testDomain) {
			let linkText, linkField;

			if (location.host != res.productionDomain) {
				linkText = 'Old website';
				linkField = 'productionDomain';
			} else {
				linkText = 'Test the new website';
				linkField = 'testDomain';
			}
			
			Vn.Node.setText(this.$.testLink, _(linkText));
			this.$.testLink.href = '//'+ res.get(linkField);
			this.$.testLink.style.display = 'block';
		} else
			this.$.testLink.style.display = 'none';

		await this.loadMenu();
		
		if (Vn.isMobile()) {
			this._onScrollHandler = this._onScroll.bind(this);
			window.addEventListener('scroll', this._onScrollHandler );
		}

		await this.supplantInit();

		this.formParam = new Vn.Param({
			lot: this.hash,
			name: 'form',
		});
		this.formParam.on('changed', this._onFormChange, this);
		await this._onFormChange();

		if (!localStorage.getItem('hederaCookies')) {
			localStorage.setItem('hederaCookies', true);
			Htk.Toast.showWarning(_('By using this site you accept cookies'));
		}
	}

	,async refreshUserData() {
		const resultSet = await this._conn.execQuery(
			'SELECT id, name, nickname FROM account.myUser');
		this.user = resultSet.fetchObject();
	}
	
	,async hide() {
		if (!this._shown)
			return;
	
		this._shown = false;

		if (Vn.isMobile())
			window.removeEventListener('scroll', this._onScrollHandler);

		Htk.Toast.popTop();
		if (this.formParam) {
			this.formParam.unref();
			this.formParam = null;
		}
		await this.closeForm();
		this.hideMenu();
		Vn.Node.remove(this.node);
	}
	
	,async logout() {
		await this.onLogoutClick();
	}
	
	,async onLogoutClick() {
		try {
			if (!localStorage.getItem('hederaGuest'))
				this._conn.close();
		} finally {
			this.emit('logout');
		}
	}

	,_onConnLoadChange(conn, isLoading) {
		if (isLoading)
			this.loaderPush();
		else
			this.loaderPop();
	}
	
	,async loadMenu() {
		const resultSet = await this._conn.execQuery('SELECT * FROM myMenu');

		// Retrieving menu sections		

		var res = resultSet.fetchData();	
		var sectionMap = {};
		let i = 0;

		for (const row of res) {
			var parent = row.parentFk;
			
			if (!sectionMap[parent])
				sectionMap[parent] = [];
				
			sectionMap[parent].push(i++);
		}

		Vn.Node.removeChilds(this.$.mainMenu);
		this.createMenu(res, sectionMap, null, this.$.mainMenu);
	}

	//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Menu

	,createMenu(res, sectionMap, parent, ul) {
		var sections = sectionMap[parent];
		if (!sections) return;

		for (var i = 0; i < sections.length; i++) {
			res.row = sections[i];
			const row = res[sections[i]];
		
			var li = this.createElement('li');
			ul.appendChild(li);
	
			var text = this.createTextNode(_(row.description));

			var a = this.createElement('a');
			
			if (row.path) {
				a.href = this.hash.make({form: row.path});
				this.menuOptions[row.path] = a;
			}

			a.appendChild(text);
			li.appendChild(a);
			
			var formId = row.id;
			
			if (sectionMap[formId]) {
				var submenu = this.createElement('ul');
				submenu.className = 'submenu';
				li.appendChild(submenu);

				li.addEventListener('mouseover',
					this._onLiMouseHover.bind(this, submenu, a));
				li.addEventListener('mouseout',
					this._onLiMouseOut.bind(this));

				this.createMenu(res, sectionMap, formId, submenu);
			}
		}
	}

	,_onLiMouseHover(submenu, parent) {
		if (this.menuShown)
			return;

		this.hideSubmenu();
		this.activeSubmenu = submenu;

		var rect = parent.getBoundingClientRect();
		Vn.Node.addClass(submenu, 'popup');
		submenu.style.left = rect.right +'px';
		submenu.style.top = rect.top +'px';
	}
	
	,_onLiMouseOut() {
		this.timeout = setTimeout(this.hideSubmenu.bind(this), 160);
	}
	
	,hideSubmenu() {
		var submenu = this.activeSubmenu;
	
		if (submenu) {
			Vn.Node.removeClass(submenu, 'popup');
			submenu.style.left = '';
			submenu.style.top = '';
			clearTimeout(this.timeout);
			this.activeSubmenu = null;
			this.timeout = 0;
		}
	}

	,onMenuClick(event) {
		event.stopPropagation();
		this.showMenu();
	}

	,showMenu() {
		this.showBackground();
		Vn.Node.addClass(this.$.leftPanel, 'show');
		this.menuShown = true;

		this.hideMenuCallback = this.hideMenu.bind(this);
		this.doc.addEventListener('click', this.hideMenuCallback);
	}

	,hideMenu() {
		if (!this.menuShown)
			return;
	
		this.hideBackground();
		Vn.Node.removeClass(this.$.leftPanel, 'show');
		this.menuShown = false;
		
		this.doc.removeEventListener('click', this.hideMenuCallback);
		this.hideMenuCallback = null;
	}

	//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Navigation bar
	
	,_onScroll() {
		if (this._scrollTimeout === null)
			this._scrollTimeout = setTimeout(
				this._scrollTimeoutFunc.bind(this), 150);
	}
	
	,_scrollTimeoutFunc() {
		if (!this._shown)
			return;
		
		var navbar = this.$.topBar;
		var yOffset = Vn.Browser.getPageYOffset();
		var showNavbar = this._lastYOffset > yOffset || yOffset < navbar.offsetHeight;
		
		if (showNavbar !== this._navbarVisible) {
			if (showNavbar)
				var translateY = 0;
			else
				var translateY = -navbar.offsetHeight;

			navbar.style.transform =
				'translateZ(0) translateY('+ translateY +'px)';
		}
		
		this._navbarVisible = showNavbar;
		this._lastYOffset = yOffset;
		this._scrollTimeout = null;
	}

	//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Background

	,showBackground() {
		Vn.Node.addClass(this.$.background, 'show');
	}

	,hideBackground() {
		Vn.Node.removeClass(this.$.background, 'show');
	}

	//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Spinner
	
	,loaderPush() {
		this.loadingCount++;

		if (this.loadingCount == 1)
			this.$.loader.start();
	}
	
	,loaderPop() {
		if (this.loadingCount == 0)
			return;
		
		this.loadingCount--;
		
		if (this.loadingCount == 0)
			this.$.loader.stop();
	}
	
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forms
	
	,async _onFormChange() {
		var formPath = this.formParam.value;
		
		if (!formPath)
			formPath = Vn.Config.defaultForm;
		
		this.hideMenu();
		await this.closeForm();
		this.requestedForm = formPath;

		if (!formPath) return;
		this.loaderPush();
		const newChoosedOption = this.menuOptions[formPath];
		
		if (newChoosedOption) {
			Vn.Node.addClass(newChoosedOption, 'selected');
			this.choosedOption = newChoosedOption;
		}

		await Vn.Locale.load(`forms/${formPath}`);

		let FormKlass;
		
		try {
			FormKlass = (await this.importForm(formPath)).default;
		} catch (err) {
			this.loaderPop();
			console.log(err);
			return Htk.Toast.showError(_('Error loading form') +`: ${err.message}`);
		}

		this.loaderPop();

		if (!this._shown)
			return;

		this.activeForm = new FormKlass(this);
		await this.activeForm.open();
	}

	,async importForm(path) {
		const states = path.split('/');
		let importFn = routes;
		for (let i = 0; i < states.length && importFn; i++)
			importFn = importFn[kebabToCamel(states[i])];
		if (!importFn)
			throw new Error(`Route '${path}' does not exist`);
		return importFn();
	}
	
	,setForm(form) {
		const holder = this.$.formHolder;
		Vn.Node.removeChilds(holder);

		if (form) {
			holder.appendChild(form);
			holder.classList.add('move-start');
			setTimeout(() => this._onSetFormTimeout(), 10);
		}
	}
	
	,_onSetFormTimeout() {
		const holder = this.$.formHolder;
		holder.classList.remove('move-start');
		holder.classList.add('move-end');
		holder.addEventListener('transitionend',
			() => holder.classList.remove('move-end'),
			{once: true}
		);
	}
	
	,setTitle(title) {
		Vn.Node.removeChilds(this.$.title);
	
		if (title)
			this.$.title.appendChild(title);
	}
	
	,setActions(actions) {
		Vn.Node.removeChilds(this.$.actionBar);
				
		if (actions)
			this.$.actionBar.appendChild(actions);
	}
	
	,async closeForm() {
		if (this.activeForm) {
			Vn.Node.removeClass(this.$.formHolder, 'show');
			await this.activeForm.close();
			this.activeForm._destroy();
			this.activeForm = null;
		}

		if (this.activeCss) {
			Vn.excludeCss(this.activeCss);
			this.activeCss = null;
		}

		if (this.choosedOption) {
			Vn.Node.removeClass(this.choosedOption, 'selected');
			this.choosedOption = null;
		}
	}
	
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Reports
	
	,async openReport(reportName, lot) {
		try {
			this.loaderPush();
			const module = new Module('reports', reportName);
			await module.load();
		
			const report = new module.klass(module, this);
			report.open(lot);
		} catch(err) {
			Htk.Toast.showError(_('Error loading report'));
		} finally {
			this.loaderPop();
		}
	}
	
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Supplant

	/**
	 * Supplants another user.
	 *
	 * @param {String} supplantUser The user name
	 */
	,async supplantUser(supplantUser) {
		const json = await this._conn.send('client/supplant', {supplantUser});
		this._conn.token = json;
		sessionStorage.setItem('supplantUser', supplantUser);

		await this.refreshUserData();
		Vn.Node.setText(this.$.supplanted, this.user.nickname);
		this.$.supplant.classList.toggle('show', true);
		await this.loadMenu();
	}

	/*
	 * Ends the user supplanting and restores the original login.
	 */
	,async onSupplantExitClick() {
		this._conn.post('Accounts/logout');
		this._conn.fetchToken();
		sessionStorage.removeItem('supplantUser');

		this.$.supplant.classList.toggle('show', false);
		await this.refreshUserData();
		await this.loadMenu();
		this._onFormChange();
	}
	
	,async supplantInit() {
		var user = sessionStorage.getItem('supplantUser');
		if (user == null) return;
		await this.supplantUser(user);
	}
	
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Destroy

	,_destroy() {
		this.hide();
		Vn.Component.prototype.initialize.call(this);
	}
});
