// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2019 Fredrik Noring
 */

#ifndef VT_H
#define VT_H

#include <stdarg.h>

#include "internal/compare.h"
#include "internal/fifo.h"

#include "toslibc/unicode/utf8.h"

#include "vt-cmd.h"

typedef char vt_char;

struct vt_attr {
	union {
		struct {
			uint8_t reverse : 1;
		};
		uint8_t state;
	};
};

struct vt_char_attr {
	vt_char code;
	struct vt_attr attr;
};

struct vt_row {		/* FIXME */
	int begin;
	int end;
};

struct vt_col {		/* FIXME */
	int begin;
	int end;
};

struct vt_buffer {
	bool clear;
	struct {
		struct {
			int rows;
			int cols;
		} size;
		vt_char *chars;
		struct vt_attr *attrs;
	} client, server;
	struct {
		int row;
		int col;
		struct vt_attr attr;
	} cursor;
	struct {
		int row;
		int col;
		size_t offset;
		size_t index;
		size_t size;
		uint8_t chars[32];
		bool redraw;
	} output;
	struct {
		bool escape;
		bool drain;
		uint64_t timestamp;
		size_t size;
		size_t index;
		char buffer[16];
	} input;
	const struct vt_cmd *cmd;
};

#define DECLARE_VT(rows_, cols_)					\
	struct {							\
		vt_char client_chars[rows_][cols_];			\
		vt_char server_chars[rows_][cols_];			\
		struct vt_attr client_attrs[rows_][cols_];		\
		struct vt_attr server_attrs[rows_][cols_];		\
		struct vt_buffer vtb;					\
	}

#define INIT_VT(id_, cmd_)						\
{									\
	.vtb = {							\
		.client = {						\
			.size = {					\
				.rows = ARRAY_SIZE(*id_.server_chars),	\
				.cols = ARRAY_SIZE(id_.server_chars),	\
			},						\
			.chars = &id_.client_chars[0][0],		\
			.attrs = &id_.client_attrs[0][0],		\
		},							\
		.server = {						\
			.size = {					\
				.rows = ARRAY_SIZE(*id_.client_chars),	\
				.cols = ARRAY_SIZE(id_.client_chars),	\
			},						\
			.chars = &id_.server_chars[0][0],		\
			.attrs = &id_.server_attrs[0][0],		\
		},							\
		.cmd = cmd_						\
	}								\
}

#define DEFINE_VT(id_, rows_, cols_, cmd_)				\
	DECLARE_VT(rows_, cols_) id_ = INIT_VT(id_, cmd_)

void vt_putc(struct vt_buffer *vtb, int row, int col,
	vt_char c, struct vt_attr attr);

void vt_putc_normal(struct vt_buffer *vtb, int row, int col, vt_char c);
void vt_putc_reverse(struct vt_buffer *vtb, int row, int col, vt_char c);

int vt_printf(struct vt_buffer *vtb, int row, int col,
   struct vt_attr attr, const char *fmt, ...)
   __attribute__((format(printf, 5, 6)));

int vt_vprintf(struct vt_buffer *vtb, int row, int col,
	struct vt_attr attr, const char *fmt, va_list ap);

uint8_t vt_getc(struct vt_buffer *vtb);

ssize_t vt_read(struct vt_buffer *vtb, void *data, size_t count);

ssize_t vt_write_fifo(struct vt_buffer *vtb, struct fifo *f);

ssize_t vt_read_utf8_from_charset(struct vt_buffer *vtb,
	void *data, size_t count,
	unicode_t (*charset_to_utf32)(uint8_t c, void *arg), void *arg);

ssize_t vt_write_fifo_utf8_from_charset(struct vt_buffer *vtb, struct fifo *f,
	unicode_t (*charset_to_utf32)(uint8_t c, void *arg), void *arg);

uint64_t vt_event(struct vt_buffer *vtb, uint64_t timestamp);

ssize_t vt_deescape_fifo(struct vt_buffer *vtb,
	struct fifo *dst, struct fifo *src, uint64_t timestamp);

void vt_clear(struct vt_buffer *vtb);

void vt_redraw(struct vt_buffer *vtb);

struct vt_text vt_cursor_end(struct vt_buffer *vtb);

struct vt_text vt_reset(struct vt_buffer *vtb);

void vt_client_resize(struct vt_buffer *vtb, int rows, int cols);

extern struct vt_attr vt_attr_normal;
extern struct vt_attr vt_attr_reverse;

#endif /* VT_H */
