/**
 */
async function main(
) : Promise<void>
{
	await _heimdall.init();
	
	// consts
	const version : string = "0.9";
	
	// args
	const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler(
		{
			"order_path": new lib_plankton.args.class_argument(
				{
					"name": "order_path",
					"type": lib_plankton.args.enum_type.string,
					"kind": lib_plankton.args.enum_kind.positional,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": "monitoring.hmdl.json",
					"parameters": {
						"index": 0,
					},
					"info": lib_plankton.translate.get("help.args.order_path"),
				}
			),
			"show_help": new lib_plankton.args.class_argument(
				{
					"name": "help",
					"type": lib_plankton.args.enum_type.boolean,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": false,
					"parameters": {
						"indicators_long": ["help"],
						"indicators_short": ["h"],
					},
					"info": lib_plankton.translate.get("help.args.show_help"),
				}
			),
			"show_version": new lib_plankton.args.class_argument(
				{
					"name": "version",
					"type": lib_plankton.args.enum_type.boolean,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": false,
					"parameters": {
						"indicators_long": ["version"],
						"indicators_short": ["r"],
					},
					"info": lib_plankton.translate.get("help.args.show_version"),
				}
			),
			"show_schema": new lib_plankton.args.class_argument(
				{
					"name": "schema",
					"type": lib_plankton.args.enum_type.boolean,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": false,
					"parameters": {
						"indicators_long": ["schema"],
						"indicators_short": ["s"],
					},
					"info": lib_plankton.translate.get("help.args.show_schema"),
				}
			),
			"expose_full_order": new lib_plankton.args.class_argument(
				{
					"name": "expose_full_order",
					"type": lib_plankton.args.enum_type.boolean,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": false,
					"parameters": {
						"indicators_long": ["expose-full-order"],
						"indicators_short": ["e"],
					},
					"info": lib_plankton.translate.get("help.args.expose_full_order"),
				}
			),
			"erase_state": new lib_plankton.args.class_argument(
				{
					"name": "erase_state",
					"type": lib_plankton.args.enum_type.boolean,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": false,
					"parameters": {
						"indicators_long": ["erase-state"],
						"indicators_short": ["x"],
					},
					"info": lib_plankton.translate.get("help.args.erase_state"),
				}
			),
			"database_path": new lib_plankton.args.class_argument(
				{
					"name": "database_path",
					"type": lib_plankton.args.enum_type.string,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": null,
					"parameters": {
						"indicators_long": ["database-path"],
						"indicators_short": ["d"],
					},
					"info": lib_plankton.translate.get("help.args.database_path"),
				}
			),
			"mutex_path": new lib_plankton.args.class_argument(
				{
					"name": "mutex_path",
					"type": lib_plankton.args.enum_type.string,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": "/tmp/heimdall.lock",
					"parameters": {
						"indicators_long": ["mutex-path"],
						"indicators_short": ["m"],
					},
					"info": lib_plankton.translate.get("help.args.mutex_path"),
				}
			),
			"send_ok_notifications": new lib_plankton.args.class_argument(
				{
					"name": "send_ok_notifications",
					"type": lib_plankton.args.enum_type.boolean,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": false,
					"parameters": {
						"indicators_long": ["send-ok-notifications"],
						"indicators_short": ["y"],
					},
					"info": lib_plankton.translate.get(
						"help.args.send_ok_notifications",
						{
							"condition_name": lib_plankton.translate.get("conditions.ok"),
						}
					),
				}
			),
			"language": new lib_plankton.args.class_argument(
				{
					"name": "language",
					"type": lib_plankton.args.enum_type.string,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": null,
					"parameters": {
						"indicators_long": ["language"],
						"indicators_short": ["l"],
					},
					"info": lib_plankton.translate.get("help.args.language"),
				}
			),
			"time_to_live": new lib_plankton.args.class_argument(
				{
					"name": "time_to_live",
					"type": lib_plankton.args.enum_type.float,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": (60 * 60 * 24 * 7),
					"parameters": {
						"indicators_long": ["time-to-live"],
						"indicators_short": ["t"],
					},
					"info": lib_plankton.translate.get("help.args.time_to_live"),
				}
			),
			"working_directory": new lib_plankton.args.class_argument(
				{
					"name": "working_directory",
					"type": lib_plankton.args.enum_type.string,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": ".",
					"parameters": {
						"indicators_long": ["working-directory"],
						"indicators_short": ["w"],
					},
					"info": lib_plankton.translate.get("help.args.working_directory"),
				}
			),
			"verbosity": new lib_plankton.args.class_argument(
				{
					"name": "verbosity",
					"type": lib_plankton.args.enum_type.integer,
					"kind": lib_plankton.args.enum_kind.volatile,
					"mode": lib_plankton.args.enum_mode.replace,
					"default": 1,
					"parameters": {
						"indicators_long": ["verbosity"],
						"indicators_short": ["v"],
					},
					"info": lib_plankton.translate.get("help.args.verbosity"),
				}
			),
		}
	);
	const args : Record<string, any> = arg_handler.read(
		lib_plankton.args.enum_environment.cli,
		process.argv.slice(2).join(" ")
	);
	
	// setup logging
	lib_plankton.log.conf_push(
		[
			new lib_plankton.log.class_channel_minlevel(
				new lib_plankton.log.class_channel_stdout(),
				[
					lib_plankton.log.enum_level.debug,
					lib_plankton.log.enum_level.info,
					lib_plankton.log.enum_level.notice,
					lib_plankton.log.enum_level.warning,
					lib_plankton.log.enum_level.error,
				][Math.min(4, /*args["verbosity"]*/0)]
			),
		]
	);
	
	// exec
	if (args.show_help) {
		process.stdout.write(
			arg_handler.generate_help(
				{
					"programname": "heimdall",
					"description": lib_plankton.translate.get("help.title"),
					"executable": "heimdall",
				}
			)
		);
	}
	else {
		if (args["show_version"]) {
			process.stdout.write(version + "\n");
		}
		else {
			if (args["show_schema"]) {
				process.stdout.write(
					lib_plankton.json.encode(
						_heimdall.order.schema_root(
						),
						true
					)
					+
					"\n"
				)
			}
			else {
				const order_path : string = (
					args["order_path"].startsWith("/")
					? args["order_path"]
					: (args["working_directory"] + "/" + args["order_path"])
				);
				const nm_path = require("path");
				const nm_fs = require("fs");
				if (! nm_fs.existsSync(order_path)) {
					lib_plankton.log.error(
						lib_plankton.translate.get("misc.order_file_not_found"),
						{
							"path": args["order_path"],
						}
					);
				}
				else {
					const order : _heimdall.type_order = await _heimdall.order.load(
						nm_path.normalize(order_path)
					);
					if (args["expose_full_order"]) {
						process.stdout.write(lib_plankton.json.encode(order, true) + "\n");
					}
					else {
						await _heimdall.master.wrap_mutex(
							args["mutex_path"],
							() => _heimdall.master.wrap_database(
								args["database_path"],
								args["order_path"],
								async () => {
									let ordered_to_quit : boolean = false;
									let deferral_id : (null | int) = null;
									const stop = function () {
										ordered_to_quit = true;
										if (deferral_id === null) {
											// do nothing
										}
										else {
											lib_plankton.call.deferral_abort(deferral_id);
										}
									};
									process.on(
										"SIGINT",
										() => {
											lib_plankton.log.info("main_received_sigint", {});
											stop();
										}
									);
									process.on(
										"SIGTERM",
										() => {
											lib_plankton.log.info("main_received_sigterm", {});
											stop();
										}
									);
									while (! ordered_to_quit) {
										// cleanup
										{
											lib_plankton.log.debug("cleanup_starting", {});
											await _heimdall.master.clean(
												{
													"time_to_live": args["time_to_live"],
													"erase_state": args["erase_state"],
												}
											);
											lib_plankton.log.debug("cleanup_ended", {});
										}
										// run checks
										{
											lib_plankton.log.debug("checks_starting", {});
											await _heimdall.master.run(
												order,
												{
													"send_ok_notifications": args["send_ok_notifications"],
												}
											);
											lib_plankton.log.debug("checks_ended", {});
										}
										// pause
										{
											let {timeout_id, promise} = lib_plankton.call.timeout_start<void>(
												new Promise<void>(
													(resolve, reject) => {
														while (! ordered_to_quit) {
															// laze
														}
														resolve(undefined);
													}
												),
												5.0
											);
											await promise;
										}
									}
								}
							)
						)
						.catch(
							() => {process.exit(2);}
						);
					}
				}
			}
		}
	}
}


main();
