//Fuel Flow Gauge and EGT
// Brake and Fuel Qty

class Button
{
private:
  uint8_t _pin;
  uint16_t _delay;
  bool _state;
  uint32_t _ignore_until;
  bool _has_changed;
  long btnUpTime;
  long btnDnTime;
  long holdTime = 3000; // 3 seconds in ms
  bool ignoreUp = false;

  const static bool PRESSED = LOW;
  const static bool RELEASED = HIGH;

public:
  Button()
  {
    // does nothing
  }

  Button(uint8_t pin)
      : _pin(pin), _delay(150), _state(HIGH), _ignore_until(0), _has_changed(false)
  {
    begin();
  }

  void begin()
  {
    pinMode(_pin, INPUT_PULLUP);
  }

  //
  // public methods
  //

  bool read()
  {
    // ignore pin changes until after this delay time
    if (_ignore_until > millis())
    {
      // ignore any changes during this period
    }

    // pin has changed
    else if (digitalRead(_pin) != _state)
    {
      // Serial.print("\n");
      // Serial.print(_state);
      _ignore_until = millis() + _delay;
      _state = !_state;
      _has_changed = true;
    }

    return _state;
  }

  // has the button been toggled from on -> off, or vice versa
  bool toggled()
  {
    read();
    return has_changed();
  }

  // mostly internal, tells you if a button has changed after calling the read() function
  bool has_changed()
  {
    if (_has_changed)
    {
      // Serial.print("\n");
      // Serial.print("has_changed");
      _has_changed = false;
      return true;
    }
    return false;
  }

  // has the button gone from off -> on
  bool pressed()
  {
    return read() == PRESSED && has_changed();
  }

  // has the button gone from on -> off
  bool released()
  {
    return read() == RELEASED && has_changed();
  }

  bool releasedLongPress()
  {
    if (released() && (millis() - btnDnTime) >= holdTime)
    {
      ignoreUp = true;
      btnDnTime = millis();
      return true;
    }
    return false;
  }

  bool releasedShortPress()
  {
    if (released() && (millis() - btnDnTime) < holdTime)
    {
      btnDnTime = millis();
      if (ignoreUp == false)
      {
        return false;
      }
      ignoreUp = false;
      return true;
    }
    return false;
  }

}; // don't forget the semicolon at the end of the class

// Pin definitions
const int STCPPin = 8;            // Pin connected to ST_CP of 74HC595
const int SHCPPin = 7;            // Pin connected to SH_CP of 74HC595 (can be SCK of SPI)
const int DSPin = 9;              // Pin connected to DS of 74HC595 (can be MOSI of SPI)
const int resetButtonPin = A0;    // Pin for the reset button , reset to 35.0
const int increaseButtonPin = A1; // Pin for the increase button by +5
const int decreaseButtonPin = A2; // Pin for the decrease button by-1
const int pulsePin = 2;           // Interrupt pin for fuel usage pulses

const int breakButtonPin = A3; // Pin to acknowledge BRAKE applied
const int fuelButtonPin = A4;  // Pin to acknowledge LOW FuEL applied
const int fuelLEDPin = 11;  // Pin for panel LED FUEL on
const int breakLEDPin = 10; // Pin for panel LED BRAKE on

const int flashLED1Pin = 13; // Pin for panel LED FLASHING
const int flashLED2Pin = 12; // Pin for panel LED FLASHING

const int Dig1 = 6;//pin out to pwr digit 1
const int Dig2 = 5;// pin out to pwr digit 2
const int Dig3 = 4;//pin out to pwr digit 3
//const int Dig4 = null; no pin alocated for digit 4

Button increaseButton = *new Button(increaseButtonPin);
Button decreaseButton = *new Button(decreaseButtonPin);

byte current_digit;
int timer = 0;

bool fuelButtonActive = false;
bool breakButtonActive = false;
bool flashLEDActive = false;

void disp(byte number, bool dec_point = 0);

volatile long fuelAmountMilliliters = 35000; // Start with 35 liters

const int a = 128;
const int b = 64;
const int c = 32;
const int d = 16;
const int e = 8;
const int f = 4;
const int g = 2;
const int dp = 1;

const int numbers[10] = {
    a + b + c + d + e + f,     // 0
    b + c,                     // 1
    a + b + g + e + d,         // 2
    a + b + g + c + d,         // 3
    f + g + b + c,             // 4
    a + f + g + c + d,         // 5
    a + f + e + d + c + g,     // 6
    a + b + c,                 // 7
    a + b + c + d + e + f + g, // 8
    a + b + c + d + f + g      // 9
};

void setup()
{
  Serial.begin(9600);
  Serial.println(fuelAmountMilliliters);
  pinMode(STCPPin, OUTPUT);
  pinMode(SHCPPin, OUTPUT);
  pinMode(DSPin, OUTPUT);
  pinMode(resetButtonPin, INPUT_PULLUP);//A0
  pinMode(breakButtonPin, INPUT_PULLUP);//A3
  pinMode(fuelButtonPin, INPUT_PULLUP);//A4
  pinMode(Dig1, OUTPUT);//pin6
  pinMode(Dig2, OUTPUT);//pin5
  pinMode(Dig3, OUTPUT);//pin4
  //pinMode(Dig4, OUTPUT);

  pinMode(fuelLEDPin, OUTPUT);//pin11
  pinMode(breakLEDPin, OUTPUT);//pin10
  pinMode(flashLED1Pin, OUTPUT);//pin12
  pinMode(flashLED2Pin, OUTPUT);//pin13
  Serial.println(fuelAmountMilliliters);
  attachInterrupt(digitalPinToInterrupt(pulsePin), pulseISR, FALLING);
  Serial.println(fuelAmountMilliliters);
}

void loop()
{

  handleButtons();
  updateDisplay();
}

void disp(byte number, bool dec_point)
{

  int dp = 0;
  if (dec_point == 1)
  {
    dp = 1;
  }

  shiftOut(DSPin, SHCPPin, MSBFIRST, numbers[number] + dp);
  digitalWrite(STCPPin, HIGH);
  digitalWrite(STCPPin, LOW);
}

void handleButtons()
{

  if (increaseButton.pressed())
  {
    // Increment to the nearest number divisible by 5, with an upper limit of 70
    // float increment = 5.0 - fmod(fuelAmount, 5.0);
    // if (increment == 5.0)
    // {
    //   increment = 0; // If already divisible by 5, don't add
    // }

    fuelAmountMilliliters += 5000;
    if (fuelAmountMilliliters > 70000)
    {
      fuelAmountMilliliters = 0;
    }
  }

  if (decreaseButton.pressed())
  {
    fuelAmountMilliliters -= 1000;
    if (fuelAmountMilliliters <= 0)
    {
      fuelAmountMilliliters = 70000;
    }
  }

  if (!digitalRead(resetButtonPin))
  {
    fuelAmountMilliliters = 35000;
  }

  if (!digitalRead(fuelButtonPin))
  {
    digitalWrite(fuelLEDPin, HIGH);
    fuelButtonActive = true;
    if (timer == 0)
    {
      timer = millis();
    }
  }
  else
  {
    digitalWrite(fuelLEDPin, LOW);
    fuelButtonActive = false;
  }

  if (!digitalRead(breakButtonPin))
  {
    digitalWrite(breakLEDPin, HIGH);
    breakButtonActive = true;
    if (timer == 0)
    {
      timer = millis();
    }
  }
  else
  {
    digitalWrite(breakLEDPin, LOW);
    breakButtonActive = false;
  }

  if (fuelButtonActive || breakButtonActive)
  {
    if (millis() - timer > 250)
    {
      if (flashLEDActive)
      {
        digitalWrite(flashLED1Pin, HIGH);
        digitalWrite(flashLED2Pin, LOW);
        flashLEDActive = false;
      }
      else
      {
        digitalWrite(flashLED1Pin, LOW);
        digitalWrite(flashLED2Pin, HIGH);
        flashLEDActive = true;
      }
      timer = 0;
    }
  }
  else
  {
    digitalWrite(flashLED1Pin, LOW);
    digitalWrite(flashLED2Pin, LOW);
    flashLEDActive = false;
  }
}

void updateDisplay()
{

  disp_off(); // turn off the display
  float fuelAmountLiters = fuelAmountMilliliters / 1000.0;
  int fuelInt = (int)(fuelAmountLiters * 100); // Convert fuel amount to integer for display
  // Serial.println(fuelInt);
  switch (current_digit)
  {
  case 1:
    disp(fuelInt / 1000);    // prepare to display digit 1 (most left)
    digitalWrite(Dig1, LOW); // turn on digit 1
    break;

  case 2:
    disp((fuelInt / 100) % 10, 1); // prepare to display digit 2
    digitalWrite(Dig2, LOW);       // turn on digit 2
    break;

  case 3:
    disp((fuelInt / 10) % 10); // prepare to display digit 3
    digitalWrite(Dig3, LOW);   // turn on digit 3
    break;

  //case 4:
  //  disp(fuelInt % 10);      // prepare to display digit 4 (most right)
  //  digitalWrite(Dig4, LOW); // turn on digit 4
  }

  current_digit = (current_digit % 4) + 1;
}

void pulseISR()
{
  fuelAmountMilliliters -= 625; // Each pulse represents 1/20 of 1/100th of a liter, or 625 milliliters
  if (fuelAmountMilliliters < 0)
  {
    fuelAmountMilliliters = 0; // Prevent going below 0
  }

  digitalWrite(fuelLEDPin, HIGH);
}

void disp_off()
{
  digitalWrite(Dig1, HIGH);
  digitalWrite(Dig2, HIGH);
  digitalWrite(Dig3, HIGH);
  //digitalWrite(Dig4, HIGH);
}
74HC595