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

router.register('/post', () => {
	router.redirect('/');
});

router.register(['/post/$id', '/post/$id/$comment'], (values) => {
	if (!config.user && values.comment) {
		if (!config.bot) {
			router.redirect('/login', { url: router.getURL() });
		} else {
			router.noIndex();
		}

		return;
	}
	
	let url = '/post/' + values.id, urls = [url];
	
	if (values.comment) {
		url += '/' + values.comment, urls[1] = url;
	}
	
	let view = createView({
		titleBar: __('Post'), hideMainTitleBar: true, hideBottomMenu: true, buttons: ['close'], urls: urls, spinner: true, pullToRefresh: true
	});
	
	let req;
	
	function fetchPost () {
		let url;
		
		if (config.user) {
			url = '/comments/' + values.id;
		} else {
			url = '/post/' + values.id;
		}
		
		req = api.get({
			url: url,
			data: { include_post: true, comment_id: values.comment },
			success: (result) => {
				view.content.innerHTML = '';
				
				view.content.append(renderPost(result.post));
				
				setTimeout(view.videoElements, 0);
				
				if (config.user) {
					let comments = renderComments(result, result.post);	
					view.content.append(comments);
					
					if (values.comment) {
						let element = comments.querySelector('.comment-' + values.comment);
						
						if (element) {
							let rect = element.getBoundingClientRect();
							
							view.scrollTop += rect.top - (window.innerHeight - rect.height) / 2;
							view.updateScroll();
						}
						
						delete values.comment;
					}
				}
				
				view.hideSpinner();
				view.revertPullToRefresh();
			},
			error: () => {
				toast(__('Post not found.'));
				
				if (config.bot) {
					router.go('/404');
				} else {
					router.back();
				}
				
				view.destroy();
			},
			complete: () => req = null
		});
	}
	
	view.register('load', () => {
		fetchPost();
	});
	
	view.register('pause', () => {
		let elements = view.content.querySelectorAll('.edit-comment');
		
		for (let element of elements) {
			element.remove();
		}
	});
	
	view.register('resume', () => {
		refreshPostsCount(view.content);
	});

	view.register('refresh', () => {
		if (req) {
			req.abort();
		}
		
		view.spinner();
		fetchPost();
	});
	
	view.register('refresh destroy', () => {
		let elements = view.content.querySelectorAll('[data-blob-url]');
		
		for (let element of elements) {
			URL.revokeObjectURL(element.getAttribute('data-blob-url'));
		}
	});
	
	return view;		
});
	
function renderPost (post) {
	let container = createElement('div', 'post post-' + post.id + ' user-' + post.user.id);
	
	if (~post.permissions.indexOf('edit')) {
		container.className += ' permission-edit';
	}
	
	if (~post.permissions.indexOf('delete')) {
		container.className += ' permission-delete';
	}
	
	{
		let profile = renderUser(post.user, ['follow', 'menu']);
		container.append(profile);

		let button = profile.querySelector('.button-menu');
		
		button.onclick = () => {
			let user = post.user, currentUser = false;
			
			if (config.user && config.user.id == user.id) {
				currentUser = true;
			}
			
			contextMenu(button, [
				{
					text: __('Share post'),
					hidden: !navigator.share,
					click: () => {
						let url = config.url + '/post/' + post.id;
						
						navigator.share({ url: url });
						analytics.push('share', { item_id: url });;
					}
				}, {
					text: __('Edit post'),
					hidden: !~post.permissions.indexOf('edit'),
					click: () => router.go('/post/' + post.id + '/edit', { type: post.type })
				}, {
					text: __('Delete post'),
					hidden: !~post.permissions.indexOf('delete'),
					click: () => {
						api.confirm(__('Are you sure you want to delete this post?'), () => {
							api.delete({
								url: '/post/' + post.id,
								success: removeRenderPost
							});
						});
					}
				}, {
					text: __('Hide this post'),
					hidden: !config.user || currentUser,
					click: () => {
						api.post({
							url: '/post/' + post.id + '/hide',
							error: false
						});
						
						removeRenderPost();
						toast(__('This post is now hidden.'));
					}
				}, {
					text: __('Subscribe to user'),
					hidden: !config.user || currentUser || user.subscribed,
					click: () => api.subscribe(user.id)
				}, {
					text: __('Unsubscribe from user'),
					hidden: !config.user || currentUser || !user.subscribed,
					click: () => api.unsubscribe(user.id)
				}, {
					text: __('Report user or post'),
					hidden: !config.user || currentUser || post.type == 'badge',
					href: '/report/post/' + post.id
				}, {
					text: __('Unfollow user'),
					hidden: !config.user || user.following != 'yes',
					click: () => api.unfollow(user.id)
				}, {
					text: __('Cancel follow'),
					hidden: !config.user || user.following != 'pending',
					click: () => api.cancel(user.id)
				}, {
					text: __('Block user'),
					hidden: !config.user || currentUser,
					click: () => {
						api.confirm(__('Are you sure you want to block %s?', getUserName(user.id)), () => {
							api.block(user.id);
						});
					}
				}
			]);
		}
	}
	
	if (post.images) {
		container.append(renderGallery());
	}

	if (post.type == 'video') {
		container.append(renderVideo());
	}
	
	if (post.type == 'post' && post.url && !post.images) {
		container.append(renderURL());
	}
		
	if (post.badge) {
		let html;
		
		html  = _e('%s has been promoted to', getUserName(post.user)) + ' ';
		html += '<span>' + _e(post.badge.badge) + '</span> ';
		html += _e('for reaching the goal of %d followers', post.badge.goal);
		
		let badge = createElement('div', 'badge uppercase');
		badge.innerHTML = html;
		
		container.className += ' has-badge';
		container.append(badge);
	}

	if (post.text) {
		let content = createElement('div', 'content');
		content.innerHTML = post.text;
		
		container.append(content);
	}	

	if (post.poll) {
		if (post.poll.closed || post.poll.voted) {
			container.append(renderPollScore());
		} else {
			container.append(renderPollVote());			
		}
	}
	
	if ('post' in post && post.post) {
		let content = renderPost(post.post);
		content.querySelector('.buttons').remove();
		
		container.append(content);
	}
	
	if ('post' in post && !post.post) {
		container.append(createElement('div', 'post missing', __('This post is not available.')));
	}
		
	let buttons = createElement('div', 'buttons');
	
	{
		let button = createElement('button', 'button-comment');
		button.value = post.comment_count || 0;
		
		button.onclick = () => {
			if (!config.user) {
				router.go('/login', { url: '/post/' + post.id });
				return;
			}
			
			if (config.offline) {
				toast(__('You are currently offline.'));
				return;
			}
			
			let state = history.state || {}, url = state.url || location.pathname;
			
			if (~url.indexOf('/post/' + post.id)) {
				return;
			}
			
			if (config.mobile) {
				router.go('/comments/' + post.id);	
			} else {
				router.go('/post/' + post.id);
			}
		}
		
		buttons.append(button, createElement('span', 'count count-comment', formatNumber(button.value)));
	}
	
	{
		let button = createElement('button', 'button-repost');
		button.value = post.repost_count || 0;
		
		button.onclick = () => {
			if (!config.user) {
				router.go('/login', { url: '/post/' + post.id });
				return;
			}
			
			if (config.offline) {
				toast(__('You are currently offline.'));
				return;
			}
			
			if (post.post) {
				router.go('/compose/repost', { post: post.post.id });	
			} else {
				router.go('/compose/repost', { post: post.id });
			}
		}
		
		buttons.append(button, createElement('span', 'count count-repost', formatNumber(button.value)));
	}
	
	{
		let button = createElement('button', 'button-like');
		button.value = post.like_count || 0;
		
		if (post.like) {
			button.className += ' liked';
		}			

		button.onclick = () => {
			if (!config.user) {
				router.go('/login', { url: '/post/' + post.id });
				return;
			}
			
			if (config.offline) {
				toast(__('You are currently offline.'));
				return;
			}
			
			button.classList.toggle('liked');
			
			let like = button.classList.contains('liked'), value = +button.value || 0;
			
			if (like) {
				button.value = value + 1;
			} else if (value) {
				button.value = value - 1;
			}
			
			let label = button.nextSibling;
			label.innerHTML = formatNumber(button.value);
			
			if (like) {
				popupReview();

				api.post({
					url: '/post/' + post.id + '/like',
					success: likePost,
					error: undoLike
				});
			} else {
				api.delete({
					url: '/post/' + post.id + '/like',
					success: likePost,
					error: undoLike
				});
			}
			
			function likePost (result) {
				let elements = document.querySelectorAll('.post-' + post.id + ' .button-like');
				
				for (let element of elements) {
					element.value = result.like_count;
					element.classList.toggle('liked', like);
					element.nextSibling.innerHTML = formatNumber(result.like_count);
				}
			}
			
			function undoLike () {
				button.value = value;
				button.classList.toggle('liked', !like);
				label.innerHTML = formatNumber(value);
			}
		}
		
		buttons.append(button);
		
		if (!config.bot) {
			let href = '/post/' + post.id + '/likes';
			
			let count = createElement('a', 'count count-like', formatNumber(button.value));
			Object.assign(count, { href: href, rel: 'nofollow' });
			
			count.onclick = (e) => {
				e.preventDefault();
				e.stopPropagation();
				
				if (config.offline) {
					toast(__('You are currently offline.'));
					return;
				}
				
				router.go(href, { reset: true });
			}
			
			buttons.append(count);
		}
	}
		
	container.append(buttons);
		
	let meta = createElement('div', 'meta');
	container.append(meta);
	
	let link = createElement('a', null, renderDatetime(post.created));
	link.href = '/post/' + post.id;
		
	meta.append(link);
	
	if (post.poll) {
		if (config.user && config.user.id == post.user.id && !post.poll.voted) {
			let button = createElement('button', null, __('poll results'));
			
			button.onclick = () => {
				let element = container.querySelector('.poll');
				element.replaceWith(renderPollScore());
				
				button.previousSibling.remove();
				button.remove();
			}
			
			meta.append(createElement('span', 'bullet'), button);
		}

		let span = createElement('span');
		
		if (post.poll.ended) {
			span.innerHTML = _e('this poll lasted') + ' ';
		} else {
			span.innerHTML = _e('this poll lasts') + ' ';
		}
		
		if (post.poll.duration == 1) {
			span.innerHTML += _e('a day');
		} else {
			span.innerHTML += _e('%d days', post.poll.duration);
		}
		
		meta.append(createElement('span', 'bullet'), span);
	}
		
	if (post.location && !config.bot) {
		let href = '/location?latlng=' + post.latitude + ',' + post.longitude;
		
		let link = createElement('a', 'location', post.location);
		Object.assign(link, { href: href, rel: 'nofollow' });
		
		link.onclick = (e) => {
			e.preventDefault();
			e.stopPropagation();
			
			if (config.offline) {
				toast(__('You are currently offline.'));
				return;
			}

			router.go(href, { location: post.location });
		}
		
		meta.append(createElement('span', 'bullet'), link);
	}

	if (post.date && !config.bot) {
		let link = createElement('a', 'date', formatDateLocal(post.date, 'readable-date'));
		Object.assign(link, { href: '/search/posts?q=date:' + formatDateLocal(post.date, 'date'), rel: 'nofollow' });
		
		meta.append(createElement('span', 'bullet'), link);
	}

	function renderGallery () {
		let images = post.images, length = images.length, preloaded = false;
		
		let fragment = document.createDocumentFragment();
		
		let container = createElement('div', 'images');
		
		let outer = createElement('div', 'outer');
		outer.style.paddingTop = (images[0].height / images[0].width * 100) + '%';
		
		let inner = createElement('div', 'inner');

		for (let i = 0; i < length; i ++) {
			let image = images[i];
			
			let element = createElement('img', 'zoomable image-' + image.id);
			Object.assign(element, { alt: __('Photo of a train, posted by %s', post.user.name), src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=' });
			
			if (i == 0 || i == 1) {
				setTimeout(() => preload(image.image, (url) => {
					let elements = document.querySelectorAll('.image-' + image.id);
					
					for (let element of elements) {
						element.src = url;
					}
					
					element.src = url;
				}), i * 250);
			}
			
			inner.append(element);
		}
		
		outer.append(inner), container.append(outer);
		
		let lastTouch = 0, state, index = 0, x, y, lastX, direction;
		
		container.addEventListener('touchstart', (e) => {
			if (e.touches.length > 1) {
				return;
			}
			
			if (config.user) {
				if (Date.now() - lastTouch < 300) {
					lastTouch = 0;
					
					if (container.classList.contains('heart')) {
						return;
					}
					
					container.classList.add('heart');
					
					setTimeout(() => container.classList.remove('heart'), 800);
					
					let parent = container.parentNode;
					
					if (parent.parentNode.classList.contains('post')) {
						parent = parent.parentNode;
					}
					
					let button = parent.querySelector('button.button-like');
					
					if (!button.classList.contains('liked')) {
						button.click();
					}
					
					return;
				}
				
				lastTouch = Date.now();
			}
			
			state = '', x = e.touches[0].pageX, y = e.touches[0].pageY, lastX = x;
		}, { passive: false });
		
		container.addEventListener('touchmove', (e) => {
			if (e.touches.length > 1) {
				return;
			}
			
			if (!state && window.scrolling) {
				state = 'scrolling';
			}
			
			let touchX = e.touches[0].pageX, touchY = e.touches[0].pageY;
				
			let offsetX = Math.abs(x - touchX), offsetY = Math.abs(y - touchY);
				
			if (!state) {
				if (offsetX < 5 && offsetY < 5) {
					return;
				}
				
				if (offsetX > offsetY) {
					state = 'swiping';
					preloadImages();
				}
				
				if (offsetY > offsetX) {
					state = 'scrolling';
				}
				
				lastTouch = 0;
			}
			
			if (state != 'swiping') {
				return;
			}
			
			document.body.classList.add('disable-scrolling');
			
			if (e.cancelable) {
				e.preventDefault();
			}
			
			e.stopPropagation();
			
			direction = 0;
			
			if (touchX < x && touchX < lastX) {
				direction = 1;
			}

			if (touchX > x & touchX > lastX) {
				direction = -1;
			} 
			
			lastX = touchX;
			
			inner.className = 'inner swiping';

			let left = index + (x - touchX) / container.offsetWidth;
			
			if (length - 1 < left) {
				left = length - 1;
			}
			
			if (left < 0) {
				left = 0;
			}
			
			inner.style.transform = 'translateX(-' + (left * 100) + '%';
		}, { passive: false });
		
		function imageTouchEnd () {
			if (state != 'swiping') {
				return;
			}
			
			document.body.classList.remove('disable-scrolling');

			index += direction;
			
			if (index < 0) {
				index = 0;
			}
			
			if (index >= length) {
				index = length - 1;
			}
			
			inner.className = 'inner animate';
			inner.style.transform = 'translateX(-' + (index * 100) + '%';

			updateBullets();
		}
		
		container.addEventListener('touchend', imageTouchEnd);
		container.addEventListener('touchcancel', imageTouchEnd);
		
		fragment.append(container);
		
		let bullets = createElement('ul', 'bullets');

		if (length > 1) {
			{
				let button = createElement('button', 'button-prev');
				
				button.onclick = () => {
					if (index) {
						index --;
					} else {
						index = length - 1;
					}
					
					preloadImages();
					
					inner.className = 'inner animate';
					inner.style.transform = 'translateX(-' + (index * 100) + '%';
					
					updateBullets();
				}
				
				container.append(button);
			}
			
			{
				let button = createElement('button', 'button-next');
				
				button.onclick = () => {
					index ++;
					
					if (index == length) {
						index = 0;
					}
					
					preloadImages();
					
					inner.className = 'inner animate';
					inner.style.transform = 'translateX(-' + (index * 100) + '%';
					
					updateBullets();
				}
				
				container.append(button);
			}
			
			for (let i = 0; i < length; i ++) {
				let bullet = createElement('li');
				
				bullet.onclick = () => {
					if (index = i) {
						preloadImages();
					}
					
					inner.className = 'inner animate';
					inner.style.transform = 'translateX(-' + (index * 100) + '%';
					
					updateBullets();
				}
				
				if (!i) {
					bullet.className = 'active';
				}
				
				bullets.append(bullet);
			}
			
			fragment.append(bullets);
		}
		
		return fragment;
		
		function updateBullets () {
			outer.style.paddingTop = (images[index].height / images[index].width * 100) + '%';

			if (length < 2) {
				return;
			}
			
			for (let i = 0; i < length; i ++) {
				bullets.children[i].classList.toggle('active', i == index);
			}
		}
		
		function preloadImages () {
			if (preloaded) {
				return;
			}
			
			for (let image of images) {
				preload(image.image, (url) => {
					let elements = document.querySelectorAll('.image-' + image.id);
					
					for (let element of elements) {
						element.src = url;
					}
				});
			}
			
			preloaded = true;
		}
	}
	
	function renderVideo () {
		let container = createElement('div', 'video');
		
		let inner = createElement('div', 'inner paused');
		inner.style.paddingBottom = (Math.min(post.height / post.width, .8) * 100) + '%';
		
		let video = createElement('video');
		Object.assign(video, { loop: true, preload: 'none', poster: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=' });
		
		preload(post.thumbnail, (url) => video.poster = url);
		
		let timer = createElement('span', 'timer');
		
		if (config.iOS) {
			video.setAttribute('playsinline', true);
		}
		
		video.onclick = () => {
			if (video.paused) {
				video.play();
			} else {
				video.pause();
			}
		}
		
		video.onplay = () => {
			if (window.activeView) {
				let elements = activeView.container.querySelectorAll('video');
				
				for (let element of elements) {
					if (element == video || element.paused) {
						 continue;
					}
					
					element.pause();
				}
			}
			
			inner.classList.remove('paused');
		}

		video.onpause = () => {
			inner.classList.add('paused');				
		}
		
		video.ontimeupdate = () => {
			let time = Math.round(video.duration - video.currentTime);
			timer.innerHTML = (time / 60 | 0) + ':' + (time % 60).toString().padStart(2, '0')
		}
		
		video.src = post.video;

		inner.append(video, timer);
		
		container.append(inner);
		
		return container;
	}

	function renderURL () {
		let video = isYouTubeVideo(post.url);
		
		if (video) {
			let container = createElement('div', 'video youtube');
			container.youtube = video;
			
			let inner = createElement('div', 'inner');
			
			let thumbnail = createElement('div', 'thumbnail');
			
			preload('https://img.youtube.com/vi/' + video + '/hqdefault.jpg', (url) => thumbnail.style.backgroundImage = 'url(' + url + ')');
			
			inner.append(thumbnail);
			
			container.append(inner);
			
			return container;
		}
				
		let link = createElement('a', 'link-details');
		Object.assign(link, { href: post.url, target: '_blank' });
		
		let inner = createElement('span', 'inner');
		
		let details = post.details || {};
		
		if (details.image) {
			preload(details.image, (url) => inner.style.backgroundImage = 'url(' + url + ')');
		} else {
			link.className += ' no-image';
		}
		
		link.append(inner);
		
		if (details.title) {
			link.append(createElement('div', 'title', details.title));
		}
		
		try {
			link.append(createElement('div', 'domain', new URL(post.url).host));
		} catch (e) {}
		
		return link;
	}

	function renderPollVote () {
		let poll = post.poll;

		let container = createElement('div', 'poll');
		
		for (let answer of poll.answers) {
			let button = createElement('button', 'button uppercase poll-answer answer-' + answer.id, answer.answer);
			
			button.onclick = () => {
				if (!config.user) {
					router.go('/login', { url: '/post/' + post.id });
					return;
				}
				
				if (config.offline) {
					toast(__('You are currently offline.'));
					return;
				}
				
				api.post({
					url: '/post/' + post.id + '/vote',
					data: { vote: answer.id },
					success: (result) => {
						let elements = document.querySelectorAll('.post-' + post.id);
						
						for (let element of elements) {
							element.replaceWith(renderPost(result.post));
						}
					}
				});
			}
			
			container.append(button);
		}
		
		return container;
	}

	function renderPollScore () {
		let poll = post.poll;
		
		let container = createElement('div', 'poll');
		
		let sum = 0, maximum = 0;
		
		for (let answer of poll.answers) {
			sum += answer.votes;
			
			if (answer.votes > maximum) {
				maximum = answer.votes;
			}
		}
		
		for (let answer of poll.answers) {
			let element = createElement('div', 'poll-answer');
			
			let label = answer.answer;
			
			if (answer.voted) {
				label += ' (' + __('you') + ')';
			}
			
			element.append(createElement('span', 'label uppercase', label));
				
			if (answer.votes == 1) {
				element.append(createElement('span', 'votes', __('1 vote')));
			} else {
				element.append(createElement('span', 'votes', __('%d votes', answer.votes)));
			}
			
			let inner = createElement('span', 'inner');
			
			if (answer.votes) {
				if (answer.votes == sum) {
					inner.style.width = '100%';
				} else {
					inner.style.width = (answer.votes / maximum * 90) + '%';
				}
			}
			
			element.append(createElement('div', 'percentage', inner));
			
			container.append(element);
		}
			
		return container;	
	}
	
	function removeRenderPost () {
		cache.delete(['/post/' + post.id, '/post/' + post.id + '/*', '/comments/' + post.id, '/comments/' + post.id + '/*']);

		{
			let elements = document.querySelectorAll('.timeline > .post-' + post.id);
			
			for (let element of elements) {
				element.remove();
			}
		}
		
		{
			let elements = document.querySelectorAll('.post > .post-' + post.id);
			
			for (let element of elements) {
				element.parentNode.querySelector('.count-repost').innerHTML = '';
				element.replaceWith(createElement('div', 'post missing', __('This post is not available.')));
			}
		}
	}
	
	return container;	
}

function refreshPostsCount (container) {
	let posts = [];
	
	for (let element of container.children) {
		let match = element.className.match(/\b(?:post)-(\S{20})/);
		
		if (!match) {
			continue;
		}
		
		if (~posts.indexOf(match[1])) {
			continue;
		}
		
		posts[posts.length] = match[1];
		
		if (posts[99]) {
			break;
		}
	}
	
	if (!posts.length) {
		return;
	}
	
	api.post({
		url: '/posts/refresh',
		data: { post_ids: posts },
		success: (result) => {
			for (let post of result.posts) {
				refreshPost(post);
			}
		}
	});
	
	function refreshPost (post) {
		for (let type of ['comment', 'repost', 'like']) {
			let elements = document.querySelectorAll('.post-' + post.id + ' .button-' + type);
			
			for (let element of elements) {
				element.value = post[type + '_count'];
				element.nextSibling.innerHTML = formatNumber(post[type + '_count']);
				
				if (type == 'like') {
					element.classList.toggle('liked', !!post.like);
				}
			}
		}
	}
}

document.addEventListener('click', (e) => {
	let target = e.target;
	
	while (target && target.matches && !target.matches('.content > a.read-more')) {
		target = target.parentNode;
	}
	
	if (target && target.remove) {
		target.remove();
	}
});