#include "DisplayManager.h"

#include <Wire.h>
#include "Config.h"

namespace field_qa {

namespace {

static void formatElapsed(uint32_t ms, char* out, size_t outSize) {
  const uint32_t sec = ms / 1000U;
  const uint32_t hh = sec / 3600U;
  const uint32_t mm = (sec % 3600U) / 60U;
  const uint32_t ss = sec % 60U;
  snprintf(out, outSize, "%02lu:%02lu:%02lu", (unsigned long)hh, (unsigned long)mm, (unsigned long)ss);
}

}  // namespace

void DisplayManager::begin() {
  Wire.begin(OLED_SDA, OLED_SCL);
  m_oled.setI2CAddress(OLED_ADDR << 1);
  m_oled.begin();
  m_oled.setPowerSave(0);
  m_powerSave = false;
}

void DisplayManager::drawLines(const char* l1,
                               const char* l2,
                               const char* l3,
                               const char* l4,
                               const char* l5,
                               const char* l6) {
  m_oled.clearBuffer();
  m_oled.setFont(u8g2_font_5x8_tf);
  if (l1) m_oled.drawUTF8(0, 10, l1);
  if (l2) m_oled.drawUTF8(0, 20, l2);
  if (l3) m_oled.drawUTF8(0, 30, l3);
  if (l4) m_oled.drawUTF8(0, 40, l4);
  if (l5) m_oled.drawUTF8(0, 50, l5);
  if (l6) m_oled.drawUTF8(0, 60, l6);
  m_oled.sendBuffer();
}

void DisplayManager::showBoot(const char* line2, const char* line3, const char* line4, const char* batteryText) {
  char header[24];
  if (batteryText && batteryText[0] != '\0') {
    snprintf(header, sizeof(header), "%s %s", kExerciseName, batteryText);
    drawLines(header, kFirmwareVersion, line2, line3, line4);
  } else {
    drawLines(kExerciseName, kFirmwareVersion, line2, line3, line4);
  }
}

void DisplayManager::showError(const char* line1, const char* line2) {
  drawLines(kExerciseName, "ERROR", line1, line2);
}

void DisplayManager::showSample(const GnssSample& sample,
                                const RunStats& stats,
                                bool recording,
                                const char* batteryText) {
  char l1[24];
  char l2[20];
  char l3[20];
  char l4[20];
  char l5[20];
  char l6[20];

  snprintf(l1,
           sizeof(l1),
           "%s %s",
           recording ? "*RECORDING" : "Halted",
           (batteryText && batteryText[0] != '\0') ? batteryText : "--.-v");
  snprintf(l2, sizeof(l2), "FIX: %s", fixTypeToString(sample.fixType));
  snprintf(l3, sizeof(l3), "USED: %d/%d", sample.satsUsed < 0 ? 0 : sample.satsUsed, sample.satsInView < 0 ? 0 : sample.satsInView);
  if (sample.validHdop) {
    snprintf(l4, sizeof(l4), "HDOP: %.1f", sample.hdop);
  } else {
    snprintf(l4, sizeof(l4), "HDOP: --");
  }
  snprintf(l5, sizeof(l5), "Q: %s", qualityClassForSample(sample));
  formatElapsed(stats.elapsedMs(millis()), l6, sizeof(l6));
  drawLines(l1, l2, l3, l4, l5, l6);
}

void DisplayManager::setPowerSave(bool enabled) {
  if (m_powerSave == enabled) {
    return;
  }
  m_oled.setPowerSave(enabled ? 1 : 0);
  m_powerSave = enabled;
}

bool DisplayManager::powerSave() const {
  return m_powerSave;
}

}  // namespace field_qa
