/*
 * Logserver
 * Copyright (C) 2017-2025 Joel Reardon
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef __CURSES_WRAPPER__H__
#define __CURSES_WRAPPER__H__

#include <mutex>
#include <ncurses.h>

using namespace std;

/* A wrapper around curses functions to make them threadsafe */
class CursesWrapper {
public:
	/* static mutex holder */
	static inline mutex& get_mutex() {
		static mutex _m;
		return _m;
	}

	/* simulate blocking getch by polling for characters */
	static int getch_blocking() {
		while (true) {
			unique_lock<mutex> ul(get_mutex());
			nodelay(stdscr, TRUE);
			int ret = getch();
			if (ret != ERR) return ret;
			ul.unlock();
			this_thread::sleep_for(chrono::milliseconds(3));
		}
	}

	/* calls getch without blocking */
	static int getch_nonblocking() {
		unique_lock<mutex> ul(get_mutex());
		nodelay(stdscr, TRUE);
		return getch();
	}

	/* puts the current cursor yx coords into parms */
	static void get_yx(size_t* y, size_t* x) {
		unique_lock<mutex> ul(get_mutex());
		*y = getcury(stdscr);
		*x = getcurx(stdscr);
	}

	/* moves to the yx position in the parms */
	static void move_yx(int y, int x) {
		unique_lock<mutex> ul(get_mutex());
		wmove(stdscr, y, x);
	}

	/* for an attr defined in the paramter, turns it on or off depending on
	 * the boolean second parameter */
	static int attr(NCURSES_ATTR_T& attr, bool on) {
		unique_lock<mutex> ul(get_mutex());
		if (on) return wattron(stdscr, attr);
		return wattroff(stdscr, attr);
	}

	/* clears to the end of the line */
	static int clear_eol() {
		unique_lock<mutex> ul(get_mutex());
		return wclrtoeol(stdscr);
	}

	/* start of window work goes here */
	static void start_win() {
	}

	/* locks ncurses and calls end win */
	static int end_win() {
		unique_lock<mutex> ul(get_mutex());
		return endwin();
	}

	/* puts the char ch at position yx */
	static int add_ch(int y, int x, const chtype ch) {
		unique_lock<mutex> ul(get_mutex());
		if (wmove(stdscr, y, x) == ERR) return ERR;
		return waddch(stdscr, ch);
	}

	/* refreshes the screen */
	static void refresh() {
		unique_lock<mutex> ul(get_mutex());
		::refresh();
	}
};

#endif  // __CURSES_WRAPPER__H__
