// License: MPL-2.0
// (c) 2022 Julian Hurst <ark@mansus.space>

use libtui;
use io;
use unix::tty;

export type error = !(io::error | tty::error);

// A function that displays the widget.
export type print = fn(w: *widget) (void | error);

// A function that frees the resources associated to the widget.
export type finish = fn(w: *widget) void;

// An input listener on a widget. The returning value is intended to be used as
// a signal that will be returned by [[notify]] in order to trigger certain more
// global ui events (terminate the program, change widget focus, etc.). To
// register a listener with a widget, use [[addlistener]].
export type listener = *fn(w: *widget, r: libtui::key) bool;

// A widget is an abstraction around a user-defined UI component. Custom widgets
// can be created through sub-typing:
//
// 	export type my_widget = struct {
// 		widget: widget::widget,
// 		lines: []str,
// 	};
//
// 	fn print(w: *widget::widget) (void | widget::error) = {
// 		const w = w: *my_widget;
// 		for (let i = 0z; i < len(w.lines); i += 1) {
//	 		fmt::println(w.lines[i])!;
//	 	};
// 	};
//
// 	fn finish(w: *widget::widget) void = {
// 		const w = w: *my_widget;
//		free(w.lines);
//		widget::finishcommon(w);
// 	};
//
// 	let list = my_widget {
// 		widget = widget::widget {
//			print = &print,
//			finish = &finish,
//			...
// 		};
// 		lines = strings::split("one,two,three", ","),
// 	};
// 	let l = layout::newlayout(list);
// 	layout::print(l)!;
export type widget = struct {
	print: nullable *print,
	finish: nullable *finish,
	listeners: []listener,
	ui: libtui::ttyui,
};

// Add a listener to the given widget.
export fn addlistener(w: *widget, listener: listener) void = {
	append(w.listeners, listener);
};

// Delete a listener from the given widget.
export fn dellistener(w: *widget, idx: size) void = {
	delete(w.listeners[idx]);
};

// Clear the listeners of the given widget.
export fn clearlisteners(w: *widget) void = {
	w.listeners = [];
};

// Free the widget's listeners.
export fn finishcommon(w: *widget) void = {
	free(w.listeners);
};

// Notify (call) the widget's listeners with the widget and r as a parameter.
// Returns true if a listener returned true, false otherwise.
export fn notify(w: *widget, r: (rune | libtui::specialkey)) bool = {
	for (let i = 0z; i < len(w.listeners); i += 1) {
		if (w.listeners[i](w, r)) {
			return true;
		};
	};
	return false;
};
