#include <Arduino.h>
#include <JC_Button.h>
#include <TaskScheduler.h>

// Elk pootje van de Piezzo op 1 pin zetten. Door 1 hoog en ander laag te zetten creeer je meer 
// spanningsverschil en dus meer geluid.
#define SOUND_PIN 6
#define SOUND_PIN2 7

#define BREATHE_PIN 4

#define LOW_BPM 10
#define HIGH_BPM 20

// iterations = hoeveel biepjes
// interval = hoe lang tussen biepjes
#define SLOW_BEEP_ITERATIONS 3  // om een of andere reden biept ie hier in Wokwi maar 2x, in het echt werkt het wel 
#define SLOW_BEEP_INTERVAL 500 // milliseconds
#define FAST_BEEP_ITERATIONS 3
#define FAST_BEEP_INTERVAL 300 // milliseconds
#define REMIND_INTERVAL 5000 // milliseconds

void beep();
void detectBreath();
long calculate_bpms();

Scheduler _runner;
Task _taskBeep( SLOW_BEEP_INTERVAL * TASK_MILLISECOND, SLOW_BEEP_ITERATIONS, &beep);
Task _taskDetectBreath( 50 * TASK_MILLISECOND, TASK_FOREVER, &detectBreath);

Button breathDetector(BREATHE_PIN);

long lastReminder = millis(); // timestamp van laatste reminder

const int taps_len = 24;
unsigned long taps_millis[taps_len];
long next_tap = 0;
long total_taps = 0;
long time_signiture = 4;
long bpm  = 0;
#define SIXTY_S 60000

void setup() {
    Serial.begin(9600);

    pinMode(SOUND_PIN, OUTPUT);
    pinMode(SOUND_PIN2, OUTPUT);
    
    pinMode(LED_BUILTIN, OUTPUT);
    breathDetector.begin();

    _runner.addTask(_taskBeep);
    _taskBeep.enable();
    _runner.addTask(_taskDetectBreath);
    _taskDetectBreath.enable();
}

void loop() {
    _runner.execute();
}

void detectBreath() {
    breathDetector.read();

    if(breathDetector.wasReleased()) {
        taps_millis[next_tap] = millis();
        Serial.println(String(next_tap) + ": " + String(taps_millis[next_tap]));
        bpm  = calculate_bpms();
        next_tap = ++next_tap % taps_len;
        total_taps++;
        Serial.println("BPM: " + String(bpm));
        digitalWrite(LED_BUILTIN,HIGH); // visual feedback
        digitalWrite(LED_BUILTIN,LOW);
    }

    if( bpm > HIGH_BPM && millis() - lastReminder > REMIND_INTERVAL) {
        _taskBeep.setIterations(SLOW_BEEP_ITERATIONS);
        _taskBeep.setInterval(SLOW_BEEP_INTERVAL);
        _taskBeep.enableIfNot();
        lastReminder = millis();
        Serial.println("Reminder: Slow down");
    }

    if( bpm < LOW_BPM && millis() - lastReminder > REMIND_INTERVAL) {
        _taskBeep.setIterations(FAST_BEEP_ITERATIONS);
        _taskBeep.setInterval(FAST_BEEP_INTERVAL);
        _taskBeep.enableIfNot();
        lastReminder = millis();
        Serial.println("Reminder: Speed up");
    }
}

void beep() {
    digitalWrite(SOUND_PIN2, LOW);
    tone(SOUND_PIN, 4000); // Send 1KHz sound signal...
    delay(1);
    noTone(SOUND_PIN);     // Stop sound...
    digitalWrite(SOUND_PIN2, HIGH);
}

// From: https://github.com/victorman/ArduinoMetronome/blob/master/metronome/metronome.ino
long calculate_bpms() {
  if(total_taps < time_signiture) {
    return 0;
  }
  
  unsigned long total = 0;
  for(int i=1; i<=time_signiture; i++) {
    int tap = next_tap - i;
    
    if(tap < 0) {
      tap = taps_len + tap;
    }
    
    if(i>1) {
      Serial.print(String(tap + 1 % taps_len) + ": " + String(taps_millis[tap+1%taps_len]) + " - ");
      Serial.print(String(tap) + ": " + String(taps_millis[tap]));
      
      total += (taps_millis[tap + 1 % taps_len] - taps_millis[tap]);
    }
    Serial.println(total);
  }
  
  return SIXTY_S/(total / (time_signiture - 1));
}