<script lang="ts">
	let { data } = $props();

	const WEEKDAYS: string[] = [ "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag" ]

	const HEADERS: string[] = [ "Datum", "Wochentag", "Beginn", "Ende", "Dauer", "Anmerkung" ];

	const TODAY: Date			= new Date();
	const CENTURY_PREF: number	= Math.floor(TODAY.getFullYear() / 100);
	const CENTURY_YEAR: number	= CENTURY_PREF * 100;

	let dateInput: HTMLInputElement;
	let startInput: HTMLInputElement;
	let endInput: HTMLInputElement;
	
	let dateValid: boolean	= $state(true);
	let startValid: boolean	= $state(true);
	let endValid: boolean	= $state(true);

	let inWeekDay: string   = $state("");
	let inDuration: string	= $state("");

	function toInt(str: string): number {
		let value = 0;
		for (let i = 0; i < str.length; ++i) {
			let c = str.charAt(i);
			let n = Number(c);
			if (isNaN(n)) {
				return NaN;
			}
			value = value*10 + n;
		}
		
		return value;
	}

	function parseDate(str: string): Date | null {
		if (str.length != 2+1+2+1+4) {
			return null;
		}

		let day		= toInt(str.slice(0, 2))
		let month	= toInt(str.slice(3, 5));
		let year	= toInt(str.slice(6, 10));

		if (isNaN(day) || isNaN(month) || isNaN(year) || str.charAt(2) !== '.' || str.charAt(5) !== '.') {
			return null;
		}

		let date = new Date(year, month-1, day);

		if (isNaN(date.valueOf())) {
			return null;
		}

		return date;
	}

	function validateForm(event: Event): boolean {
		let valid = dateValid  && dateInput.value.length !== 0
			&& startValid && startInput.value.length !== 0
			&& endValid && endInput.value.length !== 0;
		
		if (!valid) {
			event.preventDefault();
		}
		return valid;
	}

	function validateDate(element: HTMLInputElement) {
		
		/*
		supports:
			D.M

			DDMM
			D.MM
			DD.M
			
			DD.MM
			
			DDMMYY
			D.M.YY
			
			D.M.YYYY
			DD.MM.YY
			DDMMYYYY
			
			DD.MM.YYYY
		*/

		switch (element.value.length) {
			case 0: return true;
			case 3: {
					/*
					 * D.M
					 */

					let day		= toInt(element.value.charAt(0));
					let month	= toInt(element.value.charAt(2));

					if (isNaN(day) || isNaN(month) || element.value.charAt(1) !== '.') {
						return false;
					}

					if (day > 0 && month > 0) {
						element.value = "0" + day + ".0" + month + "." + TODAY.getFullYear();
						return true;
					}
				} break;
			case 4: if (
				(() =>{
					/*
					 * DDMM
					 */
					
					let day		= toInt(element.value.slice(0, 2));
					let month	= toInt(element.value.slice(2, 4));

					if (isNaN(day) || isNaN(month)) {
						return false;
					}

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(TODAY.getFullYear(), month, 0).getDate())) {
						element.value = element.value.slice(0, 2) + "." + element.value.slice(2, 4) + "." + TODAY.getFullYear();
						return true;
					}

					return false;
				})() === true
				|| (() => {
					/*
					 * DD.M
					 */

					let day		= toInt(element.value.slice(0, 2));
					let month	= toInt(element.value.charAt(3));

					if (isNaN(day) || isNaN(month) || element.value.charAt(2) !== '.') {
						return false;
					}

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(TODAY.getFullYear(), month, 0).getDate())) {
						element.value = element.value.slice(0, 2) + ".0" + month + "." + TODAY.getFullYear();
						return true;
					}

					return false;
				})() === true
				|| (() => {
					/*
					 * D.MM
					 */
					
					let day		= toInt(element.value.charAt(0));
					let month	= toInt(element.value.slice(2, 4));

					if (isNaN(day) || isNaN(month) || element.value.charAt(1) !== '.') {
						return false;
					}

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(TODAY.getFullYear(), month, 0).getDate())) {
						element.value = "0" + day + "." + element.value.slice(2, 4) + "." + TODAY.getFullYear();
						return true;
					}

					return false;
				})() === true) {
					return true;
				} break;
			case 5: {
					/*
					 * DD.MM
					 */

					let day		= toInt(element.value.slice(0, 2));
					let month	= toInt(element.value.slice(3, 5));

					if (isNaN(day) || isNaN(month) || element.value.charAt(2) !== '.') {
						return false;
					}

					if (!((month < 1 || month > 12)
						|| (day < 1 || day > new Date(TODAY.getFullYear(), month, 0).getDate()))) {
						element.value = element.value + "." + TODAY.getFullYear();
						return true;
					}
				} break;
			case 6: if ((() => {
					/*
					 * DDMMYY
					 */

					let day		= toInt(element.value.slice(0, 2));
					let month	= toInt(element.value.slice(2, 4));
					let year	= toInt(element.value.slice(4, 6));

					if (isNaN(day) || isNaN(month) || isNaN(year)) {
						return false;
					}

					year += CENTURY_YEAR;

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(year, month, 0).getDate())) {
						element.value = element.value.slice(0, 2) + "." + element.value.slice(2, 4) + "." + CENTURY_PREF + element.value.slice(4, 6);
						return true;
					}
					return false;
				})() === true
				|| (() => {
					/*
					 * D.M.YY
					 */
					
					let day		= toInt(element.value.charAt(0));
					let month	= toInt(element.value.charAt(2));
					let year	= toInt(element.value.slice(4, 6));

					if (isNaN(day) || isNaN(month) || isNaN(year) || element.value.charAt(1) !== '.' || element.value.charAt(3) !== '.') {
						return false;
					}

					year += CENTURY_YEAR;

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(year, month, 0).getDate())) {
						element.value = "0" + day + ".0" + month + "." + CENTURY_PREF + element.value.slice(4, 6);
						return true;
					}

					return false;
				})() === true) {
					return true;
				} break;
			case 8: if (
				(() => {
					/*
					 * D.M.YYYY
					 */

					let day		= toInt(element.value.charAt(0));
					let month	= toInt(element.value.charAt(2));
					let year	= toInt(element.value.slice(4, 8));

					if (isNaN(day) || isNaN(month) || isNaN(year) || element.value.charAt(1) !== '.' || element.value.charAt(3) !== '.') {
						return false;
					}

					year += CENTURY_YEAR;

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(year, month, 0).getDate())) {
						element.value = "0" + day + ".0" + month + "." + element.value.slice(4, 8);
						return true;
					}

					return false;
				})() === true
				|| (() => {
					/*
					 * DD.MM.YY
					 */

					let day		= toInt(element.value.slice(0, 2));
					let month	= toInt(element.value.slice(3, 5));
					let year	= toInt(element.value.slice(6, 8));

					if (isNaN(day) || isNaN(month) || isNaN(year) || element.value.charAt(2) !== '.' || element.value.charAt(5) !== '.') {
						return false;
					}

					year += CENTURY_YEAR;

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(year, month, 0).getDate())) {
						element.value = element.value.slice(0, 2) + "." + element.value.slice(3, 5) + "." + CENTURY_PREF + element.value.slice(6, 8);
						return true;
					}
					return false;
				})() === true
				|| (() => {
					/*
					 * DDMMYYYY
					 */
					
					let day		= toInt(element.value.slice(0, 2));
					let month	= toInt(element.value.slice(2, 4));
					let year	= toInt(element.value.slice(4, 8));

					if (isNaN(day) || isNaN(month) || isNaN(year)) {
						return false;
					}

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(year, month, 0).getDate())) {
						element.value = element.value.slice(0, 2) + "." + element.value.slice(2, 4) + "." + element.value.slice(4, 8);
						return true;
					}

					return false;
				})() === true) {
					return true;
				} break;
			case 10: {
					/*
					 * DD.MM.YYYY
					 */

					let day		= toInt(element.value.slice(0, 2));
					let month	= toInt(element.value.slice(3, 5));
					let year	= toInt(element.value.slice(6, 10));

					if (isNaN(day) || isNaN(month) || isNaN(year) || element.value.charAt(2) !== '.' || element.value.charAt(5) !== '.') {
						return false;
					}

					if (!(month < 1 || month > 12
						|| day < 1 || day > new Date(year, month, 0).getDate())) {
						return true;
					}
			} break;
		}
		
		return false;
	}

	function validateTime(element: HTMLInputElement): boolean {
		
		/*
		supports:
			
			H:MM
			HHMM
			HH:MM
		 */

		switch(element.value.length) {
			case 0: return true;
			case 4: if (
				(() => {
					let h = toInt(element.value.slice(0, 2));
					let m = toInt(element.value.slice(2, 4));

					if (isNaN(h) || isNaN(m)) {
						return false;
					}

					if (0 <= h && h <= 24 && 0 <= m && m <= 59) {
						element.value = element.value.slice(0, 2) + ":" + element.value.slice(2, 4);
						return true;
					}
					return false;
				})() === true
				|| (() => {
					let h = toInt(element.value.charAt(0));
					let m = toInt(element.value.slice(2, 4));

					if (isNaN(h) || isNaN(m) || element.value.charAt(1) !== ':') {
						return false;
					}

					if (0 <= m && m <= 59) {
						element.value = "0" + element.value;
						return true;
					}
					return false;
				})() === true) {
					return true;
				}
			case 5: {	
				let h = toInt(element.value.slice(0, 2));
				let m = toInt(element.value.slice(3, 5));

				if (isNaN(h) || isNaN(m) || element.value.charAt(2) !== ':') {
					return false;
				}

				if (0 <= h && h <= 24 && 0 <= m && m <= 59) {
					return true;
				}
			} break;
		}

		return false;
	}

	function calculateDuration(start: string, end: string): string {
		
		if (start.length !== 5 || end.length !== 5) {
			return "";
		}

		let start_h	= toInt(start.slice(0, 2));
		let start_m = toInt(start.slice(3, 5));

		let end_h	= toInt(end.slice(0, 2));
		let end_m	= toInt(end.slice(3, 5));

		if (isNaN(start_h) || isNaN(start_m) || start.charAt(2) !== ':'
			|| isNaN(end_h) || isNaN(end_m) || end.charAt(2) !== ':') {
			return "";
		}

		let start_n = start_h * 60 + start_m;
		let end_n	= end_h * 60 + end_m;

		let duration = (end_n - start_n) / 60;

		return duration.toFixed(2);
	}
	
	let entries: number[][] = [];

	for (let i = 0; i < 50; ++i) {
		entries.push([i, i, i, i, i, i, i*i]);
	}

</script>

<div class="wrap">

<form id="form_new_entry" method="POST" action="?/new_entry" onsubmit={validateForm}></form>

<table class="list">
	<caption>Stundenliste</caption>

	<thead>
		<tr>
			<th style:width="20ch">Datum</th>
			<th style:width="25ch">Wochentag</th>
			<th style:width="12ch">Beginn</th>
			<th style:width="12ch">Ende</th>
			<th style:width="12ch">Dauer</th>
			<th>Anmerkung</th>
			<th style:width="fit-content">Actions</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<input 
					bind:this={dateInput}
					class:form-invalid={!dateValid}
					name="date"
					type="text"
					form="form_new_entry" 
					onfocusin={
						(_) => {
							dateInput.select();
							dateValid = true;
						}
					}
					onfocusout={
						(_) => {
							dateValid = validateDate(dateInput);
							if (dateValid) {
								inWeekDay = WEEKDAYS[parseDate(dateInput.value)!.getDay()];
							}
						}
					}
				required>
			</td>

			<td>
				{inWeekDay}
			</td>

			<td>
				<input
					bind:this={startInput}
					class:form-invalid={!startValid}
					name="starttime"
					type="text"
					form="form_new_entry" 
					onfocusin={
						(_) => {
							startInput.select();
							startValid = true;
						}
					}
					onfocusout={
						(_) => {
							startValid = validateTime(startInput);
							inDuration = calculateDuration(startInput.value, endInput.value);
						}
					}
				required>
			</td>

			<td>
				<input 
					bind:this={endInput}
					class:form-invalid={!endValid}
					name="endtime"
					type="text"
					form="form_new_entry" 
					onfocusin={
						(_) => {
							endInput.select();
							endValid = true;
						}
					}
					onfocusout={
						(_) => {
							endValid = validateTime(endInput);
							inDuration = calculateDuration(startInput.value, endInput.value);
						}
					}
				required>
			</td>

			<td>
				{inDuration}
			</td>

			<td>
				<input
					name="comment"
					type="text"
					form="form_new_entry">
			</td>

			<td>
				<button
					type="submit"
					form="form_new_entry">
					+
				</button>
			</td>

		</tr>
{#each entries as entry}
		<!--<tr><td>{entry}</td></tr>-->
		<tr>
		{#each entry as i}
			<td>{i}</td>
		{/each}
		</tr>
{/each}
		<tr></tr>
	</tbody>
{#if entries === undefined || entries.length === 0}
	<tfoot>
		<tr>
			<td class="td-no-elements" colspan="999">No elements</td>
		</tr>
	</tfoot>
{/if}
</table>

</div>

<style>

table {
	width: 80%;
	margin: auto;

	border-collapse: collapse;
	border: 1px solid;
}

table caption {
	font-size: 25px;
	font-weight: bold;
}

tbody * {
	border: 1px solid;
}

tbody tr:nth-child(even) {
	background: gray;
}

tbody tr:nth-child(odd) {
	background: lightgray;
}

td input {
	box-sizing: border-box;
	width: 100%;

	border: none;
}

.td-no-elements {
	text-align: center;
}

.form-invalid {
	background: #FF4444;
}

</style>
