// INCLUDES *******************************************************************
#include <RTClib.h>
// #include "OCR_A_Extended24.h"
// #include "OCR_A_Extended16.h"
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
#include <SPI.h>
#include "dht_nonblocking.h"
// DEFINES ********************************************************************
RTC_DS3231 rtc;

#define DHT_SENSOR_TYPE DHT_TYPE_22
#define GFXFF 1
#define OCRA24 OCR_A_Extended24
#define OCRA16 OCR_A_Extended16
#define K TFT_BLACK
#define W TFT_WHITE
#define R TFT_RED
#define G tft.color565(100, 100, 100)
#define G2 tft.color565(150, 150, 150)
const int GRAPH_HEIGHT = 162;
const int GRAPH_WIDTH = 270;
const int XAXIS_HEIGHT = 15;
const int XAXIS_WIDTH = 320;

const int GRAPHX = 25;
const int GRAPHY = 40;
const int XAXISX = 0;
const int XAXISY = 210;

// GLOBALS ********************************************************************
static const int xmin = 0;
static const int xmax = 100;
static const int ymin = 20;
static const int ymax = 100;
static const int ydivs = 10;

char daysOfTheWeek[7][12] = {"Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"};
char monthsOfTheYear[12][10] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov","Dec"};
char twelveHour[2][4] = {"AM", "PM"};

static const int DHT_SENSOR_PIN = 13;
DHT_nonblocking dht_sensor(DHT_SENSOR_PIN, DHT_SENSOR_TYPE);
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite graph = TFT_eSprite(&tft);
TFT_eSprite xaxis = TFT_eSprite(&tft);
TFT_eSprite dt = TFT_eSprite(&tft);
int grid;
int gridWidth = 0;
int ysections = (ymax - ymin) / ydivs;
int yincr = GRAPH_HEIGHT / ysections;
const int xincr = 15;
bool isGraphScrolling = false;
int c = 0;
int minuteCounter = 0;
unsigned long previous_measurement;
int xmodulo;

// FUNCTIOMNS AND METHODDS ====================================================
void setup() {
  Serial.begin(115200);

  while (!Serial);

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }

  tft.init();
  tft.fillScreen(K);
  tft.setRotation(1);
  tft.setTextColor(W);
  tft.setTextDatum(MR_DATUM); // Middle right text datum
  tft.drawNumber(ymin, 20, (GRAPH_HEIGHT + GRAPHY));
  for(int i = 1; i <= ysections; i++){
    tft.drawNumber((i*ydivs) + ymin, 20, GRAPH_HEIGHT - (yincr * i) + GRAPHY);
  }
  tft.setTextDatum(ML_DATUM);
  tft.drawNumber(ymin, (GRAPH_WIDTH + GRAPHX) + 5, (GRAPH_HEIGHT + GRAPHY));
  for(int i = 1; i <= ysections; i++){
    tft.drawNumber((i*ydivs) + ymin, (GRAPH_WIDTH + GRAPHX) + 5, GRAPH_HEIGHT - (yincr * i) + GRAPHY);
  }
  
  tft.drawRect(GRAPHX - 1, GRAPHY - 1, GRAPH_WIDTH + 2, GRAPH_HEIGHT + 2, G);
  
  xaxis.setColorDepth(8);
  graph.setColorDepth(8);
  dt.setColorDepth(8);

  xaxis.createSprite(XAXIS_WIDTH, XAXIS_HEIGHT);
  graph.createSprite(GRAPH_WIDTH, GRAPH_HEIGHT);
  dt.createSprite(GRAPH_WIDTH + 10, XAXIS_HEIGHT);

  xaxis.fillSprite(K);
  graph.fillSprite(K);
  dt.fillSprite(K);

  dt.setTextColor(W, K);
  xaxis.setTextColor(W);
  
  xaxis.setTextDatum(CC_DATUM); 

  for(int i = GRAPHX + xincr; i <= (GRAPH_WIDTH + xincr); i += xincr){
    minuteCounter++;
    if(minuteCounter % 5 == 0){
      if(minuteCounter < 10){
        xaxis.drawString(":0" + String(minuteCounter), i, 5);
      }else{
        xaxis.drawString(":" + String(minuteCounter), i, 5);
      }
    }else{
      xaxis.drawFastVLine(i, 2, 3, G);
    }
  }

  graph.drawFastHLine(0, GRAPH_HEIGHT, GRAPH_WIDTH, G);
  for (int p = 0; p <= ysections; p++){
    graph.drawFastHLine(0, GRAPH_HEIGHT - (yincr * p), GRAPH_WIDTH, G);
  }
  for(int q = xincr; q <= GRAPH_WIDTH; q += xincr){
    graph.drawFastVLine(q, 0, GRAPH_HEIGHT, G);
    c++;
  }
  xmodulo = GRAPH_WIDTH % xincr;
  if(xmodulo == 0) xmodulo = xincr;
  grid = (xmodulo == 0) ? xincr : xmodulo;
  
  xaxis.pushSprite(XAXISX, XAXISY);
  dt.pushSprite(25, 225);
  // dt.loadFont(OCRA16);
  // tft.loadFont(OCRA24);
}

float getX(float xval){
  float gx = 0.5 + (((GRAPH_WIDTH - 0) * (xval - xmin)) / (xmax - xmin));
  return GRAPHX + gx;
}

float getY(float yval){
  float gy = 0.5 + (((GRAPH_HEIGHT - 0) * (yval - ymin)) / (ymax - ymin));
  return GRAPHY + gy;
}

static bool measure_environment(float *temperature, float *humidity){
  static unsigned long measurement_timestamp = millis();
  /* Measure once every four seconds. */
  previous_measurement = millis() - measurement_timestamp;
  if( previous_measurement > 3800ul){
    if(dht_sensor.measure( temperature, humidity) == true){
      measurement_timestamp = millis();
      return(true);
    }
  }
  return(false);
}
//==========================================================================================
void loop() {
  float temperature;
  float humidity;
  float fahrenheit = 0.1;

  DateTime now = rtc.now();

  if(isGraphScrolling == false && gridWidth >= GRAPH_WIDTH) isGraphScrolling = true;

  if( measure_environment(&temperature, &humidity) == true){
    fahrenheit = ((temperature * 9) / 5) + 32;
    tft.setTextPadding(80);
    tft.setTextDatum(TL_DATUM);
    tft.setTextColor(R, K);
    tft.drawString("Temp: ", 8, 7, GFXFF);
    tft.drawFloat(fahrenheit, 1, 83, 7, GFXFF);
    tft.drawString("°", 143, 7);
    tft.setTextColor(G2, K);
    tft.drawString("Hum:", 175, 7);
    tft.drawFloat(humidity, 1, 235, 7);
    tft.drawString("%", 295, 7, GFXFF);

    if(isGraphScrolling == false){
      graph.drawFastVLine(gridWidth, (GRAPH_HEIGHT + GRAPHY) - getY(fahrenheit) + 3, 2, R);
      graph.drawFastVLine(gridWidth, (GRAPH_HEIGHT + GRAPHY) - getY(humidity) + 3, 2, G2);
    } else {
      graph.drawFastVLine(GRAPH_WIDTH-1, (GRAPH_HEIGHT + GRAPHY) - getY(fahrenheit) + 3, 2, R);
      graph.drawFastVLine(GRAPH_WIDTH-1, (GRAPH_HEIGHT + GRAPHY) - getY(humidity) + 3, 2, G2);
    }

    // Push the sprites onto the TFT at specified coordinates
    graph.pushSprite(GRAPHX, GRAPHY);
    xaxis.pushSprite(XAXISX, XAXISY);
    dt.pushSprite(25, 225);

    if(isGraphScrolling == true){
      graph.scroll(-1, 0);
      xaxis.scroll(-1, 0);
      grid++;
    } else {
      gridWidth++;
    }

    int h = 0, m = 0;
    if(isGraphScrolling == true){
      if (grid >= xincr){
        grid = 0;
        graph.drawFastVLine(GRAPH_WIDTH - 1, 0, GRAPH_HEIGHT, G); // draw line on graph
        minuteCounter++;
        if(minuteCounter % 5 == 0){
          if(minuteCounter > 59){
            h = minuteCounter / 60;
          }
          m = minuteCounter % 60;
          // xaxis.drawNumber(minuteCounter, GRAPH_WIDTH - 1 + GRAPHX, 0);
          if(h < 1){
            if(m < 10) xaxis.drawString(":0" + String(m), GRAPH_WIDTH - 1 + GRAPHX, 5);
            else xaxis.drawString(":" + String(m), GRAPH_WIDTH - 1 + GRAPHX, 5);
          }else{
            if(m < 10) xaxis.drawString(String(h) + ":0" + String(m), GRAPH_WIDTH - 1 + GRAPHX, 5);
            else xaxis.drawString(String(h) + ":" + String(m), GRAPH_WIDTH - 1 + GRAPHX, 5);
          }
        } else {
          xaxis.drawFastVLine(GRAPH_WIDTH - 1 + GRAPHX, 2, 3, G);
        }
      } else { // Otherwise draw points spaced 10 pixels for the horizontal grid lines
        graph.drawPixel(GRAPH_WIDTH-1, GRAPH_HEIGHT, G);
        for (int p = 0; p <= ysections; p++){
          graph.drawPixel(GRAPH_WIDTH-1, GRAPH_HEIGHT - (yincr * p), G);
        }
      }
    }
  }

  dt.setTextDatum(CC_DATUM);
  dt.setTextPadding(50);
  char buf[] = "hh:mm:ss";
  dt.drawString(String(daysOfTheWeek[now.dayOfTheWeek()]) + ", " + String(monthsOfTheYear[now.month()]) + " " + String(now.day()) + " | " + now.toString(buf), GRAPH_WIDTH / 2, 10);
  dt.pushSprite(25, 225);
}
//==========================================================================================
GND5VSDASCLSQWRTCDS1307+