#include "epaperdisplay.h"
#include "qrcode.h"

// *** for Waveshare ESP32 Driver board *** //
#if defined(ESP32) && defined(USE_HSPI_FOR_EPD)
SPIClass hspi(HSPI);
#endif
// *** end Waveshare ESP32 Driver board *** //

EpaperDisplay::EpaperDisplay(uint8_t DSPLY_PIN_CS, uint8_t DSPLY_PIN_DC, uint8_t DSPLY_PIN_RST, uint8_t DSPLY_PIN_BUSY)
{
  epDisplay = new GxEPD2_DISPLAY_CLASS(GxEPD2_DRIVER_CLASS(DSPLY_PIN_CS, DSPLY_PIN_DC, DSPLY_PIN_RST, DSPLY_PIN_BUSY));
}

EpaperDisplay::~EpaperDisplay()
{
}

void EpaperDisplay::sleep()
{
  epDisplay->hibernate();
}

void EpaperDisplay::init()
{
  epDisplay->init(115200, true, 2, false);
    // *** for Waveshare ESP32 Driver board *** //
#if defined(ESP32) && defined(USE_HSPI_FOR_EPD)
  hspi.begin(13, 12, 14, 15); // remap hspi for EPD (swap pins)
  epDisplay>epd2.selectSPI(hspi, SPISettings(4000000, MSBFIRST, SPI_MODE0));
#endif

  epDisplay->setRotation(1);

}


void EpaperDisplay::cleanScreen()
{
  epDisplay->firstPage();
  do{
    epDisplay->clearScreen();
  }
  while(epDisplay->nextPage());
  epDisplay->hibernate();
}


uint16_t EpaperDisplay::xCenterText(const char* text)
{
  int16_t xul, yul;
  uint16_t textWidth, textHeight;
  epDisplay->getTextBounds(text, 0, 0, &xul, &yul, &textWidth, &textHeight);
  xul = (epDisplay->width() - textWidth)/2;
  if(xul < 0 )
  {
    xul = 0;
  }
  return xul;
}

void EpaperDisplay::drawText(const char* text, uint16_t x, uint16_t y)
{
  epDisplay->setCursor(x, y);
  epDisplay->printf(text);
}

void EpaperDisplay::drawText(const char* text, uint8_t textSize, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor )
{
  epDisplay->setTextSize(textSize);
  epDisplay->setTextColor(fgColor, bgColor);
  drawText(text, x, y);
}

void EpaperDisplay::drawXCenteredText(const char* text, uint8_t textSize, uint16_t y, uint16_t fgColor, uint16_t bgColor )
{
  epDisplay->setTextSize(textSize);
  epDisplay->setTextColor(fgColor, bgColor);
  drawText(text, xCenterText(text), y);
}

void EpaperDisplay::updateText(const char* text, uint16_t x, uint16_t y)
{
  int16_t xul, yul;
  uint16_t textWidth, textHeight;
  epDisplay->getTextBounds(text, x, y, &xul, &yul, &textWidth, &textHeight);
  epDisplay->setPartialWindow(xul, yul, textWidth, textHeight);
  epDisplay->firstPage();
  do
  {
    epDisplay->setCursor(x, y);
    epDisplay->printf(text);  
  } while (epDisplay->nextPage());
}

void EpaperDisplay::updateText(const char* text, uint8_t textSize, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor)
{
  epDisplay->setTextSize(textSize);
  epDisplay->setTextColor(fgColor, bgColor);
  updateText(text, x, y);
}


void EpaperDisplay::homeScreen()
{
  epDisplay->setFullWindow();
  epDisplay->firstPage();
  do
  {
    drawText("Insert Euro coins\n on the right ->\n to start ATM\n", 2, 11, 20, GxEPD_BLACK, GxEPD_WHITE);
    epDisplay->drawBitmap(172, 65, bitcoin_logo, 64, 64, GxEPD_BLACK);
    drawText("Prepare Lightning enabled Bitcoin\n  wallet before starting!\n  Supported coins: 1 - 50 Cent, 1 - 2 Euro\n", 1, 12, 140, GxEPD_BLACK, GxEPD_WHITE);
  } while (epDisplay->nextPage());
  epDisplay->hibernate();
}

void EpaperDisplay::showInsertedAmount(const char* amount_in_euro)
{
  epDisplay->setFullWindow();
  epDisplay->firstPage();
  do
  {
    drawText("Inserted amount:\n", 2, 11, 10, GxEPD_BLACK, GxEPD_WHITE);
    drawText(amount_in_euro, 3, 20, 75, GxEPD_BLACK, GxEPD_WHITE);
    drawText("Press button\n once finished.\n", 2, 11, 135, GxEPD_BLACK, GxEPD_WHITE);
  } while (epDisplay->nextPage());
}

void EpaperDisplay::updateInsertedAmount(const char* amount_in_euro)
{
  updateText(amount_in_euro, 3, 20, 75, GxEPD_BLACK, GxEPD_WHITE);
}

void  EpaperDisplay::qrCode(const char* content)
{
  QRCode qrcoded;
  uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; // 20 is "qr version"
  t_qrdata qr;
  uint16_t color = GxEPD_BLACK;

  qrcode_initText(&qrcoded, qrcodeData, QR_VERSION, 0, content);
  qr.module_size = 3;
  qr.qr_size = qrcoded.size * qr.module_size;
  Serial.printf("Qrcode size: %d, qrcoded.size %d\n", qr.qr_size, qrcoded.size);
  qr.start_x = (epDisplay->width() - qr.qr_size) / 2;
  qr.start_y = (epDisplay->height() - qr.qr_size) / 2;
  
  epDisplay->setFullWindow();
  epDisplay->firstPage();

  do
  {
     
    for (qr.current_y = 0; qr.current_y < qrcoded.size; qr.current_y++)
    {
      for (qr.current_x = 0; qr.current_x < qrcoded.size; qr.current_x++)
      {
        if (qrcode_getModule(&qrcoded, qr.current_x, qr.current_y))
        {
          color = GxEPD_BLACK;
        }
        else
        {
          color = GxEPD_WHITE;
        }

        epDisplay->fillRect(qr.start_x + (qr.module_size * qr.current_x),
            qr.start_y + (qr.module_size * qr.current_y), qr.module_size, qr.module_size, color);
      }
    }

    uint16_t radius_px = 5;
    epDisplay->drawRoundRect(qr.start_x - radius_px , qr.start_y - radius_px, qr.qr_size+(2*radius_px), qr.qr_size+(2*radius_px), radius_px, GxEPD_BLACK);

    drawXCenteredText("Please scan the QR code!\n", 2, 10, GxEPD_BLACK, GxEPD_WHITE );
    drawXCenteredText("This will transfer the paid value to your wallet.\n", 1, 30, GxEPD_BLACK, GxEPD_WHITE );
    drawXCenteredText("Reset - press button\n", 2, epDisplay->height() - 20, GxEPD_BLACK, GxEPD_WHITE );

   /* code */
  } while (epDisplay->nextPage());    
  epDisplay->hibernate();
}

