#include <stdio.h>
#include <string.h>
#include "../termbox.h"

static const char chars[] = "nnnnnnnnnbbbbbbbbbuuuuuuuuuBBBBBBBBB";

static const uint16_t all_attrs[] = {
	0,
	TB_BOLD,
	TB_UNDERLINE,
	TB_BOLD | TB_UNDERLINE,
};

static int next_char(int current) {
	current++;
	if (!chars[current])
		current = 0;
	return current;
}

static void draw_line(int x, int y, uint16_t bg) {
	int a, c;
	int current_char = 0;
	for (a = 0; a < 4; a++) {
		for (c = TB_DEFAULT; c <= TB_WHITE; c++) {
			uint16_t fg = all_attrs[a] | c;
			tb_change_cell(x, y, chars[current_char], fg, bg);
			current_char = next_char(current_char);
			x++;
		}
	}
}

static void print_combinations_table(int sx, int sy, const uint16_t *attrs, int attrs_n) {
	int i, c;
	for (i = 0; i < attrs_n; i++) {
		for (c = TB_DEFAULT; c <= TB_WHITE; c++) {
			uint16_t bg = attrs[i] | c;
			draw_line(sx, sy, bg);
			sy++;
		}
	}
}

static void draw_all() {
	tb_clear();

	tb_select_output_mode(TB_OUTPUT_NORMAL);
	static const uint16_t col1[] = {0, TB_BOLD};
	static const uint16_t col2[] = {TB_REVERSE};
	print_combinations_table(1, 1, col1, 2);
	print_combinations_table(2 + strlen(chars), 1, col2, 1);
	tb_present();

	tb_select_output_mode(TB_OUTPUT_GRAYSCALE);
	int c, x, y;
	for (x = 0, y = 23; x < 24; ++x) {
		tb_change_cell(x, y, '@', x, 0);
		tb_change_cell(x+25, y, ' ', 0, x);
	}
	tb_present();

	tb_select_output_mode(TB_OUTPUT_216);
	y++;
	for (c = 0, x = 0; c < 216; ++c, ++x) {
		if (!(x%24)) {
			x = 0;
			++y;
		}
		tb_change_cell(x, y, '@', c, 0);
		tb_change_cell(x+25, y, ' ', 0, c);
	}
	tb_present();

	tb_select_output_mode(TB_OUTPUT_256);
	y++;
	for (c = 0, x = 0; c < 256; ++c, ++x) {
		if (!(x%24)) {
			x = 0;
			++y;
		}
		tb_change_cell(x, y, '+', c | ((y & 1) ? TB_UNDERLINE : 0), 0);
		tb_change_cell(x+25, y, ' ', 0, c);
	}
	tb_present();
}

int main(int argc, char **argv) {
	(void)argc; (void)argv;
	int ret = tb_init();
	if (ret) {
		fprintf(stderr, "tb_init() failed with error code %d\n", ret);
		return 1;
	}

	draw_all();

	struct tb_event ev;
	while (tb_poll_event(&ev)) {
		switch (ev.type) {
		case TB_EVENT_KEY:
			switch (ev.key) {
			case TB_KEY_ESC:
				goto done;
				break;
			}
			break;
		case TB_EVENT_RESIZE:
			draw_all();
			break;
		}
	}
done:
	tb_shutdown();
	return 0;
}
