#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);
  setTextFont(1);

}

void EpaperDisplay::setTextFont(uint8_t size)
{
  switch(size){
    case 0:
      /* provide text size of 0 to keep a set font as it is*/
      break;
    case 1:
      epDisplay->setTextSize(1);
      epDisplay->setFont(&FreeSans9pt7b);
      break;
    case 2:
      epDisplay->setTextSize(1);
      epDisplay->setFont(&FreeSans12pt7b);
      break;
    case 3:
      epDisplay->setTextSize(1);
      epDisplay->setFont(&FreeSans18pt7b);
      break;
    case 4:
      epDisplay->setTextSize(1);
      epDisplay->setFont(&FreeSans24pt7b);
      break;
    // case 5:
    //   epDisplay->setTextSize(1);
    //   epDisplay->setFont(&FreeMonoBoldOblique24pt7b);
    //   break;
    default:
      epDisplay->setTextSize(1);
      epDisplay->setFont(&FreeSans9pt7b);
      break;
  }
}

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;
}

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

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);
  setTextFont(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);
  setTextFont(textSize);
  epDisplay->setTextColor(fgColor, bgColor);
  drawText(text, xCenterText(text), y);
}

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

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

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);
  setTextFont(textSize);
  epDisplay->setTextColor(fgColor, bgColor);
  updateText(text, x, y);
}



void EpaperDisplay::initScreen()
{  
  uint16_t y = 360;
  epDisplay->setFullWindow();
  epDisplay->firstPage();
  do
  {
    epDisplay->fillRect(0,0,epDisplay->width(), y - 50, GxEPD_BLACK);
    epDisplay->drawBitmap(25, 30, epd_bitmap_makerlablogosATM_ML, 250, 250, GxEPD_WHITE);
    
    //epDisplay->drawFastHLine(20,y-50,epDisplay->width()-40, GxEPD_BLACK);
    drawXCenteredText("Initialisierung ATM ...\n",2, y-20, GxEPD_BLACK,GxEPD_WHITE);
    //epDisplay->drawFastHLine(20,y,epDisplay->width()-40, GxEPD_BLACK);

    epDisplay->fillRect(0,epDisplay->height()-40,epDisplay->width(), 40, GxEPD_BLACK);
    drawXCenteredText("Zum Fortfahren Taster druecken!\n",1, epDisplay->height()-12, GxEPD_WHITE, GxEPD_BLACK);
  } while (epDisplay->nextPage());
  epDisplay->hibernate();
}

void EpaperDisplay::homeScreen()
{
  uint16_t y = 0;
  epDisplay->setFullWindow();
  epDisplay->firstPage();
  do
  {
    y = 0;
    epDisplay->fillRect(0,y,epDisplay->width(), 50, GxEPD_BLACK);
    drawXCenteredText("Belade deine MakerLab\n", 1, y+20, GxEPD_WHITE, GxEPD_BLACK);
    drawXCenteredText("Lightning Wallet hier!\n", 1, y+40, GxEPD_WHITE, GxEPD_BLACK);
    
    y = 210;
    epDisplay->drawFastHLine(10,y,epDisplay->width()-20, GxEPD_BLACK);
    drawXCenteredText("Bitte Muenzen einwerfen!\n", 2, y + 25, GxEPD_BLACK, GxEPD_WHITE);
    epDisplay->drawFastHLine(10,y+35,epDisplay->width()-20, GxEPD_BLACK);

    y = 20;
    epDisplay->drawBitmap(50, y, epd_bitmap_makerlablogosATM_hand, 280,197,GxEPD_BLACK);
    //drawXCenteredText("Betriebsbereit!\n", 3, 100, GxEPD_BLACK, GxEPD_BLACK);

    y = 270;
    drawXCenteredText("1, 2, 5, 10, 20, 50 Cent,\n", 1, y, GxEPD_BLACK, GxEPD_WHITE);
    drawXCenteredText("1 oder 2 Euro Muenzen.\n", 1, y+20, GxEPD_BLACK, GxEPD_WHITE);

    y = 310;
    epDisplay->fillRect(0,y,epDisplay->width(), epDisplay->height()-y, GxEPD_BLACK);
    epDisplay->drawBitmap(1, y+10, epd_bitmap_makerlablogosATM_ML_logo_land, 248, 69, GxEPD_WHITE);
    epDisplay->drawBitmap(220, y+10, epd_bitmap_makerlablogosATM_BC_LN, 73, 64, GxEPD_WHITE);
  
    epDisplay->drawRoundRect(5, 55, epDisplay->width()-10, 250, 5, GxEPD_BLACK);
    
  } while (epDisplay->nextPage());
}

void EpaperDisplay::showInsertedAmount(const char* amount_in_euro, const char* coin_values, const char* coin_numbers, const char* max_ammount_in_euro, bool update)
{

  uint16_t y = 0;
  if(false == update)
  {
    epDisplay->setFullWindow();
  }
  else{
    epDisplay->setPartialWindow(8,64,288,248);
  }
  epDisplay->firstPage();
  do
  {
    if(false == update)
    {
      y = 0;
      epDisplay->fillRect(0,y,epDisplay->width(), 50, GxEPD_BLACK);
      drawXCenteredText("Druecke den Taster, um die\n", 1, y+20, GxEPD_WHITE, GxEPD_BLACK);
      drawXCenteredText("Einzahlung abzuschliessen!\n", 1, y+40, GxEPD_WHITE, GxEPD_BLACK);
    }

    y = 180;
    epDisplay->setFont();
    epDisplay->setTextSize(1);
    drawXCenteredText("Aktueller Einzahlbetrag in Euro:\n", 0, 70, GxEPD_BLACK, GxEPD_WHITE);
    epDisplay->setTextSize(9);
    drawXCenteredText(amount_in_euro, 0, y - 75, GxEPD_BLACK, GxEPD_WHITE);
    //epDisplay->drawFastHLine(10,y,epDisplay->width()-20, GxEPD_BLACK);
    epDisplay->setTextSize(1);
    drawXCenteredText("Maximaler Betrag: 10,00 Euro.\n", 0, y + 25, GxEPD_BLACK, GxEPD_WHITE);
    epDisplay->drawFastHLine(10,y+50,epDisplay->width()-20, GxEPD_BLACK);

    y = 250;
    epDisplay->setFont();
    epDisplay->setTextSize(1);
    drawText(coin_values, 0, 20, y, GxEPD_BLACK, GxEPD_WHITE);
    
    drawText(coin_numbers, 0, 20, y+20, GxEPD_BLACK, GxEPD_WHITE);

    if(false == update)
    {
      y = 310;
      epDisplay->fillRect(0,y,epDisplay->width(), epDisplay->height()-y, GxEPD_BLACK);
      epDisplay->drawBitmap(1, y+10, epd_bitmap_makerlablogosATM_ML_logo_land, 248, 69, GxEPD_WHITE);
      epDisplay->drawBitmap(220, y+10, epd_bitmap_makerlablogosATM_BC_LN, 73, 64, GxEPD_WHITE);
    }    
    epDisplay->drawRoundRect(5, 55, epDisplay->width()-10, 250, 5, GxEPD_BLACK);
    
  } 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, const char* sumValue)
{
  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("Sum value: %s, Qrcode size: %d, qrcoded.size %d\n", sumValue, 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", 1, 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", 1, epDisplay->height() - 20, GxEPD_BLACK, GxEPD_WHITE );

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


void EpaperDisplay::cancelScreen()
{  
  //uint16_t y = 360;
  epDisplay->setFullWindow();
  epDisplay->firstPage();
  do
  {
    //epDisplay->fillRect(0,0,epDisplay->width(), y - 50, GxEPD_BLACK);
    epDisplay->drawBitmap(0, 30, epd_bitmap_makerlablogosATM_cancel, 280, 280, GxEPD_BLACK);
    
    //epDisplay->drawFastHLine(20,y-50,epDisplay->width()-40, GxEPD_BLACK);
    //drawXCenteredText("Initialisierung ATM ...\n",2, y-20, GxEPD_BLACK,GxEPD_WHITE);
    //epDisplay->drawFastHLine(20,y,epDisplay->width()-40, GxEPD_BLACK);

    //epDisplay->fillRect(0,epDisplay->height()-40,epDisplay->width(), 40, GxEPD_BLACK);
    //drawXCenteredText("Zum Fortfahren Taster druecken!\n",1, epDisplay->height()-12, GxEPD_WHITE, GxEPD_BLACK);
  } while (epDisplay->nextPage());
  epDisplay->hibernate();
}
