#include <string.h>
#include "display.h"

char display_content[40]; // is zeroed by being in .bss
uint8_t display_currpos;


/* char layout is "line-addr" | "data" */
const prog_uint8_t lcd_halfbar_char[] = {0x1c,  /* 11100 */
										 0x1c,  /* 11100 */
										 0x1c,  /* 11100 */
										 0x1c,  /* 11100 */
										 0x1c,  /* 11100 */
										 0x1c,  /* 11100 */
										 0x1c,  /* 11100 */
										 0x00}; /* 00000 */ /* cursor line */

const prog_uint8_t lcd_bar_char[] = 	{0x1f,  /* 11111 */
										 0x1f,  /* 11111 */
										 0x1f,  /* 11111 */
										 0x1f,  /* 11111 */
										 0x1f,  /* 11111 */
										 0x1f,  /* 11111 */
										 0x1f,  /* 11111 */
										 0x00}; /* 00000 */ /* cursor line */

const prog_uint8_t lcd_degree_char[]  = {0x12,  /* 10010 */
										 0x05,  /* 00101 */
										 0x04,  /* 00100 */
										 0x05,  /* 00101 */
										 0x02,  /* 00010 */
										 0x00,  /* 00000 */
										 0x00,  /* 00000 */
										 0x00}; /* 00000 */ /* cursor line */




void lcd_defchar(uint8_t contr, uint8_t addr, const prog_uint8_t * chargraph) {
	int i=0;

	lcd_command(contr, _BV(LCD_CGRAM) | addr*8);

	for (i=0; i<=7; i++) {
		lcd_data(contr, pgm_read_byte(chargraph+i) & 0x1F); /* only the lower 5 bits */
	}
	lcd_command(contr, _BV(LCD_DDRAM));
}


void display_puts(const char * printstr) {
	
	while (*printstr){
		if (*printstr == '\n') {
			display_put_eol();
		} else {
			display_putc(*printstr);
		}
		printstr++;
	}
}

void display_puts_P(const prog_char * printstr) {
	
	while(pgm_read_byte(printstr)) {
		if (pgm_read_byte(printstr) == '\n') {
			display_put_eol();
		} else {
			display_putc(pgm_read_byte(printstr));
		}
		printstr++;
	}
}

void display_put_eol() {
	/* fill until end of display line */

	uint8_t j = 0;

	if (display_currpos <= 16) {
		/* first line */
		for (j = display_currpos; j < 16; j++) {
			display_putc(' ');
		}
	} else if (display_currpos <= 32) {
		/* second line */
		for (j = display_currpos; j < 32; j++) {
			display_putc(' ');
		}
	}
}

void display_putc(char printchar) {
	uint8_t lcdaddr;
	if (display_currpos >= 32) {
		return;
	}
	if (printchar != display_content[display_currpos]) {
		display_content[display_currpos] = printchar;
		lcdaddr = display_currpos;
		if (display_currpos >= 16) {
			lcdaddr = LCD_LINE2_ADDR - 16 + display_currpos;
		}
		lcd_command(1,_BV(LCD_DDRAM) | lcdaddr);
		lcd_data(1,printchar);
	}
	display_currpos++;
}


void display_fillblank() {
	while (display_currpos < 32){
		display_putc(' ');
	}
}

void display_gotoyx(uint8_t y, uint8_t x) {
	/* first line is line 0 */

	if (y > 1) {
		/* caller error, we only have two lines! set to first line */
		y = 0;
	}
	if (x > 15) {
		/* caller error, we only have 16 chars! set to first char */
		x = 0;
	}

	display_currpos = y * 16 + x;
}


extern void display_update() {
	uint8_t i=0;

	lcd_command(1, _BV(LCD_DDRAM));
	for (i = 0; i <= 15; i++) {
		lcd_data(1,display_content[i]);
	}
	
	lcd_command(1, _BV(LCD_DDRAM) | LCD_LINE2_ADDR);
	for (i = 16; i <= 32; i++) {
		lcd_data(1,display_content[i]);
	}
}


extern void display_force_redraw() {
	display_update();
}




int16_t intexp10(int8_t a){
	int8_t i;
	int16_t ret=1;
	for(i=0; i<a; ++i){
		ret *= 10;
	}
	return(ret);
}

void display_temperature(int16_t temperature){
	// temperature is a signed int of 16* the actual temperature
	int8_t fillzero=0, i;
	char c;

	temperature *= 10;
	for(i=3; i>=0; i--){
		if(i==1) { 
			fillzero = 1;
		}
		c = getdigit(&temperature, intexp10(i)*16, &fillzero); // hundred-digit
		display_putc(c);
		if(i==1) {
			display_putc('.');
		}
	}

	
}

void display_putint(int16_t number){
	int8_t fillzero=0, i;
	char c;

	for(i=2; i>=0; i--){
		if(i==1) { 
			fillzero = 1;
		}
		c = getdigit(&number, intexp10(i), &fillzero); // hundred-digit
		display_putc(c);
	}

	
}

char getdigit(int16_t *input, int16_t div, int8_t *fillzero){
	char digit;
	if(*input < 0){
		*input = - *input;  /* to convert from (binary) 2s-complement
										to (ascii) sign and magnitude */
		return '-';
	} else {
		digit = *input / div;
		*input -= digit * div;
	}
	digit += '0'; //converts to ascii
	if(digit == '0' && ! *fillzero){
		digit = ' ';
	} else {
		*fillzero = 1;
	}
	return digit;
}
		


void display_puthex(uint8_t outbyte) {
	uint8_t lownibble, highnibble;
	
	lownibble = outbyte & 0x0F;
	highnibble = (outbyte & 0xF0) >> 4;

	if (highnibble >= 10) {
		display_putc(0x41 - 10 + highnibble);
	} else {
		display_putc(0x30 + highnibble);
	}
	if (lownibble >= 10) {
		display_putc(0x41 - 10 + lownibble);
	} else {
		display_putc(0x30 + lownibble);
	}
}

void display_bar(int8_t value, int8_t min, int8_t max) {
	/* paint contrast bar */
	uint16_t tmp_var = 0;

	max -= min;
	value -= min;

	tmp_var = value * 32;
	tmp_var = tmp_var / max;

	while (tmp_var >= 2) {
		display_putc(LCD_CHAR_BAR);
		tmp_var -= 2;
	}
	if (tmp_var >=1) {
		display_putc(LCD_CHAR_HALFBAR);
		tmp_var -= 1;
	}
}

void updateTemperature() {
  if(newThermoData==1) {
    newThermoData = 0;
    
    char str[34];
    snprintf(str, 34, "%3d.%02d\x03  %3d.%02d\x03\n%3d.%02d\x03  %3d.%02d\x03", thermoData[0]/100, thermoData[0]%100,
	     thermoData[1]/100, thermoData[1]%100,
	     thermoData[2]/100, thermoData[2]%100,
	     thermoData[3]/100, thermoData[3]%100
	   );
    display_gotoyx(0,0);
    display_puts(str);
    display_update();
  }
}
