#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <LiquidCrystal_I2C.h>

// Define the number of displays and data pin configurations for MAX72XX
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 16 // 4x4 matrix configuration
#define DATA_PIN    11
#define CLK_PIN     13
#define CS_PIN      10

// Define matrix configuration
#define MATRIX_ROWS 4
#define MATRIX_COLS 4

// Initialize the Parola display object
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MATRIX_ROWS * MATRIX_COLS);
LiquidCrystal_I2C lcd(0x27, 20, 4); // Set the LCD I2C address

char lineBuff[5][33];  // Buffer for 5 lines of text, each up to 32 characters

int lineA;
int lineB;
int lineC;
int mulai;
int seconds;
int cs;
long start_time = 0;
int lapa = 0, lapb = 0, lapc = 0;
bool btlastlap = false; // Boolean for lastlap toggle

void setup(void)
{
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT_PULLUP); // Push button for toggling lastlap

  Serial.begin(9600);

  // Initialize Parola display
  P.begin();
  P.setIntensity(5); // Set brightness level (0-15)
  P.displayClear();

  lcd.init();
  lcd.backlight();
  lcd.clear();
}

void loop(void)
{
  if (P.displayAnimate()) {
    P.displayReset();
  }

  // Read input pins
  lineA = digitalRead(2);
  lineB = digitalRead(3);
  lineC = digitalRead(4);

  // Toggle btlastlap using the push button
  if (digitalRead(5) == LOW) {
    delay(200); // Debouncing delay
    btlastlap = !btlastlap; // Toggle the boolean
    while (digitalRead(5) == LOW); // Wait for button release
  }

  if (btlastlap) { // If lastlap is active
    if (checkLines(lineA, lineB, lineC)) {
      delay(1);
    }

    displayResults();
  } else { // If lastlap is inactive
    if (checkLines(lineA, lineB, lineC)) {
      P.displayClear();
      displayScrollingText("WIN", PA_CENTER, 100, 2000);
      processResults(lineA, lineB, lineC);
    }
  }

  if (checkStartCondition(lineA, lineB, lineC)) {
    mulai = 1;
    start_time = millis();
    displayScrollingText("ENGINE ON", PA_CENTER, 100, 2000);
  }

  if (mulai == 1) {
    seconds = (millis() - start_time) / 1000;
    cs = ((millis() - start_time) / 10) % 100;
  }

  displayTimeAndLap();
}

bool checkLines(int a, int b, int c) {
  return ((a == 0 && b == 1 && c == 1) ||
          (a == 1 && b == 0 && c == 1) ||
          (a == 1 && b == 1 && c == 0) ||
          (a == 0 && b == 0 && c == 1) ||
          (a == 0 && b == 1 && c == 0) ||
          (a == 1 && b == 0 && c == 0) ||
          (a == 0 && b == 0 && c == 0)) && (mulai == 1);
}

bool checkStartCondition(int a, int b, int c) {
  return (a == 0 || b == 0 || c == 0) && mulai == 0;
}

void displayResults() {
  if (lapa) {
    displayScrollingText("WIN A", PA_CENTER, 100, 2000);
    hasila();
  } else if (lapb) {
    displayScrollingText("WIN B", PA_CENTER, 100, 2000);
    hasilb();
  } else if (lapc) {
    displayScrollingText("WIN C", PA_CENTER, 100, 2000);
    hasilc();
  }
}

void processResults(int a, int b, int c) {
  if (a == 0 && b == 1 && c == 1) {
    hasila();
  } else if (a == 1 && b == 0 && c == 1) {
    hasilb();
  } else if (a == 1 && b == 1 && c == 0) {
    hasilc();
  }
}

void displayTimeAndLap() {
  sprintf(lineBuff[0], "%02d:%02d", seconds, cs);
  sprintf(lineBuff[1], "A:%02d:%02d", lapa / 60, lapa % 60);
  sprintf(lineBuff[2], "B:%02d:%02d", lapb / 60, lapb % 60);
  sprintf(lineBuff[3], "C:%02d:%02d", lapc / 60, lapc % 60);

  P.setTextAlignment(PA_LEFT);
  P.setTextEffect(0, PA_PRINT, PA_NO_EFFECT);

  for (int i = 0; i < 4; i++) {
    P.displayText(lineBuff[i], PA_LEFT, 0, 0, PA_PRINT, PA_NO_EFFECT);
    P.displayAnimate();
    P.setFont(NULL); // Reset to default font
    P.setTextEffect(0, PA_PRINT, PA_NO_EFFECT);
  }

  // LCD display
  lcd.clear();
  for (int i = 0; i < 4; i++) {
    lcd.setCursor(0, i);
    lcd.print(lineBuff[i]);
  }
}

void displayScrollingText(const char* msg, textPosition_t alignment, uint16_t speed, uint16_t pause) {
  P.displayText(msg, alignment, speed, pause, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
  while (!P.displayAnimate());
}

void hasila() {
  displayScrollingText("A", PA_CENTER, 100, 2000);
}

void hasilb() {
  displayScrollingText("B", PA_CENTER, 100, 2000);
}

void hasilc() {
  displayScrollingText("C", PA_CENTER, 100, 2000);
}