#include "display.h"

#include <stddef.h>
#include <stdio.h>

#include "main.h"
#include "ssd1306.h"
#include "ssd1306_conf.h"

// printf("%f", ...) doesn't work on STM
static int float_to_str(char *buf, size_t len, float val,
                        size_t decimal_digits) {
  if (len < 2) {
    return 0;
  }

  // len = NUL + decimal digits + . + integer digits
  int int_digits = len - decimal_digits - 2;

  int chars = snprintf(buf, len, "%*d", int_digits, (int)val);
  buf[chars] = '.';
  chars++;

  val -= (int)val;
  for (size_t i = 0; i < decimal_digits; i++) {
    val *= 10;
  }
  return chars + snprintf(buf + chars, len - chars, "%d", (int)val);
}

void display_init() {
  ssd1306_Init();
  display_update_voltage();
  ssd1306_WriteChar('V', Font_16x26, White);
  display_update_state();
  ssd1306_UpdateScreen();
}

void display_update_voltage() {
  char voltage_buf[7];
  float_to_str(voltage_buf, sizeof(voltage_buf), voltage, 2);
  ssd1306_SetCursor(0, 38);
  ssd1306_WriteString(voltage_buf, Font_16x26, White);
}

void display_update_state() {
  switch (state) {
  case STATE_SETUP_CHARGE:
    ssd1306_FillRectangle(0, 0, SSD1306_WIDTH - 1, 30, Black);
    ssd1306_SetCursor(0, 0);
    ssd1306_WriteString("Charge", Font_6x8, White);
    ssd1306_SetCursor(0, 10);
    ssd1306_WriteString("Press to close relay", Font_6x8, White);
    break;
  case STATE_SETUP_DISCHARGE:
    ssd1306_FillRectangle(0, 0, SSD1306_WIDTH - 1, 30, Black);
    ssd1306_SetCursor(0, 0);
    ssd1306_WriteString("Discharge", Font_6x8, White);
    ssd1306_SetCursor(0, 10);
    ssd1306_WriteString("Press to close relay", Font_6x8, White);
    break;
  case STATE_CHARGE:
    ssd1306_FillRectangle(0, 0, SSD1306_WIDTH - 1, 30, Black);
    ssd1306_SetCursor(0, 0);
    ssd1306_WriteString("CHARGING", Font_11x18, White);
    break;
  case STATE_DISCHARGE:
    ssd1306_FillRectangle(0, 0, SSD1306_WIDTH - 1, 30, Black);
    ssd1306_SetCursor(0, 0);
    ssd1306_WriteString("DISCHARGING", Font_11x18, White);
    break;
  case STATE_ERR_CHARGE:
    ssd1306_FillRectangle(0, 0, SSD1306_WIDTH - 1, 30, White);
    ssd1306_SetCursor(10, 5);
    ssd1306_WriteString("OVERVOLTAGE", Font_6x8, White);
    ssd1306_SetCursor(10, 15);
    ssd1306_WriteString("DETECTED", Font_6x8, White);
    break;
  case STATE_ERR_DISCHARGE:
    ssd1306_FillRectangle(0, 0, SSD1306_WIDTH - 1, 30, White);
    ssd1306_SetCursor(10, 5);
    ssd1306_WriteString("UNDERVOLTAGE", Font_6x8, White);
    ssd1306_SetCursor(10, 15);
    ssd1306_WriteString("DETECTED", Font_6x8, White);
    break;
  }
}

void display_update() {
  display_update_voltage();
  display_update_state();
  ssd1306_UpdateScreen();
}
