(function() { 
	'use strict';

	// helpers {{{

	function describeTimeElementDate(element) { // {{{

		if (!(element instanceof HTMLTimeElement)) {
			return "unknown";
		}

		const startYear = element.getAttribute('startyear');
		const startMonth = element.getAttribute('startmonth');
		const startDay = element.getAttribute('startday');

		if (!startYear || !startMonth || !startDay || isNaN(startYear) || isNaN(startMonth) || isNaN(startDay)) {
			return 'Invalid date attributes on the <time> element';
		}

		const timeElementDate = new Date(startYear, startMonth - 1, startDay);
		timeElementDate.setHours(0, 0, 0, 0);

		const today = new Date();
		today.setHours(0, 0, 0, 0);

		const dayDifference = Math.round((timeElementDate - today) / (1000 * 60 * 60 * 24));

		const daysOfWeek = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
		const dayOfWeek = daysOfWeek[timeElementDate.getDay()];

		const monthsOfYear = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
		const month = monthsOfYear[timeElementDate.getMonth()];

		var ret = [dayOfWeek, month];

		if (dayDifference === 0) {
			ret.push('today');
		} else if (dayDifference === 1) {
			ret.push('tomorrow');
		} else if (dayDifference === -1) {
			ret.push('yesterday');
		} else {
			if (dayDifference < 0) {
				ret.push('late');
				// if (dayDifference > -8) {
				// 	ret.push('last');
				// } else {
				// 	ret.push('older');
				// }
			} else {
				ret.push('future');
				// if (dayDifference < 8) {
				// 	ret.push('next');
				// } else {
				// 	ret.push('later');
				// }
			}
		}

		return ret;
	}

	// }}}

	function safeGetContent(parent, selector) { // {{{
		var element = parent.querySelector(selector);
		if (element !== null) {
				var content = element.innerText;
				if (content !== null) {
						return content;
				}
		}
		return ""
	}

	// }}}
	
	function removeClassesStartingWith(element, prefix) { // {{{
		const classes = element.classList;
		for (const className of classes) {
		if (className.startsWith(prefix)) {
			element.classList.remove(className);
		}
		}
	}

	// }}}
	
	function isIosSafari() { // {{{
		 const ua = navigator.userAgent;
		 return (
			 /iPhone|iPad|iPod/.test(ua) &&
			 /Safari/.test(ua)
		 );
	}

	// }}}
		
	function removeKeyboard(contentElement) { // {{{
		if (!('allowEditing' in contentElement)) {
			contentElement.allowEditing = false;
		}

		contentElement.addEventListener('focus', (e) => {
			if (!contentElement.allowEditing) {
				e.preventDefault();
				contentElement.blur();
			}
		});

		contentElement.addEventListener('dblclick', (e) => {
			contentElement.allowEditing = true;

			// Small delay to ensure focus is handled correctly
			setTimeout(() => {
				contentElement.focus();
			}, 0);
		});

		contentElement.addEventListener('blur', () => {
			contentElement.allowEditing = false;
		});
	}

	// }}}

	// }}}

	function updateProject(projectNode) {
		removeClassesStartingWith(projectNode, "backlinked");
		removeClassesStartingWith(projectNode, "link");
		removeClassesStartingWith(projectNode, "tag");
		removeClassesStartingWith(projectNode, "time");
		const names = [];
		const notes = [];
		for (let i = 0; i < projectNode.children.length; i++) {
			const child = projectNode.children[i];
			if (child.classList.contains('name')) {
				names.push(child);
			}
			if (child.classList.contains('notes')) {
				notes.push(child);
			}
		}
		[notes, names].forEach(function(ns) {
			if (ns.length > 0) {
				const n = ns[0];
				const text = safeGetContent(n, ".content > .innerContentContainer");
				const tags = n.querySelectorAll('.contentTag');
				tags.forEach(tag => {
					var tagText = safeGetContent(tag, ".contentTagText").trim();
					if (tagText !== "") {
						projectNode.classList.add("tagged");
						projectNode.classList.add("tagged-" + tagText);
						tag.classList.add("tag");
						tag.classList.add("tag-" + tagText);
					}
				});
				const links = n.querySelectorAll('.contentLink');
				links.forEach(link => {
					link.spellcheck = false;
					const nonLetterRegex = /[^a-zA-Z0-9]/g;
					var linkFull = link.innerText.trim().replace(nonLetterRegex, '');
					if (linkFull.startsWith("x")) {
						var className = "linked-" + linkFull;
						var linkClassName = "link-" + linkFull;
						projectNode.classList.add("linked");
						projectNode.classList.add(className);
						link.classList.add("link");
						link.classList.add(linkClassName);
					}
				});
				const times = n.querySelectorAll('time');
				times.forEach(time => {
					var relatives = describeTimeElementDate(time);
					projectNode.classList.add("timed");
					time.classList.add("time");
					relatives.forEach(relative => {
						projectNode.classList.add("timed-" + relative);
						time.classList.add("time-" + relative);
					});
				});

				if (isIosSafari()) {
					const content = n.querySelector('.content');
					removeKeyboard(content);
				}

			 }
		});
	}
	
	function updateAll() {
		const projectNodes = document.querySelectorAll('.project');
		projectNodes.forEach(projectNode => {
			updateProject(projectNode);
		});
	}

	const observer = new MutationObserver((mutations) => {
		for (const mutation of mutations) {
			var nodes = null;
			if (mutation.addedNodes.length > 0) {
				nodes = mutation.addedNodes;
			} else if (mutation.removedNodes.length > 0) {
				nodes = mutation.addedNodes;
			}
			if ( nodes !== null ) {
				var node = mutation.target;
				if ( node !== null ) {
					var projectNode = node.closest('.project');
					if ( projectNode !== null && projectNode !== node ) {
						updateProject(projectNode);
					}
				}
			}
		}
	});

	observer.observe(document.body, { childList: true, subtree: true });

	updateAll();


})();