#include <TFT_eSPI.h>
#include <SPI.h>       // this is needed for display
#include <PNGdec.h>

#include "BG.h"
#include "Free_Fonts.h"

#define MAX_IMAGE_WIDTH 320

int16_t xpos = 0;
int16_t ypos = 0;

#include "NotoSansBold15.h"
#define CF_OL24 &Orbitron_Light_24
#define CF_OL32 &Orbitron_Light_32
#define CF_RT24 &Roboto_Thin_24

// The display also uses hardware SPI, plus #9 & #10
#define TFT_CS 15
#define TFT_DC 2
#define TFT_MOSI 23
#define TFT_SCLK 18

//gauge geometry
const int gauge_w = 250;
const int gauge_h = 20;
const int gauge_r = 5;
const int gauge_t = 2;

//gauge colours
const int gauge_border = 0x6b6d;
const int gauge_back = 0x4208;
const int gauge_fill = TFT_MAROON;

//gauge location
const int gauge_x = 5;
const int gauge_y = 30;
const int gauge_spacing = 30;

//ballast status variables
int ballast_port;
int ballast_port_old;
const int port_pin = 34;
int ballast_kgb;
int ballast_kgb_old;
int ballast_stbd;
int ballast_stbd_old;

PNG png;

//init TFT
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite background = TFT_eSprite(&tft);


//create sprite to hold background image (320x170)
void initPNGBack(TFT_eSprite &sprite) {

  sprite.createSprite(320, 170);
  int16_t rc = png.openFLASH((uint8_t *)BG, sizeof(BG), pngDraw);
  Serial.println(rc);

  if (rc == PNG_SUCCESS) {
    Serial.println("Successfully opened png file");
    sprite.startWrite();
    rc = png.decode(NULL, 0);
    sprite.endWrite();
  }

}

//draw backdround sprite and screen label
void drawPNGBack(char* label) {

  background.pushSprite(0, 0);

  tft.setFreeFont(CF_OL24);
  tft.setTextDatum(MC_DATUM);
  tft.setTextSize(1);
  tft.setCursor(5, 20);
  tft.print(label);


}


//helper function to draw PNG
void pngDraw(PNGDRAW *pDraw) {
  uint16_t lineBuffer[MAX_IMAGE_WIDTH];
  png.getLineAsRGB565(pDraw, lineBuffer, PNG_RGB565_BIG_ENDIAN, 0xffffffff);
  background.pushImage(xpos, ypos + pDraw->y, pDraw->iWidth, 1, lineBuffer);
}


//draw gauge outline and label at given position
void initGauge(int x, int y, char* label) {

  int txt_corr = 5;

  // Load the font
  //tft.loadFont(NotoSansBold15);
  tft.setFreeFont(FSS9);
  tft.setTextSize(1);
  tft.setTextDatum(BL_DATUM);
  tft.setCursor(x, y + gauge_h / 2 + txt_corr);
  tft.print(label);
  tft.fillSmoothRoundRect(x + 50, y, gauge_w, gauge_h, gauge_r, gauge_border, TFT_BLACK);
  tft.fillSmoothRoundRect(x + 50 + gauge_t, y + gauge_t, gauge_w - 2 * gauge_t, gauge_h - 2 * gauge_t, gauge_r - gauge_t, gauge_back, gauge_border);

}

//update gauge
void updateGauge(int x, int y, float progress) {

  int fore_start = x + 50 + gauge_t;
  float fore_width = (gauge_w - 2 * gauge_t) * (progress / 100);
  float back_start = fore_width - 5 + fore_start;
  float back_width = (gauge_w - 2 * gauge_t) - fore_width + 5;



  if (progress <= 5) {
    tft.fillSmoothRoundRect(x + 50 + gauge_t, y + gauge_t, gauge_w - 2 * gauge_t, gauge_h - 2 * gauge_t, gauge_r - gauge_t, gauge_back, gauge_border);
    tft.fillSmoothRoundRect(x + 50 + gauge_t, y + gauge_t, 5, gauge_h - 2 * gauge_t, gauge_r - gauge_t, gauge_fill, gauge_border);
  } else {

    tft.fillSmoothRoundRect(back_start, y + gauge_t, back_width, gauge_h - 2 * gauge_t, gauge_r - gauge_t, gauge_back, gauge_border);
    tft.fillSmoothRoundRect(fore_start, y + gauge_t, fore_width, gauge_h - 2 * gauge_t, gauge_r - gauge_t, gauge_fill, gauge_border);

  }

}

void drawGaugeSet() {
  initGauge(gauge_x, gauge_y, "PORT");
  initGauge(gauge_x, gauge_y + gauge_spacing, "KGB");
  initGauge(gauge_x, gauge_y + gauge_spacing * 2, "STBD");

}


void drawDataScreen() {
  drawPNGBack("DATA");
  
  tft.setFreeFont(FSSBO24);
  tft.setTextDatum(BC_DATUM);
  tft.setTextSize(1);
  tft.setCursor(120, 60);
  tft.print(random(0,88));
  tft.setTextSize(1);
  tft.fillRect(5,70,60,60, gauge_back);
  tft.setFreeFont(TT1);
  tft.setCursor(6+30,65);
  tft.print("PORT");
  tft.setFreeFont(FSSB12);
  tft.setCursor(6, 120);
  tft.print(random(0,100));

}

void setup() {


  Serial.begin(115200);


  //init TFT
  tft.init();
  tft.setRotation(1);
  tft.setTextSize(1);
  tft.fillScreen(TFT_BLACK);
  tft.setRotation(1);

  initPNGBack(background); //build background sprite

  drawPNGBack("BALLAST");  //push background sprite and label

  drawGaugeSet(); //init gauges

}


void update_gauge(int &new_value, int &old_value, int pin, int x, int y) {

  new_value = map(analogRead(pin), 0, 4095, 0, 100);

  if (new_value != old_value) {
    updateGauge(x, y, new_value);
    old_value = new_value;
  }
}



void loop() {

  //ballast_port = map(analogRead(34), 0, 4095, 0, 100);

  /*
    if (ballast_port != ballast_port_old) {
    updateGauge(gauge_x, gauge_y, ballast_port);
    ballast_port_old = ballast_port;
    }

  */


  update_gauge(ballast_port, ballast_port_old, port_pin, gauge_x, gauge_y);
  update_gauge(ballast_kgb, ballast_kgb_old, port_pin, gauge_x, gauge_y + gauge_spacing);
  update_gauge(ballast_stbd, ballast_stbd_old, port_pin, gauge_x, gauge_y + gauge_spacing * 2);

  delay(5000);

  drawDataScreen();
  
}