
/**
 */
namespace _zeitbild.frontend_web.view
{
	
	/**
	 */
	function event_generate_tooltip(
		calendar_name : string,
		event : _zeitbild.frontend_web.type.event_object
	) : string
	{
		return (
			lib_plankton.string.coin(
				"[{{calendar_name}}] {{event_name}}\n",
				{
					"calendar_name": calendar_name,
					"event_name": event.name,
				}
			)
			+
			"--\n"
			+
			(
				(event.begin.time !== null)
				?
				lib_plankton.string.coin(
					"{{label}}: {{value}}\n",
					{
						"label": "Anfang", // TODO: translate
						"value": lib_plankton.string.coin(
							"{{hour}}:{{minute}}",
							{
								"hour": event.begin.time.hour.toFixed(0).padStart(2, "0"),
								"minute": event.begin.time.minute.toFixed(0).padStart(2, "0"),
							}
						), // TODO: outsource
					}
				)
				:
				""
			)
			+
			(
				(event.end !== null)
				?
				lib_plankton.string.coin(
					"{{label}}: {{value}}\n",
					{
						"label": "Ende", // TODO: translate
						"value": (
							[
								(
									(
										(event.end.date.year !== event.begin.date.year)
										||
										(event.end.date.month !== event.begin.date.month)
										||
										(event.end.date.day !== event.begin.date.day)
									)
									?
									lib_plankton.string.coin(
										"{{year}}-{{month}}-{{day}}",
										{
											"year": event.end.date.year.toFixed(0).padStart(4, "0"),
											"month": event.end.date.month.toFixed(0).padStart(2, "0"),
											"day": event.end.date.day.toFixed(0).padStart(2, "0"),
										}
									)
									:
									null
								),
								(
									(event.end.time !== null)
									?
									lib_plankton.string.coin(
										"{{hour}}:{{minute}}",
										{
											"hour": event.end.time.hour.toFixed(0).padStart(2, "0"),
											"minute": event.end.time.minute.toFixed(0).padStart(2, "0"),
										}
									)
									:
									null
								),
							]
							.filter(x => (x !== null))
							.join(",")
						),
					}
				)
				:
				""
			)
			+
			(
				(event.location !== null)
				?
				(
					lib_plankton.string.coin(
						"{{label}}: {{value}}\n",
						{
							"label": "Ort", // TODO
							"value": event.location,
						}
					)
				)
				:
				""
			)
			+
			(
				(event.description !== null)
				?
				(
					"--\n"
					+
					lib_plankton.string.coin(
						"{{description}}\n",
						{
							"description": event.description,
						}
					)
				)
				:
				""
			)
		);
	}
	
	
	/**
	 * @todo kein "while"
	 */
	async function calendar_view_table_data(
		calendar_ids : ( 
			null
			|
			Array<_zeitbild.frontend_web.type.calendar_id>
		),
		from : {
			year : int;
			week : int;
		},
		to : {
			year : int;
			week : int;
		},
		timezone_shift : int,
	) : Promise<
		{
			sources : lib_plankton.map.type_map<
				_zeitbild.frontend_web.type.calendar_id,
				{
					name : string;
				}
			>;
			rows : Array<
				{
					week : int;
					data : Array<
						{
							pit : _zeitbild.frontend_web.helpers.type_pit;
							entries : Array<
								{
									calendar_id : _zeitbild.frontend_web.type.calendar_id;
									event : _zeitbild.frontend_web.type.event_object;
								}
							>;
							today : boolean;
						}
					>;
				}
			>
		}
	>
	{
		const now_pit : _zeitbild.frontend_web.helpers.type_pit = _zeitbild.frontend_web.helpers.pit_now();
		const from_pit : _zeitbild.frontend_web.helpers.type_pit = _zeitbild.frontend_web.helpers.pit_from_year_and_week(
			(from as {year : int; week : int}).year,
			(from as {year : int; week : int}).week,
			{
				"timezone_shift": (timezone_shift as int),
			}
		);
		const to_pit : _zeitbild.frontend_web.helpers.type_pit = _zeitbild.frontend_web.helpers.pit_from_year_and_week(
			(to as {year : int; week : int}).year,
			(to as {year : int; week : int}).week,
			{
				"timezone_shift": (timezone_shift as int),
			}
		);
		
		// prepare
		const entries : Array<
			{
				calendar_id : _zeitbild.frontend_web.type.calendar_id;
				calendar_name : string;
				event : _zeitbild.frontend_web.type.event_object;
			}
		> = await _zeitbild.frontend_web.backend.events(
			from_pit,
			to_pit,
			{
				"calendar_ids": calendar_ids,
			}
		);
		let result : {
			sources : lib_plankton.map.type_map<
				_zeitbild.frontend_web.type.calendar_id,
				{
					name : string;
				}
			>;
			rows : Array<
				{
					week : int;
					data : Array<
						{
							pit : _zeitbild.frontend_web.helpers.type_pit;
							entries : Array<
								{
									calendar_id : _zeitbild.frontend_web.type.calendar_id;
									event : _zeitbild.frontend_web.type.event_object;
								}
							>;
							today : boolean;
						}
					>;
				}
			>;
		} = {
			"sources": lib_plankton.map.hashmap.implementation_map(
				lib_plankton.map.hashmap.make(
					x => x.toFixed(0),
					{
						"pairs": (
							entries
							.map(
								(entry) => (
									{
										"key": entry.calendar_id,
										"value": {
											"name": entry.calendar_name,
										}
									}
								)
							)
						)
					}
				)
			),
			"rows": [],
		};
		let row : Array<
			{
				pit : _zeitbild.frontend_web.helpers.type_pit;
				entries : Array<
					{
						calendar_id : _zeitbild.frontend_web.type.calendar_id;
						event : _zeitbild.frontend_web.type.event_object;
					}
				>;
				today : boolean;
			}
		> = [];
		let day : int = 0;
		while (true) {
			const pit_current : _zeitbild.frontend_web.helpers.type_pit = _zeitbild.frontend_web.helpers.pit_shift_day(
				from_pit,
				day
			);
			if (
				_zeitbild.frontend_web.helpers.pit_is_before(
					pit_current,
					to_pit
				)
			) {
				day += 1;
				row.push(
					{
						"pit": pit_current,
						"entries": [],
						"today": false, // TODO
					}
				);
				if (day % 7 === 0) {
					result.rows.push(
						{
							"week": (
								(from as {year : int; week : int}).week
								+
								Math.floor(day / 7)
								-
								1 // TODO
							),
							"data": row
						}
					);
					row = [];
				}
				else {
					// do nothing
				}
			}
			else {
				break;
			}
		}
		
		// fill
		{
			// events
			(
				entries
				.forEach(
					(entry) => {
						const distance_seconds : int = (
							_zeitbild.frontend_web.helpers.pit_from_datetime(entry.event.begin)
							-
							from_pit
						);
						const distance_days : int = (distance_seconds / (60 * 60 * 24));
						
						const week : int = Math.floor(Math.floor(distance_days) / 7);
						const day : int = (Math.floor(distance_days) % 7);
						
						if ((week >= 0) && (week < result.rows.length)) {
							result.rows[week].data[day].entries.push(entry);
						}
						else {
							// do nothing
						}
					}
				)
			);
			// today
			{
				const distance_seconds : int = (
					now_pit
					-
					from_pit
				);
				const distance_days : int = (distance_seconds / (60 * 60 * 24));
				
				const week : int = Math.floor(Math.floor(distance_days) / 7);
				const day : int = (Math.floor(distance_days) % 7);
				
				if ((week >= 0) && (week < result.rows.length)) {
					result.rows[week].data[day].today = true;
				}
				else {
					// do nothing
				}
			}
		}
		
		return Promise.resolve(result);
	}
	
	
	/**
	 */
	export async function calendar_view_table_html(
		options : {
			calendar_ids ?: (
				null
				|
				Array<_zeitbild.frontend_web.type.calendar_id>
			);
			from ?: {
				year : int;
				week : int;
			};
			to ?: {
				year : int;
				week : int;
			};
			timezone_shift ?: int;
		} = {}
	) : Promise<string>
	{
		const now_pit : _zeitbild.frontend_web.helpers.type_pit = _zeitbild.frontend_web.helpers.pit_now();
		options = Object.assign(
			{
				"calendar_ids": null,
				"from": lib_plankton.call.convey(
					now_pit,
					[
						(x : _zeitbild.frontend_web.helpers.type_pit) => _zeitbild.frontend_web.helpers.pit_shift_week(x, -1),
						_zeitbild.frontend_web.helpers.pit_to_date_object,
						(x : Date) => ({
							"year": x.getFullYear(),
							"week": _zeitbild.frontend_web.helpers.date_object_get_week_of_year(x),
						})
					]
				),
				"to": lib_plankton.call.convey(
					now_pit,
					[
						(x : _zeitbild.frontend_web.helpers.type_pit) => _zeitbild.frontend_web.helpers.pit_shift_week(x, +4),
						_zeitbild.frontend_web.helpers.pit_to_date_object,
						(x : Date) => ({
							"year": x.getFullYear(),
							"week": _zeitbild.frontend_web.helpers.date_object_get_week_of_year(x),
						})
					]
				),
				"timezone_shift": 0,
			},
			options
		);
		const stuff : {
			sources : lib_plankton.map.type_map<
				_zeitbild.frontend_web.type.calendar_id,
				{
					name : string;
				}
			>;
			rows : Array<
				{
					week : int;
					data : Array<
						{
							pit : _zeitbild.frontend_web.helpers.type_pit;
							entries : Array<
								{
									calendar_id : _zeitbild.frontend_web.type.calendar_id;
									event : _zeitbild.frontend_web.type.event_object;
								}
							>;
							today : boolean;
						}
					>;
				}
			>;
		} = await calendar_view_table_data(
			options.calendar_ids,
			options.from,
			options.to,
			options.timezone_shift
		);
		const sources : lib_plankton.map.type_map<
			_zeitbild.frontend_web.type.calendar_id,
			{
				name : string;
				color : lib_plankton.color.type_color;
			}
		> = lib_plankton.map.hashmap.implementation_map(
			lib_plankton.map.hashmap.make(
				(x => x.toFixed(0)),
				{
					"pairs": (
						lib_plankton.map.dump(
							stuff.sources
						)
						.map(
							(pair) => ({
								"key": pair.key,
								"value": {
									"name": pair.value.name,
									"color": lib_plankton.color.give_generic(
										(pair.key - 1),
										{
											"saturation": 0.375,
											"value": 0.375,
										}
									),
								}
							})
						)
					)
				}
			)
		);
		return _zeitbild.frontend_web.helpers.template_coin(
			"tableview",
			{
				"sources": (
					await _zeitbild.frontend_web.helpers.promise_row<string>(
						lib_plankton.map.dump(sources)
						.map(
							({"key": calendar_id, "value": data}) => async () => _zeitbild.frontend_web.helpers.template_coin(
								"tableview-sources-entry",
								{
									"name": data.name,
									"color": lib_plankton.color.output_hex(data.color),
									"rel": calendar_id.toFixed(0),
								}
							)
						)
					)
				).join(""),
				"rows": (
					await _zeitbild.frontend_web.helpers.promise_row<string>(
						stuff.rows
						.map(
							(row) => async () => _zeitbild.frontend_web.helpers.template_coin(
								"tableview-row",
								{
									"week": row.week.toFixed(0).padStart(2, "0"),
									"cells": (
										await _zeitbild.frontend_web.helpers.promise_row<string>(
											row.data
											.map(
												(cell) => async () => _zeitbild.frontend_web.helpers.template_coin(
													"tableview-cell",
													{
														"extra_classes": (
															[""]
															.concat(cell.today ? ["calendar-cell-today"] : [])
															.join(" ")
														),
														"title": lib_plankton.call.convey(
															cell.pit,
															[
																_zeitbild.frontend_web.helpers.pit_to_datetime,
																(x : _zeitbild.frontend_web.helpers.type_datetime) => lib_plankton.string.coin(
																	"{{year}}-{{month}}-{{day}}",
																	{
																		"year": x.date.year.toFixed(0).padStart(4, "0"),
																		"month": x.date.month.toFixed(0).padStart(2, "0"),
																		"day": x.date.day.toFixed(0).padStart(2, "0"),
																	}
																),
															]
														),
														"day": lib_plankton.call.convey(
															cell.pit,
															[
																_zeitbild.frontend_web.helpers.pit_to_datetime,
																(x : _zeitbild.frontend_web.helpers.type_datetime) => lib_plankton.string.coin(
																	"{{day}}",
																	{
																		"year": x.date.year.toFixed(0).padStart(4, "0"),
																		"month": x.date.month.toFixed(0).padStart(2, "0"),
																		"day": x.date.day.toFixed(0).padStart(2, "0"),
																	}
																),
															]
														),
														"entries": (
															await _zeitbild.frontend_web.helpers.promise_row<string>(
																cell.entries
																.map(
																	(entry) => () => _zeitbild.frontend_web.helpers.template_coin(
																		"tableview-cell-entry",
																		{
																			"color": lib_plankton.color.output_hex(
																				sources.get(
																					entry.calendar_id
																				).color
																			),
																			"title": event_generate_tooltip(
																				sources.get(
																					entry.calendar_id
																				).name,
																				entry.event
																			),
																			"name": entry.event.name,
																		}
																	)
																)
															)
														).join(""),
													}
												)
											)
										)
									).join(""),
								}
							)
						)
					)
				).join(""),
			}
		);
	}


	/**
	 */
	async function calendar_view_list_data(
		calendar_ids : Array<_zeitbild.frontend_web.type.calendar_id>,
		options : {
			from ?: _zeitbild.frontend_web.helpers.type_pit;
			to ?: _zeitbild.frontend_web.helpers.type_pit;
			timezone_shift ?: int;
		} = {}
	) : Promise<
		Array<
			{
				calendar_id : _zeitbild.frontend_web.type.calendar_id;
				event : _zeitbild.frontend_web.type.event_object;
			}
		>
	>
	{
		const now_pit : _zeitbild.frontend_web.helpers.type_pit = _zeitbild.frontend_web.helpers.pit_now();
		options = Object.assign(
			{
				"from": lib_plankton.call.convey(
					now_pit,
					[
						(x : _zeitbild.frontend_web.helpers.type_pit) => _zeitbild.frontend_web.helpers.pit_shift_day(x, -1),
					]
				),
				"to": lib_plankton.call.convey(
					now_pit,
					[
						(x : _zeitbild.frontend_web.helpers.type_pit) => _zeitbild.frontend_web.helpers.pit_shift_week(x, +4),
					]
				),
				"timezone_shift": 0,
			},
			options
		);
		
		const entries : Array<
			{
				calendar_id : _zeitbild.frontend_web.type.calendar_id;
				event : _zeitbild.frontend_web.type.event_object;
			}
		> = await _zeitbild.frontend_web.backend.events(
			(options.from as _zeitbild.frontend_web.helpers.type_pit),
			(options.to as _zeitbild.frontend_web.helpers.type_pit),
			{
				"calendar_ids": calendar_ids,
			}
		);
		// TODO: optimize
		entries.sort(
			(entry_1, entry_2) => (
				_zeitbild.frontend_web.helpers.pit_from_datetime(entry_1.event.begin)
				-
				_zeitbild.frontend_web.helpers.pit_from_datetime(entry_2.event.begin)
			)
		);
		
		return Promise.resolve(entries);
	}


	/**
	 */
	export async function calendar_view_list_html(
		calendar_ids : Array<_zeitbild.frontend_web.type.calendar_id>,
		options : {
			from ?: _zeitbild.frontend_web.helpers.type_pit;
			to ?: _zeitbild.frontend_web.helpers.type_pit;
			timezone_shift ?: int;
		} = {}
	) : Promise<string>
	{
		const stuff : Array<
			{
				calendar_id : _zeitbild.frontend_web.type.calendar_id;
				event : _zeitbild.frontend_web.type.event_object;
			}
		> = await calendar_view_list_data(
			calendar_ids,
			options
		);
		return Promise.resolve<string>(
			new lib_plankton.xml.class_node_complex(
				"div",
				{
					"class": "list",
				},
				[
					new lib_plankton.xml.class_node_complex(
						"style",
						{},
						[
							new lib_plankton.xml.class_node_text(
								"html {background-color: #111; color: #FFF; font-family: sans-serif;}\n"
								+
								"table {width: 100%; border-collapse: collapse;}\n"
							)
						]
					),
					new lib_plankton.xml.class_node_complex(
						"ul",
						{
							"class": "list-events",
						},
						(
							stuff
							.map(
								(entry) => (
									new lib_plankton.xml.class_node_complex(
										"li",
										{
											"class": "list-event_entry",
										},
										[
											new lib_plankton.xml.class_node_text(
												JSON.stringify(entry)
											),
										]
									)
								)
							)
						)
					),
				]
			).compile()
		);
	}
	
}
