// For: https://forum.arduino.cc/t/timer-has-random-error/1037211/
//
// This Wokwi project: https://wokwi.com/projects/344260957282763346
//
// "DS3231" libary from the Library Manager in the Arduino IDE.
// (that is this library: https://github.com/NorthernWidget/DS3231)
//
// Changed #include "DS3231.h" with #include <DS3231.h>
//
// 1 Oct 2022
//   Started with my own version with millis:
//   https://wokwi.com/projects/344339167081136722
//

#include <LiquidCrystal.h>
#include <Wire.h>
#include <DS3231.h>
#include <Keypad.h>

RTClib RTC;
DS3231 Clock;
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

#define Red A1
#define Green A0
#define button 3
const int rs = 13, en = 12, d4 = 11, d5 = 10, d6 = 9, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {A2, A3, 0, 1}; /* connect to the row pinouts of the keypad */
byte colPins[COLS] = {4, 7, 6, 5}; //connect to the column pinouts of the keypad

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

char customKey, sign[10];
byte num, a = 0;
bool Key_Status = false, button_press = false, Complete = false, Key_Enter = false;
unsigned int split[10][3], split1[10][3], error = 0;
unsigned long int ms, milli[10];
long int pulse = 0;
unsigned long int b;
void setup() {
  pinMode(Red, OUTPUT);
  pinMode(Green, OUTPUT);
  pinMode(2, INPUT_PULLUP);
  pinMode(button, INPUT_PULLUP);
  digitalWrite(Red, LOW);
  digitalWrite(Green, LOW);
  lcd.begin(20, 4);
  lcd.clear();
  lcd.print("Welcome");
  delay(1500);
  lcd.setCursor(0, 0);
  lcd.print("Enter Split Number");
  lcd.setCursor(0, 1);
  Split_Number();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Enter Split Times");
  Split_Time();
  lcd.clear();
  customKey = ':';
  int j = 0;
  int p = (num - 1) / 4 + 1;
  int Prev_s = 100;
  while (customKey != 'D') {
    customKey = customKeypad.getKey();
    if (customKey && customKey == 'A')
      j = (j + 1) % p;
    if (customKey && customKey == 'B')
      j = (j - 1 + p) % p;
    if (Prev_s != j) {
      Prev_s = j;
      int i = 0;
      lcd.clear();
      while (i < 4 && (4 * j + i) < num) {
        lcd.setCursor(0, i % 4);
        lcd.print(4 * j + i + 1);
        lcd.print(". ");
        lcd_check(split[4 * j + i][0], 3);
        lcd.print(split[4 * j + i][0]); lcd.print("'");
        lcd_check(split[4 * j + i][1], 2);
        lcd.print(split[4 * j + i][1]); lcd.print("''");
        lcd_check(split[4 * j + i][2], 3);
        lcd.print(split[4 * j + i][2]); lcd.print("'''");
        i ++;
      }
    }
  }

  Wire.begin();
  lcd.clear();
  lcd.setCursor(4, 1);
  lcd.print("Press Button");
  lcd.setCursor(3, 2);
  lcd.print("To Start Race");

}

void squr() {
  if (pulse == -1)
    error = millis() - error;
  pulse += 1;
  b = millis();
}

void loop() {
  if (digitalRead(button) == 0) {
    delay(20);
    if (digitalRead(button) == 0) {
      if (a == 0) {
        b = millis();
        error = b;
        Clock.enableOscillator(true, false, 0);
        pulse = -1;
        
        attachInterrupt(digitalPinToInterrupt(2), squr, FALLING);
      }
      else {
        ms = millis() - b;
        if (ms >= 1000)
          ms = random(996, 1000);
        if (pulse < 0){
          pulse = 0;
          
        }
        milli[a - 1] = pulse * 1000 + ms + error;
      }
      a++;
      button_press = true;
    }
  }

  if (button_press && a <= (num + 1))
    sub();

  int i = num - 1;
  int prev = num;
  int s = 0;
  while (Complete) {
    customKey = customKeypad.getKey();
    if (customKey && customKey == 'A')
      i = (i + 1) % num;
    if (customKey && customKey == 'B')
      i = (i - 1 + num) % num;
    if (i != prev) {
      prev = i;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print(i + 1);
      lcd.print(". ");
      lcd_check(split[i][0], 3);
      lcd.print(split[i][0]);
      lcd.print("'");
      lcd_check(split[i][1], 2);
      lcd.print(split[i][1]);
      lcd.print("''");
      lcd_check(split[i][2], 3);
      lcd.print(split[i][2]);
      lcd.print("'''");
      lcd.setCursor(0, 2);
      lcd.print(i + 1);
      lcd.print(". ");
      s = milli[i] / 60000;
      lcd_check(s, 3);
      lcd.print(s);
      lcd.print("'");
      s = (milli[i] / 1000) % 60;
      lcd_check(s, 2);
      lcd.print(s);
      lcd.print("''");
      s = milli[i] % 1000;
      lcd_check(s, 3);
      lcd.print(s);
      lcd.print("'''");
      lcd.setCursor(0, 3);
      lcd.print(i + 1);
      lcd.print(". ");
      if (sign[i] == '+') {
        digitalWrite(Green, LOW);
        digitalWrite(Red, HIGH);
      }
      else {
        digitalWrite(Green, HIGH);
        digitalWrite(Red, LOW);
      }
      lcd.print(sign[i]);
      lcd_check(split1[i][0], 3);
      lcd.print(split1[i][0]);
      lcd.print("'");
      lcd_check(split1[i][1], 2);
      lcd.print(split1[i][1]);
      lcd.print("''");
      lcd_check(split1[i][2], 3);
      lcd.print(split1[i][2]);
      lcd.print("'''");
    }
  }
}

void lcd_check(int m, int p) {
  if (p == 2 && m / 10 == 0) {
    lcd.print("0");
    return 0;
  }
  if (p == 3 && m / 10 == 0) {
    lcd.print("00");
    return 0;
  }
  if (p == 3 && m / 100 == 0) {
    lcd.print("0");
    return 0;
  }
}

void sub() {
  if ((a - 1) < num) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Present Time: ");
    lcd.setCursor(0, 1);
    lcd.print(a);
    lcd.print(". ");
    lcd_check(split[a - 1][0], 3);
    lcd.print(split[a - 1][0]);
    lcd.print("'");
    lcd_check(split[a - 1][1], 2);
    lcd.print(split[a - 1][1]);
    lcd.print("''");
    lcd_check(split[a - 1][2], 3);
    lcd.print(split[a - 1][2]);
    lcd.print("'''");
  }
  if (a > 1) {
    unsigned long int d;
    d = split[a - 2][0] * 60000 + split[a - 2][1] * 1000 + split[a - 2][2];
    lcd.setCursor(0, 2);
    lcd.print("Previous Result: ");
    lcd.setCursor(0, 3);
    lcd.print(a - 1);
    lcd.print(". ");

    if (milli[a - 2] > d) {
      split1[a - 2][0] = (milli[a - 2] - d) / 60000;
      split1[a - 2][1] = ((milli[a - 2] - d) / 1000) % 60;
      split1[a - 2][2] = (milli[a - 2] - d) % 1000;
      sign[a - 2] = '+';
      lcd.print("+");
      digitalWrite(Green, LOW);
      digitalWrite(Red, HIGH);
    }
    else {
      split1[a - 2][0] = (d - milli[a - 2]) / 60000;
      split1[a - 2][1] = ((d - milli[a - 2]) / 1000) % 60;
      split1[a - 2][2] = (d - milli[a - 2]) % 1000;
      sign[a - 2] = '-';
      lcd.print("-");
      digitalWrite(Green, HIGH);
      digitalWrite(Red, LOW);
    }
    lcd_check(split1[a - 2][0], 3);
    lcd.print(split1[a - 2][0]);
    lcd.print("'");
    lcd_check(split1[a - 2][1], 2);
    lcd.print(split1[a - 2][1]);
    lcd.print("''");
    lcd_check(split1[a - 2][2], 3);
    lcd.print(split1[a - 2][2]);
    lcd.print("'''");
  }
  button_press = false;
  if (a == (num + 1)) {
    detachInterrupt(digitalPinToInterrupt(2));
    Complete = true;
  }
  while (digitalRead(button) == 0);
  delay(10);
}

void Split_Number()
{
  while (1)
  {
    customKey = customKeypad.getKey();
    delay(100);
    if (customKey <= 57 && customKey != '*' && customKey != '#' && customKey)
    {
      num = num * 10 + customKey - 48;
      lcd.print(customKey);
      Key_Enter = true;
    }
    if (customKey == 'C' || num > 10)
    {
      num = 0;
      lcd.setCursor(0, 1);
      lcd.print("                ");
      lcd.setCursor(0, 1);
      Key_Enter = false;
    }
    if (customKey == 'D' && customKey && num != 0 && Key_Enter)
      break;
  }
}

void Split_Time() {
  int k = 1;
  for (int i = 0; i < num; i++) {
    int j = 0;
    lcd.setCursor(0, k);
    lcd.print(i + 1);
    lcd.print(". ");
    Key_Enter = false;
    while (1) {
      customKey = customKeypad.getKey();

      if (customKey <= 57 && customKey >= 48 && customKey && j < 3) {
        split[i][j] = split[i][j] * 10 + customKey - 48;
        if (split[i][1] >= 60) {
          split[i][1] = 0;
          lcd.setCursor(3, k);
          lcd.print("             ");
          lcd.setCursor(3, k);
          lcd.print(split[i][0]);
          lcd.print("'");
          Key_Enter = false;
        }
        else if (split[i][2] >= 1000) {
          split[i][2] = 0;
          lcd.setCursor(3, k);
          lcd.print("             ");
          lcd.setCursor(3, k);
          lcd.print(split[i][0]);
          lcd.print("'");
          lcd.print(split[i][1]);
          lcd.print("''");
          Key_Enter = false;
        }
        else {
          lcd.print(customKey);
          Key_Enter = true;
        }
      }

      if (customKey == 'C') {
        j = 0;
        split[i][0] = 0;
        split[i][1] = 0;
        split[i][2] = 0;
        lcd.setCursor(3, k);
        lcd.print("             ");
        lcd.setCursor(3, k);
        Key_Enter = false;
      }

      if (customKey == '*' && j < 3 && Key_Enter) {
        j++;
        for (int l = 0; l < j; l++)
          lcd.print("'");
        Key_Enter = false;
      }
      if (i > 0 && ((split[i][0] < split[i - 1][0] && j == 1) || (split[i][0] == split[i - 1][0] && split[i][1] < split[i - 1][1] && j == 2) || (split[i][0] == split[i - 1][0] && split[i][1] == split[i - 1][1] && split[i][2] < split[i - 1][2] && j == 3))) {
        j = 0;
        j = 0;
        split[i][0] = 0;
        split[i][1] = 0;
        split[i][2] = 0;
        lcd.setCursor(3, k);
        lcd.print("             ");
        lcd.setCursor(3, k);
        Key_Enter = false;
      }
      if (customKey == 'D' && customKey && j == 3) {
        if (k == 3) {
          for (k = 1; k <= 3; k++) {
            lcd.setCursor(0, k);
            lcd.print("                   ");
          }
          k = 0;
        }
        k++;
        break;
      }
    }
  }
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
lcd1:VSS
lcd1:VDD
lcd1:V0
lcd1:RS
lcd1:RW
lcd1:E
lcd1:D0
lcd1:D1
lcd1:D2
lcd1:D3
lcd1:D4
lcd1:D5
lcd1:D6
lcd1:D7
lcd1:A
lcd1:K
r1:1
r1:2
r2:1
r2:2
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
rgb1:R
rgb1:COM
rgb1:G
rgb1:B
r3:1
r3:2
r4:1
r4:2
r5:1
r5:2
GND5VSDASCLSQWRTCDS1307+
rtc1:GND
rtc1:5V
rtc1:SDA
rtc1:SCL
rtc1:SQW
keypad1:R1
keypad1:R2
keypad1:R3
keypad1:R4
keypad1:C1
keypad1:C2
keypad1:C3
keypad1:C4