/* Add callbacks on text formatting buttons */

/* Locate the editor associated to an edition event.
   event: Global event emitted by one of the editor buttons
   Returns [the div.editor, the button, the textarea] */
function editor_event_source(event)
{
	let button = undefined;
	let editor = undefined;

	/* Grab the button and the parent editor block. The onclick event itself
	   usually reports the SVG in the button as the source */
	let node = event.target || event.srcElement;
	while(node != document.body) {
		if(node.tagName == "BUTTON" && !button) {
			button = node;
		}
		if(node.classList.contains("editor") && !editor) {
			editor = node;
			break;
		}
		node = node.parentNode;
	}
	if(!button || !editor) return;

	const ta = editor.querySelector("textarea");
	return [editor, button, ta];
}

/* Replace the range [start:end) with the new contents, and returns the new
   interval [start:end) (ie. the range where the contents are now located). */
function editor_replace_range(textarea, start, end, contents)
{
	ta.value = ta.value.substring(0, start)
			 + contents
			 + ta.value.substring(end);

	return [start, start + contents.length];
}

/* Event handler that inserts specified tokens around the selection.
   after token is the same as before if not specified */
function editor_insert_around(event, before="", after=null)
{
	const [editor, button, ta] = editor_event_source(event);
	ta.focus();
	let indexStart = ta.selectionStart;
	let indexEnd = ta.selectionEnd;

	if(after === null) {
		after = before;
	}

	let [start, end] = editor_replace_range(ta, indexStart, indexEnd,
		before + ta.value.substring(indexStart, indexEnd) + after);

	/* Restore selection */
	if(indexStart != indexEnd) {
		ta.selectionStart = start;
		ta.selectionEnd = end;
	}
	else {
		ta.selectionStart = ta.selectionEnd = start + before.length;
	}

	preview();
}

/* Event handler that modifies each line within the selection through a
   generic function. */
function editor_act_on_lines(event, fn)
{
	const [editor, button, ta] = editor_event_source(event);
	ta.focus();
	let indexStart = ta.selectionStart;
	let indexEnd = ta.selectionEnd;

	let firstLineIndex = ta.value.substring(0, indexStart).lastIndexOf('\n');
	if(firstLineIndex < 0)
		firstLineIndex = 0;
	else
		firstLineIndex += 1;

	let lastLineIndex = ta.value.substring(indexEnd).indexOf('\n');
	if(lastLineIndex < 0)
		lastLineIndex = ta.value.length;
	else
		lastLineIndex += indexEnd;

	let lines = ta.value.substring(firstLineIndex, lastLineIndex).split('\n');

	for(let i = 0; i < lines.length; i++)
		lines[i] = fn(lines[i]);

	let [start, end] = editor_replace_range(ta, firstLineIndex, lastLineIndex,
		lines.join('\n'));

	ta.selectionStart = start;
	ta.selectionEnd = end;

	preview();
}

function editor_clear_modals(event, close = true)
{
	// Stop the propagation of the event
	event.stopPropagation()

	// Reset all modal inputs
	document.getElementById('media-alt-input').value = '';
	document.getElementById('media-link-input').value = '';
	document.getElementById('link-desc-input').value = '';
	document.getElementById('link-desc-input').value = '';
	const media_type = document.getElementsByName("media-type");
	for(i = 0; i < media_type.length; i++) {
		media_type[i].checked = false;
	}

	// Close all modal if requested
	if (!close) { return }
	const modals = document.getElementsByClassName('modal');
	for (const i of modals) {i.style.display = 'none'};
}


/* End-user functions */
function editor_inline(event, type)
{
	tokens = {
		bold: "**",
		italic: "*",
		underline: "__",
		strike: "~~",
		inlinecode: "`",
	};

	if(type in tokens){
		editor_insert_around(event, tokens[type]);
	}

	preview();
}

function editor_display_link_modal(event) {
	const [editor, button, ta] = editor_event_source(event);
	let indexStart = ta.selectionStart;
	let indexEnd = ta.selectionEnd;
	let selection = ta.value.substring(indexStart, indexEnd);

	// Assuming it's a link
	if(selection.match(/^https?:\/\/\S+/)) {
		event.currentTarget.querySelector("#link-link-input").value = selection;
	}
	// Or text
	else if(selection != "") {
		event.currentTarget.querySelector("#link-desc-input").value = selection;	
	}
	// Or nothing selected
	else {
		event.currentTarget.querySelector("#link-desc-input").value = "";
		event.currentTarget.querySelector("#link-link-input").value = "";
	}

	event.currentTarget.children[1].style = {'display': 'block'};
}

function editor_insert_link(event, link_id, text_id, media = false)
{
	const [editor, button, ta] = editor_event_source(event);
	ta.focus();
	let indexStart = ta.selectionStart;
	let indexEnd = ta.selectionEnd;

	const link = document.getElementById(link_id).value;
	const text = document.getElementById(text_id).value;
	let media_type = "";

	const media_selector = document.getElementsByName("media-type");
	for(i = 0; i < media_selector.length; i++) {
		if(media_selector[i].checked) {
			media_type = `{type=${media_selector[i].value}}`;
		}
	}

	editor_clear_modals(event);

	let [start, end] = editor_replace_range(ta, indexStart, indexEnd,
		`[${text.length === 0 ? ta.value.substring(indexStart, indexEnd) : text}]${media ? "!" : ""}(${link})${media ? media_type : ""}`);

	/* Restore selection */
	if(indexStart != indexEnd) {
		ta.selectionStart = start;
		ta.selectionEnd = end;
	}
	else {
		ta.selectionStart = ta.selectionEnd = start + 1;
	}

	preview();
}

function editor_title(event, level, diff)
{
	editor_act_on_lines(event, function(line) {
		/* Strip all the initial # (and count them) */
		let count = 0;
		while(count < line.length && line[count] == '#') count++;

		let contents_index = count;
		if(count < line.length && line[count] == ' ') contents_index++;
		let contents = line.slice(contents_index);

		if(level > 0 || count == 1 && diff == -1) {
			/* Remove the title if the corresponding level is re-requested */
			if(count == level || count == 1 && diff == -1)
				return contents;
			/* Otherwise, add it */
			else
				return '#'.repeat(level) + ' ' + contents;
		}
		else if(count > 0) {
			/* Apply the difference */
			let new_level = Math.max(1, Math.min(6, count + diff));
			return '#'.repeat(new_level) + ' ' + contents;
		}
		return line;
	});
}

function editor_quote(event)
{
	editor_act_on_lines(event, function(line) {
		/* Strip all the initial > (and count them) */
		let count = 0;
		while(count < line.length && line[count] == '>') count++;

		let contents_index = count;
		if(count < line.length && line[count] == ' ') contents_index++;
		let contents = line.slice(contents_index);

		/* Apply the difference */
		return '>'.repeat(count + 1) + ' ' + contents;
	});
}

function editor_bullet_list(event)
{
	editor_act_on_lines(event, function(line) {
		let ident_match = line.match(/^[\t]+/m) ?? [''];
		let ident = ident_match[0];
		let count = ident.length;

		const contents = line.slice(count);
		if((count < line.length || count == 0) && line[count] != '-') return '- ' + contents;

		return ident + "\t" + contents;
	});
}

function editor_numbered_list(event)
{
	editor_act_on_lines(event, function(line) {
		let ident_match = line.match(/^[\t]+/m) ?? [''];
		let ident = ident_match[0];
		let count = ident.length;

		const contents = line.slice(count);
		if((count < line.length || count == 0) && isNaN(line[count])) return '1. ' + contents;

		return ident + "\t" + contents;
	});
}

function editor_table(event) {
	let table = `| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| Text     | Text     | Text     |`;

	editor_insert_around(event, "", table);
}

function editor_separator(event) {
	editor_insert_around(event, "", "\n---\n");
}


previewTimeout = null;
ta = document.querySelector(".editor textarea");
ta.addEventListener('keydown', function(e) {
	// Tab insert some spaces
	let keyCode = e.keyCode || e.which;
	if (keyCode == 9) {
		// TODO Add one tab to selected text without replacing it
		e.preventDefault();
		
		let start = e.target.selectionStart;
		let end = e.target.selectionEnd;
		// set textarea value to: text before caret + tab + text after caret
		e.target.value = e.target.value.substring(0, start) + "\t" + e.target.value.substring(end);
		e.target.selectionEnd = start + 1;
	}
	
	// TODO
	// Ctrl+B adds bold
	// Ctrl+I adds italic
	// Ctrl+U adds underline

	// Ctrl+Enter send the form
	if (e.ctrlKey && keyCode == 13) {
		let t = e.target;
		while(! (t instanceof HTMLFormElement)) {
			t = t.parentNode;
		}
		try {
			t.submit();
		} catch(exception) {
			t.submit.click();
		}
	}

	// Set a timeout for refreshing the preview
	if (previewTimeout != null) {
		clearTimeout(previewTimeout);
	}
	previewTimeout = setTimeout(preview, 3000);
});


function preview() {
	const previewArea = document.querySelector("#editor_content_preview");

	const textarea = document.querySelector(".editor textarea");
	const payload = {text: ta.value};

	const headers = new Headers();
	headers.append("Content-Type", "application/json");

	const params = {
		method: "POST",
		body: JSON.stringify(payload),
		headers
	};

	fetch("/api/markdown", params).then(
		(response) => {
			response.text().then(
			(text) => {
				previewArea.innerHTML = text;
			}
		);
	});
}

