#include "interface.h"
#include "bassofono.h"
#include <stdint.h>

uint8_t menu_item, menu_page;
uint8_t menu_last_item[MENU_PAGE_EOM + 1];

/*
typedef void (*menu_set_function)(void);
typedef void (*menu_print_function)(uint8_t a);

struct menu_item {
	uint8_t page;
	char name[14];
	uint8_t type;
	uint8_t size;
	uint8_t row;
	uint8_t col;
	uint32_t step;
	uint32_t min;
	uint32_t max;
	uint8_t wrap;
	char suffix[3];
	uint32_t *varptr;
	menu_set_function set_function_ptr;
	menu_print_function print_function_ptr;
};
*/

// size deve comprendere lo spazio per il '>', eccetto che per i campi NED
// set_function_ptr viene applicata dopo che varptr e' stata modificata con

//			    name,          type,    size,row,col,step,	min,	max,	wrap	suffix	*varptr,		set_function_ptr	print_function_ptr
struct menu_item items[] = {
	{MENU_PAGE_DEFAULT, "  Frequenza", TYP_INT, 9,	1,  0,	 100,	1000,	1750000,WRAP,	"",  " Hz",	&canale.frequenza,			&set_frequency, 	&print_frequency},
//	{MENU_PAGE_DEFAULT, "     Rit   ", TYP_INT, 4,	2,  0,	 10,	0,	9999,	SAT,	"",  "",	&rit,				&set_frequency, 	&print_frequency},
	{MENU_PAGE_DEFAULT, "   Volume  ", TYP_INT, 5,	2,  0,	 1,	0,	32,	SAT,	"",  "|",	&stato.volume,			&set_dummy, 		&print_bar},
	{MENU_PAGE_DEFAULT, "  Guadagno ", TYP_INT, 1,	2,  7,	 1,	1,	6,	SAT,	"",  "x",	&rx_gain,			&set_rx_gain, 		&print_integer},
	{MENU_PAGE_DEFAULT, "Modulazione", TYP_INT, 3,	2,  10,	 1,	0,	6,	WRAP,	"",  "",	&canale.modulazione,		&imposta_modulazione,	&print_modulation},
//	{MENU_PAGE_DEFAULT, " Squelch   ", TYP_INT, 2,	3,  10,	 1,	0,	32,	SAT,	"",  "",	&squelch,			&set_dummy,		&print_integer},

	{MENU_PAGE_AUDIO,   " Filtro CF ", TYP_INT, 4,	1,  0,	 50,	50,	3500,	SAT,	"",  " Hz",	&audio_filter_freq, 		&set_rx_audio_filter,	&print_integer},
	{MENU_PAGE_AUDIO,   " Filtro BP ", TYP_INT, 4,	2,  0,	 50,	50,	2500,	SAT,	"",  " Hz",	&audio_filter_bw, 		&set_rx_audio_filter,	&print_integer},
	{MENU_PAGE_AUDIO,   " Filtro Q  ", TYP_INT, 2,	3,  0,	 1,	1,	32,	SAT,	"",  " Q",	&audio_filter_beta, 		&set_rx_audio_filter,	&print_integer},

	{MENU_PAGE_MEM,     "   Nome    ", TYP_ALPHANUM, 14,	1,  0,	 1,	0,	0,	SAT,	"",  "",&audio_filter_beta, 		&set_dummy,		&print_string},
	{MENU_PAGE_MEM,	    "   Numero  ", TYP_ALPHANUM, 2,	2,  0,	 1,	100,	100,	SAT,	"",  "",canale.nome, 			&set_dummy,		&print_string},


	{MENU_PAGE_ALL, "   Segnale ", 	   TYP_NED, 13,	4,  0,	 0,	0,	0,	SAT,	"S",  "",	&s_meter,	&set_dummy,	&print_bar},
	{MENU_PAGE_ALL, "   Tabs    ",     TYP_NED, 3,	5,  0,	 0,	0,	0,	SAT,	"",  "",	"PTT", 		&set_dummy,	&print_string},
	{MENU_PAGE_ALL, "   Tabs    ",     TYP_NED, 3,	5,  4,	 0,	0,	0,	SAT,	"",  "",	"SET", 		&set_dummy,	&print_string},
	{MENU_PAGE_ALL, "   Tabs    ",     TYP_NED, 2,	5,  9,	 0,	0,	0,	SAT,	"",  "",	"BL", 		&set_dummy,	&print_string},
	{MENU_PAGE_ALL, "   Tabs    ",     TYP_NED, 1,	5,  12,	 0,	0,	0,	SAT,	"",  "",	"M", 		&set_dummy,	&print_string},
};

/*
struct menu_item tabs[] = {
	{MENU_PAGE_DEFAULT, "SCN", 	TYP_INT, 3,	0, 0,	1,	0,	3,	WRAP,	"Hz",     &scan,			&set_dummy,	&print_integer},
};
*/

uint8_t menu_item_count = sizeof(items)/sizeof(items[0]);
// uint8_t tabs_count = sizeof(tabs)/sizeof(tabs[0]);

char modulation_list[][4] = {
	[MOD_DC] = "DC",
	[MOD_LSB] = "LSB",
	[MOD_USB] = "USB",
	[MOD_CWL] = "CWL",
	[MOD_CWU] = "CWU",
	[MOD_AM] = "AM",
	[MOD_FM] = "FM"
};

uint8_t modulation_list_count = sizeof(modulation_list)/sizeof(modulation_list[0]);

char status_list[][3] = {
	[STATUS_RX] = "Rx",
	[STATUS_TX] = "Tx",
	[STATUS_SQ] = "Sq",
};

uint8_t status_list_count = sizeof(status_list)/sizeof(status_list[0]);

// == ################################ ==

void decode_cmd(char cmd){
        switch(cmd){
                case ENRH:
                        encoder_increment();
                        click();
                        break;
                case ENLH:
                        encoder_decrement();
                        click();
                        break;
                case JSRP:
                        joystick_dx();
                        click();
                        break;
                case JSLP:
                        joystick_sx();
                        click();
                        break;
                case JSUP:
                        joystick_up();
                        click();
                        break;
                case JSDP:
                        joystick_down();
                        click();
                        break;
                case JSBP:
                	joystick_button();
                        click();
                	break;
                case BT1P:
                	tab_up(0);
                        break;
                case BT2P:
                      	tab_up(1);
                        break;
                case BT3P:
                      	tab_up(2);
                        break;
                case BT4P:
                      	tab_up(3);
                        break;
                case BT1R:
                	tab_down(0);
                        break;
                case BT2R:
                      	tab_down(1);
                        break;
                case BT3R:
                      	tab_down(2);
                        break;
                case BT4R:
                      	tab_down(3);
                        break;
        }

}

void encoder_increment(void){
	if(items[menu_item].type == TYP_INT) integer_editor_up(menu_item);
	else if(items[menu_item].type == TYP_ALPHANUM) string_editor_up(menu_item);
	items[menu_item].set_function_ptr();
}

void encoder_decrement(void){
	if(items[menu_item].type == TYP_INT) integer_editor_down(menu_item);
	else if(items[menu_item].type == TYP_ALPHANUM) string_editor_down(menu_item);
	items[menu_item].set_function_ptr();
}

void joystick_dx(void){
	if(items[menu_item].type == TYP_INT) step_down(menu_item);
	else if(items[menu_item].type == TYP_ALPHANUM) string_editor_destra(menu_item);
}

void joystick_sx(void){
	if(items[menu_item].type == TYP_INT) step_up(menu_item);
	else if(items[menu_item].type == TYP_ALPHANUM) string_editor_sinistra(menu_item);
}

void joystick_down(void){
	menu_item_up();
}

void joystick_up(void){
	menu_item_down();
}

void joystick_button(void){
}

void menu_item_up(void){
	set_changed(menu_item); // pulisci vecchio
	menu_item++;
//	if((items[menu_item].type == TYP_NED) || (items[menu_item].page != menu_page)) menu_item++;
	while((items[menu_item].type == TYP_NED) || (items[menu_item].page != menu_page)){
		menu_item++;
		if(menu_item >= menu_item_count) menu_item = 0;
	}
	set_changed(menu_item); // cursore nel nuovo
	// nome
	display_update_item();
}

void menu_item_down(void){
	set_changed(menu_item); // pulisci vecchio
	menu_item--;
	if(menu_item >= menu_item_count) menu_item = menu_item_count - 1;
//	if(menu_item >= menu_item_count) menu_item = menu_item_count - 1;
	// if((items[menu_item].type == TYP_NED) || (items[menu_item].page != menu_page)) menu_item--;
//	if(menu_item >= menu_item_count) menu_item = menu_item_count - 1;
	while((items[menu_item].type == TYP_NED) || (items[menu_item].page != menu_page)){
		menu_item--;
		if(menu_item >= menu_item_count) menu_item = menu_item_count - 1;
	}
	
	set_changed(menu_item); // nuovo
	display_update_item();
}

void step_up(uint8_t mode){
	if((items[mode].step * 10) < items[mode].max)	items[mode].step *= 10;
}

void step_down(uint8_t mode){
	if(items[mode].step >= 10) items[mode].step /= 10;
}

void interface_set_default(void){
	menu_item = 0;
	menu_page = MENU_PAGE_DEFAULT;
	menu_last_item[MENU_PAGE_DEFAULT] = 0;
	menu_last_item[MENU_PAGE_AUDIO] = 4;
//	strcpy(tabstring, "TX SET MEM NO");
}

void display_set_position(uint8_t row, uint8_t col){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[%d,%dz", col, row);
}

/*
void display_print_string(uint8_t row, uint8_t col, char * string){
	display_set_position(row,col);
	enqueue_tx(string, strlen(string));
}
*/ 

void display_update_item(void){
	display_set_position(MENU_NAME_ROW,MENU_NAME_COL);
        uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"%d %-12s", menu_item, items[menu_item].name);
}

void display_update_state(void){
//	uint8_t var;
	for(uint8_t item_idx = 0; item_idx < (menu_item_count); item_idx++){
		if(get_changed(item_idx)){
			if(((items[item_idx].page == menu_page) || (items[item_idx].page == MENU_PAGE_ALL) )&& (items[item_idx].type != TYP_HID)){
				// posizionati
		                display_set_position(items[item_idx].row,items[item_idx].col);
	        	        // setta o meno il >
	        	        uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx, items[item_idx].prefix);
	                	if(items[item_idx].type != TYP_NED){
		                	if(item_idx == menu_item) uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx, ">");
			                else {
						uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx, " ");
		                	}
		                }
	        	        // stampa valore
//	        	        if(items[item_idx].type != TYP_HID) items[item_idx].print_function_ptr(item_idx);
	        	        items[item_idx].print_function_ptr(item_idx);
	        	        uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx, items[item_idx].suffix);

				// if(items[item_idx].type == TYP_INT) uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"%0*ld", items[item_idx].size, * items[item_idx].varptr);
		                // if(items[item_idx].type == TYP_LIST) uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"%*s", items[item_idx].size, &items[item_idx].mapptr[* items[item_idx].varptr]);
			}
			// resetta
                	reset_changed(item_idx);
	        }
	}
}

void integer_editor_up(uint8_t mode){
	* items[mode].varptr += items[mode].step;
	if((* items[mode].varptr < items[mode].min) || (* items[mode].varptr > items[mode].max)){
		if(items[mode].wrap){
			* items[mode].varptr = items[mode].min;
		}
		else{
			* items[mode].varptr = items[mode].max;
		}
	}
	set_changed(mode);
}

void integer_editor_down(uint8_t mode){
	* items[mode].varptr -= items[mode].step;
	if((* items[mode].varptr < items[mode].min) || (* items[mode].varptr > items[mode].max)){
		if(items[mode].wrap){
			* items[mode].varptr = items[mode].max;
		}
        	else{
			* items[mode].varptr = items[mode].min;
		}
	}
	set_changed(mode);
}

void string_editor_up(uint8_t mode){
}
void string_editor_down(uint8_t mode){
}
void string_editor_sinistra(uint8_t mode){
}
void string_editor_destra(uint8_t mode){
}


void list_editor_down(uint8_t mode){

}

void tabs_update(void){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\a");
}

void tab_up(uint8_t tab){
        switch(tab){
                case 0:
			ferma_ricezione();
			avvia_trasmissione();
                        break;
                case 1:
  			menu_last_item[menu_page] = menu_item;
			menu_page++;
			if(menu_page > MENU_PAGE_EOM) menu_page = MENU_PAGE_SOM;
			menu_item = menu_last_item[menu_page];

			state_changed = 0xFFFF;
			clear_display();
			display_update_item();
			display_update_state();
                        click();
                        break;
               case 2:
//                        encoder_increment();
//                        click();
			display_backlight_on();
                        break;
               case 3:
//                        encoder_decrement();
                        click();
                        break;
	}
}

void tab_down(uint8_t tab){
        switch(tab){
                case 0:
                        ferma_trasmissione();
                        avvia_ricezione();
                        break;
                case 2:
                	display_backlight_off();
                	break;
        }

}

void display_init(void){
	// https://git.lattuga.net/asdrea/tosta
	// caratteri print_bar
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[128,127,0,0,0,0,0c");
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[129,127,127,0,0,0,0c");
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[130,127,127,127,0,0,0c");
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[131,127,127,127,127,0,0c");
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[132,127,127,127,127,127,0c");
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[133,127,127,127,127,127,127c");

	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[%ds",DISPLAY_STANDBY_TIMER);
//	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[150,100q");
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[%db",0);
//	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\a");
	clear_display();
}

// menu prints
void print_dummy(uint8_t item_idx){
}

void print_integer(uint8_t item_idx){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"%*ld", items[item_idx].size, * items[item_idx].varptr);
}

void print_string(uint8_t item_idx){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"%*s", items[item_idx].size, items[item_idx].varptr);
}

void print_modulation(uint8_t item_idx){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"%*s", items[item_idx].size, modulation_list[*items[item_idx].varptr]);
}

void print_bar(uint8_t item_idx){
	// il range massimo e' items[item_idx].size * 6
        uint8_t i, cols;
        cols = *items[item_idx].varptr;
        char buf[items[item_idx].size];

        for( i = 0; i < items[item_idx].size; i++){
                if(cols >= 6){
                        buf[i] = 133;
                } else if (cols > 0){
                        buf[i] = 128 + cols;
                } else {
                        buf[i] = 32;
                }
                cols = sat_subu8b(cols, 6);
        }
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx, buf);
}

void print_frequency(uint8_t item_idx){
	char bufin[14];
	char bufout[14];
	uint8_t i, j;
	j = 0;
	sprintf(bufin,"%8ld", * items[item_idx].varptr);
	for(i=0; bufin[i] != '\0'; i++){
		if((((strlen(bufin)-i)%3)==0) && (i != 0)) {
			if(bufin[i-1] == ' '){
				bufout[j] = ' ';
			} else {
				bufout[j] = '.';
			}
			j++;
		}
		bufout[j] = bufin[i];
		j++;
	}
	bufout[j] = '\0';
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"%s", bufout);
}

// ###

void scan_do(uint8_t scan_state){
        static uint8_t scan_timer;
        canale.frequenza += items[0].step * scan_state;
        set_frequency();
        set_changed(0);
}

uint8_t sat_subu8b(uint8_t x, uint8_t y){
    uint8_t res = x - y;
    res &= -(res <= x);
    return res;
}

void click(void){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[600,5q");
}

void clear_display(void){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\f");
}

void display_backlight_on(void){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[%db",DISPLAY_BL_DIM);
}

void display_backlight_off(void){
	uart_tx_buf_in_idx += sprintf(uart_tx_buf+uart_tx_buf_in_idx,"\x1B[%db",0);
}
