/*
 * $Id: menu_0_fn.c 464 2019-08-01 02:15:54Z true $
 * begin 20190527 true
 *
 * main menu functions
 */

#include "ui/menu.h"
#include "disp/font.h"

#include "math/sin7.h"

#include "sensor/system.h"
#include "sensor/adxl.h"

#include "user_config.h"

#include <string.h>
#include <stdio.h>


#define ROTATE_TARGET_WIDTH		40
#define ROTATE_TARGET_HEIGHT	32

#define ROTATE_NAME_LEN_FULLRATE		4		// change at your peril
#define ROTATE_NAME_LEN_HALFRATE		9		// change at your peril

uint8_t xdata rotsrc_fb[(ROTATE_TARGET_WIDTH * (ROTATE_TARGET_HEIGHT >> 3)) + 1];
uint8_t xdata rotdst_fb[(ROTATE_TARGET_WIDTH * (ROTATE_TARGET_HEIGHT >> 3)) + 1];

SSD1306 xdata rotsrc;
SSD1306 xdata rotdst;


uint8_t idata wiggle = 1;


static void menu_none_init()
{
	rotsrc.width = rotdst.width   = ROTATE_TARGET_WIDTH;
	rotsrc.height = rotdst.height = ROTATE_TARGET_HEIGHT;

	rotsrc.mode = rotsrc_fb;
	rotsrc.fb = rotsrc_fb + 1;

	rotdst.mode = rotdst_fb;
	rotdst.fb = rotdst_fb + 1;
}

static void menu_none_set_halfwidth(SSD1306 xdata *dst)
{
	if (uconf.nameconf & UCONF_NAME_MODE_HALFWIDTH) {
		dst->state |=  SSD1306_STATE_STR_HALFWIDTH;
	} else {
		dst->state &= ~SSD1306_STATE_STR_HALFWIDTH;
	}
}

static void menu_none_set_flipmirror(uint8_t flip_flag)
{
	if (uconf.nameconf & UCONF_NAME_MODE_AUTOROTATE) {
		if (sysflags & flip_flag) {
			ssd1306_set_flipmirror(1);
		} else {
			ssd1306_set_flipmirror(0);
		}
	} else if (uconf.nameconf & UCONF_NAME_MODE_ROTATE180) {
		ssd1306_set_flipmirror(1);
	} else {
		ssd1306_set_flipmirror(0);
	}
}


const uint8_t code err_namewide_1[] = "Name Too Wide";
const uint8_t code err_namewide_2[] = "Shorten the name, reduce";
const uint8_t code err_namewide_3[] = "spacing or try a smaller font.";

const uint8_t code err_namelong_1[] = "Name Too Long";
const uint8_t code err_namelong_2[] = "Names 10 to 15 chars long";
const uint8_t code err_namelong_3[] = "must use Horizontal orientation.";

static void menu_none_print_error(uint8_t *err1, uint8_t *err2, uint8_t *err3)
{
	ssd1306fb_set_cursor(0, 0);
	ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, err1, 0);
	ssd1306fb_set_cursor(0, 12);
	ssd1306fb_draw_str(font_Dialog_plain_8,           err2, 0);
	ssd1306fb_set_cursor(0, 20);
	ssd1306fb_draw_str(font_Dialog_plain_8,           err3, 0);
	return;
}

void menu_none_disp(uint8_t idx)
{
	uint8_t i, j;
	uint8_t o;
	uint16_t w;

	int8_t left, top;
	int8_t  rot;

	uint8_t xdata txt[2];

	(idx = idx);

	menu_none_init();

	// total width and left / starting boundary
	menu_none_set_halfwidth(&rotsrc);
	ssd1306fb_set_target(&rotsrc);

	w = ssd1306fb_get_str_width(font_table[uconf.font_idx].font,
				uconf.name,
				strlen(uconf.name),
				uconf.char_spacing);

	if (w > oled.width + 16) {
		menu_none_print_error(err_namewide_1, err_namewide_2, err_namewide_3);
	}

	left = (oled.width >> 1) - (w >> 1);
	top = oled.height - ssd1306fb_get_font_height(font_table[uconf.font_idx].font) - 1;

	// get rotation
	rot = adxl345_get_rotation(&adxl);

	// render modes
	switch (uconf.nameconf & UCONF_NAME_DISP_MASK) {
		case UCONF_NAME_DISP_STATIC_HORIZ: {
			menu_none_set_flipmirror(SYS_OLED_ROTATE_X);

			menu_none_set_halfwidth(&oled);
			ssd1306fb_set_target(&oled);

			ssd1306fb_set_cursor(left, top);
			ssd1306fb_draw_str(font_table[uconf.font_idx].font, uconf.name, uconf.char_spacing);
			break;
		}

		case UCONF_NAME_DISP_STATIC_VERT: {
			menu_none_set_flipmirror(SYS_OLED_ROTATE_Y);

			rot = 95;

			goto MENU_0_DISP_CHAR_ROTATE;
		}
		case UCONF_NAME_DISP_WIGGLE: {
			menu_none_set_flipmirror(SYS_OLED_ROTATE_X);

			// why this value? why the fuck not. value is the "speed" of the wiggle
			wiggle += MISC_WIGGLE_RATE;
			wiggle += (uconf.framemod == UCONF_FRAMERATE_FULL) ? 0 : MISC_WIGGLE_RATE;
			// the shift is the maximum "angle" of the wiggle
			rot = (cos7(wiggle) >> MISC_WIGGLE_SHIFT);

			goto MENU_0_DISP_CHAR_ROTATE;
		}
		case UCONF_NAME_DISP_CHAR_ROTATE: {
			ssd1306_set_flipmirror(0);

MENU_0_DISP_CHAR_ROTATE:
			// set pixel printing color - only set it on the output, not on rotation buffers
			ssd1306fb_set_target(&oled);
			ssd1306fb_set_color(uconf.nameconf & UCONF_NAME_MODE_COLOR_INVERT ?
						SSD1306_STATE_INVERT_PIXEL : SSD1306_STATE_SET_PIXEL);

			j = strlen(uconf.name);

			// set framerate, or abort if invalid
			if (j > ROTATE_NAME_LEN_FULLRATE) {
				if (j > ROTATE_NAME_LEN_HALFRATE) {
					menu_none_print_error(err_namelong_1, err_namelong_2, err_namelong_3);
					return;
				} else {
					uconf.framemod = UCONF_FRAMERATE_HALF;
				}
			} else {
				uconf.framemod = UCONF_FRAMERATE_FULL;
			}

			// configure rotation buffer
			ssd1306fb_set_target(&rotsrc);
			ssd1306fb_set_color(SSD1306_STATE_SET_PIXEL);
			menu_none_set_halfwidth(&rotsrc);

			txt[1] = 0;

			for (i = 0; i < strlen(uconf.name); i++) {
				j = i;

				// change character order
				if (uconf.nameconf & UCONF_NAME_DISP_MASK) {
					// this method is a bit jumpy, but works for now
					if (sysflags & SYS_OLED_REVERSE_CHARS) {
						j = strlen(uconf.name) - i - 1;
					}
				}

				txt[0] = uconf.name[j];

				// set target buffer, need to do this before width calc
				// as this will have the halfwidth bit set appropriately
				ssd1306fb_set_target(&rotsrc);

				// get left drawing position, so the character is rendered centered
				o = ssd1306fb_get_str_width(font_table[uconf.font_idx].font, txt, 1, 0);
				w = ((rotsrc.width >> 1) - (o >> 1));

				// clear buffers before work
				ssd1306_cls(&rotdst);
				ssd1306_cls(&rotsrc);

				// render and rotate
				ssd1306fb_set_cursor(w, top);
				ssd1306fb_draw_str(font_table[uconf.font_idx].font, txt, 0);
				ssd1306fb_rotate(&rotsrc, &rotdst, rot);

				// copy dst buffer to oled buffer in correct position
				ssd1306fb_set_target(&oled);
				ssd1306fb_copy(left - w, 0, ROTATE_TARGET_WIDTH, ROTATE_TARGET_HEIGHT, rotdst.fb);

				// update position of character based on spacing
				left += o + uconf.char_spacing;
			}

			break;
		}
	}

	ssd1306fb_set_target(&oled);

	if (uconf.flags & UCONF_FLAGS_SHOW_ACCEL_ANGLE) {
		sprintf(txt, "%+3Bd", adxl345_get_rotation(&adxl));
		ssd1306fb_set_cursor(90, 0);
		ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1);
	}

	if (uconf.flags & UCONF_FLAGS_SHOW_CPU_USAGE) {
		sprintf(txt, "%3Bu%%", cpu_use);
		ssd1306fb_set_cursor(90, 20);
		ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1);
	}

	oled.state &= ~SSD1306_STATE_STR_HALFWIDTH;
}

void menu_0_disp(uint8_t idx)
{
	char xdata txt[12];
	uint8_t w;

	ssd1306fb_set_color(SSD1306_STATE_SET_PIXEL);

	// circle next to item
	ssd1306fb_draw_circle(24, 16, (mtick & 0x04) ? 2 : 1);

	// which item selected?
	ssd1306fb_set_cursor(32, 9);
	switch (idx) {
		case 0: strcpy(txt, "Nametag!");	break;
		case 1: strcpy(txt, "Name Setup");	break;
		case 2: strcpy(txt, "LED Setup");	break;
		case 3: strcpy(txt, "Snek");		break;
		case 4: strcpy(txt, "Morble");		break;
		case 5: strcpy(txt, "Options");		break;
		case 6: strcpy(txt, "About");		break;
	}
	ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1);

	// disabled / incomplete entries
	switch (idx) {
		case 3:
		case 4: {
			w = ssd1306fb_get_str_width(font_DejaVu_Sans_Mono_Bold_11, txt, strlen(txt), 1);
			ssd1306fb_draw_hline(32, w + 32, 16);
			ssd1306fb_draw_hline(32, w + 32, 17);
		}
	}

	// draw extras
	menu_draw_tabs(idx);
	menu_draw_buttons(MENU_BTNSTYLE_MAIN, idx);
}

void menu_0_enter(uint8_t idx)
{
	switch (idx) {
		case 0: {
			menu_stop(0);
			return;
		}
		case 1: {
			menu = &menu_1;
			menu_idx = 0;
			return;
		}
		case 2: {
			menu = &menu_2;
			menu_idx = 0;
			return;
		}
		case 3:
		case 4: {
			return;
		}
		case 5: {
			menu = &menu_5;
			menu_idx = 0;
			return;
		}
		case 6: {
			menu = &menu_6;
			menu_idx = 0;
			return;
		}
	}
}
