//Dashboard designed by UPIR
//Code adjusted for it to work without any bitmaps by Arjan Pals
//Entire dashboard drawn in less 20 lines of code! (excluding code within functions oc)

//For now startAngle needs to be smaller then endAngle

#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Hello, ESP32!");
  u8g2.begin();
}

void loop() {

  int calclulatedGear = map(analogRead(4), 0, 4095, 1, 7);
  int RPM = map(analogRead(4), 0, 4095, 0, 6500);
  int Speed = map(analogRead(4), 0, 4095, 0, 230);
  
  u8g2.sendBuffer();
  u8g2.clearBuffer();

  //Draw the Gauges first, it influences with already drawn object around it
  //drawGauge(centerX,centerY,innerRadius,outerRadius,startAngle,endAngle,currentAngle);
  drawGauge(27, 40, 22, 27, 45, 315, map(analogRead(4), 0, 4095, 45, 315));
  drawGauge(99, 40, 22, 27, 45, 315, map(analogRead(4), 0, 4095, 45, 315));


  drawCricleCustomAngles(99, 40, 27, 285, 315); //Red region for RPM Gauge


  u8g2.setFont(u8g2_font_profont10_tr);
  printTextAtCenter(27, 62, "KPH");
  printTextAtCenter(99, 62, "RPM");

  u8g2.setFont(u8g2_font_profont22_tr);
  printTextAtCenter(64, 61, String(calclulatedGear));
  u8g2.drawFilledEllipse(63, 64, 12, 2, U8G2_DRAW_ALL);

  printTextAtCenter(27, 40 + u8g2.getAscent() / 2, String(Speed));

 u8g2.setFont(u8g2_font_profont22_tr);
int totalWidth = u8g2.getStrWidth(String((int)round(RPM / 100)*100).substring(0,1).c_str());
  u8g2.setFont(u8g2_font_profont17_tr);
totalWidth += u8g2.getStrWidth(String((int)round(RPM / 100)*100).substring(1,String((int)round(RPM / 100)*100).length()).c_str());

u8g2.setFont(u8g2_font_profont22_tr);
u8g2.setCursor(99-totalWidth/2,40+u8g2.getFontAscent()/2);
u8g2.print(String((int)round(RPM / 100)*100).substring(0,1));
u8g2.setFont(u8g2_font_profont17_tr);
u8g2.print(String((int)round(RPM / 100)*100).substring(1,4));

  u8g2.drawLine(0, 11, 128, 11);
  u8g2.setFont(u8g2_font_profont11_tr);

  static unsigned long pMillis = 0;
  printTextAtCenter(64, 8, "Gauge Cluster @ " + String(1000 / (millis() - pMillis)) + " Hz");
  pMillis = millis();

}

//Entire gauge with dots and needle changes when you enter diffrent parameters
void drawGauge(int centerX, int centerY, int innerRadius, int outerRadius, int minAngle, int maxAngle, int currentAngle)
{
  //Always use 'drawCDCustomAngles' first
  drawCDCustomAngles(centerX, centerY, innerRadius, outerRadius, minAngle, constrain(currentAngle,minAngle,maxAngle));
  drawNeedleCustomAngles(centerX, centerY, innerRadius * 0.8, outerRadius, currentAngle);
  drawDottedCircleCustomAngles(centerX, centerY, outerRadius, 20, minAngle, maxAngle);//20 dots
}

void drawCricleCustomAngles(int centerX, int centerY, int radius, int startDeg, int endDeg)
{
  for (int currentAngle = startDeg; currentAngle != endDeg; currentAngle++)
  {
    float pointX = -sin((currentAngle) * PI / 180.0) * radius;
    float pointY = cos((currentAngle) * PI / 180.0) * radius;
    pointX += centerX;
    pointY += centerY;
    u8g2.drawPixel(round(pointX), round(pointY));
    if (currentAngle == 360)
    {
      currentAngle = 0;
    }
  }
}

void drawNeedleCustomAngles(int centerX, int centerY, int innerRadius, int outerRadius, int degree)
{
  float needle_x_start = -sin((degree) * PI / 180.0) * innerRadius ;
  float needle_y_start = cos((degree) * PI / 180.0) * innerRadius;
  needle_x_start += centerX;
  needle_y_start += centerY;

  float needle_x_end = -sin((degree) * PI / 180.0) * outerRadius ;
  float needle_y_end = cos((degree) * PI / 180.0) * outerRadius ;
  needle_x_end += centerX;
  needle_y_end += centerY;

  u8g2.drawLine(needle_x_start, needle_y_start, needle_x_end, needle_y_end);
}

void drawCDCustomAngles(int centerX, int centerY, int innerRadius, int outerRadius, int startDeg, int endDeg)
{
  //First draw a disc with a hole in the middle
  startDeg += 360;
  u8g2.setDrawColor(1);
  u8g2.drawDisc(centerX, centerY, outerRadius);
  u8g2.setDrawColor(0);
  u8g2.drawDisc(centerX, centerY, innerRadius);

  //Now draw triangles to remove unwanted disc

  bool done = false;
  int currentAngle = endDeg;
  int secondAngle = 0;

  while (done == false)
  {
    if ((currentAngle + 20) < startDeg)
    {

      secondAngle = (currentAngle + 20);

    }
    else
    {
      secondAngle = startDeg;
      done = true;
    }
    float needle_x_start = -sin((currentAngle) * PI / 180.0) * outerRadius * 1.1;
    float needle_y_start = cos((currentAngle) * PI / 180.0) * outerRadius * 1.1;
    needle_x_start += centerX;
    needle_y_start += centerY;

    float needle_x_end = -sin((secondAngle) * PI / 180.0) * outerRadius * 1.1;
    float needle_y_end = cos((secondAngle) * PI / 180.0) * outerRadius * 1.1;
    needle_x_end += centerX;
    needle_y_end += centerY;
    u8g2.setDrawColor(0);
    u8g2.drawTriangle(needle_x_start, needle_y_start, needle_x_end, needle_y_end, centerX, centerY);
    currentAngle = secondAngle;
  }
  u8g2.setDrawColor(1);
}

void drawDottedCircleCustomAngles(int centerX, int centerY, int radius, int amountOfDots, int startDeg, int endDeg)
{


  float angleToAdd = (endDeg - startDeg) / amountOfDots;
  for (double currentAngle = startDeg; currentAngle <= endDeg ; currentAngle += angleToAdd)
  {

    float needle_x_start = -sin((currentAngle) * PI / 180.0) * radius;
    float needle_y_start = cos((currentAngle) * PI / 180.0) * radius;
    needle_x_start += centerX;
    needle_y_start += centerY;


    u8g2.drawPixel(round(needle_x_start), round(needle_y_start));
    if (currentAngle == 360)
    {
      currentAngle = 0;
    }
  }
}

void printTextAtCenter(int x, int y, String textToPrint)
{
  u8g2.setCursor(x - u8g2.getStrWidth(textToPrint.c_str()) / 2, y);
  u8g2.print(textToPrint);
}