'use strict';

import { glob, basename, realpath, chdir, mkstemp } from "fs";

export const TYPE_ARRAY = 1;
export const TYPE_STRING = 3;
export const TYPE_INT = 5;
export const TYPE_BOOL = 7;

export function parse_bool(val)
{
	switch (val) {
	case "1":
	case "true":
		return true;
	case "0":
	case "false":
		return false;
	}
};

export function parse_array(val)
{
	if (type(val) != "array")
		val = split(val, /\s+/);
	return val;
};

function __type_parsers()
{
	let ret = [];

	ret[TYPE_ARRAY] = parse_array;
	ret[TYPE_STRING] = function(val) {
		return val;
	};
	ret[TYPE_INT] = function(val) {
		return +val;
	};
	ret[TYPE_BOOL] = parse_bool;

	return ret;
}
export const type_parser = __type_parsers();

export function handler_load(path, cb)
{
	for (let script in glob(path + "/*.sh")) {
		script = basename(script);

		let f = mkstemp();
		let prev_dir = realpath(".");
		chdir(path);
		system(`./${script} "" "dump" >&${f.fileno()}`);
		chdir(prev_dir);
		f.seek();
		while (!f.error()) {
			let data = trim(f.read("line"));
			try {
				data = json(data);
			} catch (e) {
				continue;
			}

			if (type(data) != "object")
				continue;

			cb(script, data);
		}
		f.close();
	}
};

export function handler_attributes(data, extra, validate)
{
	let ret = { ...extra };
	for (let cur in data) {
		let name_data = split(cur[0], ":", 2);
		let name = name_data[0];
		ret[name] = cur[1];
		if (validate && name_data[1])
			validate[name] = name_data[1];
	}
	return ret;
};

export function parse_attribute_list(data, spec)
{
	let ret = {};

	for (let name, type_id in spec) {
		if (!(name in data))
			continue;

		let val = data[name];
		let parser = type_parser[type_id];
		if (parser)
			val = parser(val);
		ret[name] = val;
	}

	return ret;
};

export function is_equal(val1, val2) {
	let t1 = type(val1);

	if (t1 != type(val2))
		return false;

	if (t1 == "array") {
		if (length(val1) != length(val2))
			return false;

		for (let i = 0; i < length(val1); i++)
			if (!is_equal(val1[i], val2[i]))
				return false;

		return true;
	} else if (t1 == "object") {
		for (let key in val1)
			if (!is_equal(val1[key], val2[key]))
				return false;
		for (let key in val2)
			if (val1[key] == null)
				return false;
		return true;
	} else {
		return val1 == val2;
	}
};
