/*
	Created by Michael Schuijff <michael@reglobe.nl>
	Copyright Lost Images, The Netherlands
	
	For more information, visit www.michaelschuijff.nl
*/

var router = new function () {
	let router = this;
	
	let routes = [], sorted = false;
	
	let back = null;
	
	router.register = function (paths, callback) {
		if (typeof paths == 'string') {
			paths = [paths];
		}
		
		if (!Array.isArray(paths)) {
			return false;
		}
		
		for (let url of paths) {
			if (url == 'back') {
				back = callback;
				continue;
			}
			
			if (url[0] == '/') {
				url = url.substr(1);
			}
			
			routes[routes.length] = {
				url: url, path: url.split('/'), callback: callback
			}
			
			sorted = false;
		}
		
		return true;
	}
  
	router.visit = function (url) {
		if (window.cordova) {
			cordova.InAppBrowser.open(url, '_system');
		} else {
			window.open(url, '_blank');
		}
	}
	
	router.getURL = function () {
		if (window.cordova || location.protocol == 'file:') {
			let state = history.state || {};
			return state.url || '/';
		} else {
			let url = new URL(location.href);
			return url.pathname + url.search;
		}
	}
	
	router.setURL = function (path, values) {
		values = values || {};
		
		let url = strippedURL(path, values);

		if (router.getURL() == url) {
			return false;
		}
		
		if (window.cordova || location.protocol == 'file:') {
			history.replaceState(Object.assign(history.state || {}, { url: url }), '');
		} else {
			history.replaceState(history.state, '', location.protocol + '//' + location.hostname + url);
		}
		
		return true;
	}

	router.go = function (url, values, force) {
		url = strippedURL(url), values = values || {};
		
		router.canonical(url);
		
		if (!force && router.getURL() == url) {
			if (window.activeView) {
				if ('scrollBottom' in activeView) {
					activeView.scrollBottom = 0;
				} else {
					activeView.scrollTop = 0;
				}
				
				activeView.updateScroll();
			}
			
			return false;
		}
		
		if (window.cordova || location.protocol == 'file:') {
			history.pushState(Object.assign(history.state || {}, { url: url, start: false }), '');
		} else {
			history.pushState(history.state, '', location.protocol + '//' + location.hostname + url);
		}
		
		return getView(url, values);
	}
	
	router.redirect = function (url, values, force) {
		url = strippedURL(url), values = values || {};
		
		router.canonical(url);
		
		if (!force && router.getURL() == url) {
			if (window.activeView) {
				if ('scrollBottom' in activeView) {
					activeView.scrollBottom = 0;
				} else {
					activeView.scrollTop = 0;
				}
				
				activeView.updateScroll();
			}

			return false;
		}
		
		if (window.cordova || location.protocol == 'file:') {
			history.replaceState(Object.assign(history.state || {}, { url: url }), '');
		} else {
			history.replaceState(history.state, '', location.protocol + '//' + location.hostname + url);
		}

		return getView(url, values);
	}
		
	function strippedURL (url, values) {
		url = url || '/', values = values || {};
		
		let position = url.indexOf('//');
		
		if (~position) {
			url = url.substr(position + 2);
			
			{
				let position = url.indexOf('/');
				
				if (~position) {
					url = url.substr(position);
				} else {
					url = '/';
				}
			}
		}
		
		let search = encodeURIData(values);
		
		if (search) {
			if (!~url.indexOf('?')) {
				url += '?' + search;
			} else {
				url += '&' + search;
			}
		}
		
		return url;
	}
		
	let timer;
	
	function getView (url, values) {
		clearTimeout(timer);
		
		timer = setTimeout(analytics.page, 100);
		
		let view = cache.get(url);
		
		if (view) {
			loadView(view, 'resume');
		} else {
			let callback = parseURL(url, values);

			if (callback) {
				view = callback();
			}
			
			if (!view) {
				return null;
			}

			loadView(view, 'load');
		}
		
		return true;
	}
	
	function parseURL (url, values) {
		url = url || '/', values = Object.assign({}, values);
		
		if (!sorted) {
			routes.sort((a, b) => {
				return b.url.localeCompare(a.url);
			});
			
			sorted = true;
		}
		
		try {
			let parse;
			
			if (url[0] == '/') {
				parse = new URL(url, location.protocol + '//' + location.hostname);
			} else {
				parse = new URL(url);
			}
			
			let params = parse.searchParams;
			
			params.forEach((value, field) => {
				if (!(field in values)) {
					values[field] = value;
				}
			});
			
			let path = parse.pathname;
			
			if (path[0] == '/') {
				path = path.substr(1);
			}
			
			path = path.split('/');
			
			for (let route of routes) {
				if (route.path.length != path.length) {
					continue;
				}
				
				let params = {}, callback = route.callback;
				
				for (let i = 0, length = path.length; i < length; i ++) {
					if (path[i] == route.path[i]) {
						continue;
					}
					
					if (route.path[i][0] != '$') {
						callback = null;
						break;
					}
					
					params[route.path[i].substr(1)] = path[i];
				}
				
				if (callback) {
					Object.assign(values, params);
					return () => callback(values);
				}
			}
		} catch (e) {}
		
		if (url == '/404') {
			return false;
		}
		
		return parseURL('/404');
	}
	
	(function () {
		let timer;
		
		router.back = function (button) {
			button = !!button || button === undefined;

			clearTimeout(timer);
			
			if (back) {
				back();
				back = null;
				
				return;
			}
			
			if (window.activeView && button) {
				if (activeView.buttons.close && !activeView.trigger('close')) {
					return;
				}
			}
			
			let url = router.getURL().split('?')[0], minimize = false;
			
			if (url == '/') {
				minimize = true;
			} else {
				url = url.split('/').slice(0, -1).join('/') || '/';
			}

			let state = history.state || {};
			
			if (state.start) {
				if (minimize) {
					plugins.appMinimize.minimize();
				} else {
					router.redirect(url);
				}
			} else {
				timer = setTimeout(() => router.redirect(url), 100);
				history.go(-1);
			}
		}
		
		window.addEventListener('popstate', () => {
			clearTimeout(timer);
			
			let url = router.getURL();
			
			router.canonical(url);
			
			getView(url);
		});	
		
		window.addEventListener('beforeunload', () => {
			clearTimeout(timer);
		});
	})();
	
	router.canonical = function (url) {
		if (window.cordova) {
			return;
		}
		
		router.indexable();
		
		if (!~url.indexOf('//')) {
			url = config.url + url;
		}
		
		let element = document.head.querySelector('link[rel=canonical]');
		
		if (element) {
			element.href = url;
			return;
		}
		
		let link = createElement('link');
		Object.assign(link, { rel: 'canonical', href: url });
		
		document.head.append(link);
	}

	router.indexable = function () {
		if (window.cordova) {
			return;
		}

		let element = document.head.querySelector('meta[name=robots]');
		
		if (element) {
			element.remove();
		}
	}

	router.noIndex = function () {
		if (window.cordova) {
			return;
		}

		let element = document.head.querySelector('meta[name=robots]');
		
		if (element) {
			element.content = 'noindex';
			return;
		}
		
		let link = createElement('meta');
		Object.assign(link, { name: 'robots', content: 'noindex' });
		
		document.head.append(link);
	}
}

document.addEventListener('backbutton', () => router.back());

document.addEventListener('click', (e) => {
	let target = e.target;
	
	while (target.parentNode && !target.matches('a[href]')) {
		target = target.parentNode;
	}
	
	if (!target || !target.getAttribute) {
		return;
	}
	
	e.preventDefault();
	
	let href = target.getAttribute('href');
	
	if (!href) {
		return;
	}
	
	if (href.substr(0, 7) == 'mailto:') {
		return router.visit(href);
	}
	
	let host = location.protocol + '//' + location.hostname + '/';
	
	if (href[0] == '/' || href.substr(0, host.length).toLowerCase() == host.toLowerCase()) {
		router.go(href);
	} else {
		router.visit(href);
	}
});
