// https://wokwi.com/projects/374394134602244097
// https://forum.arduino.cc/t/cutting-wires-in-sequence-out-of-sequence/1162990

/**
 * "Cut The Wires" defuse bomb puzzle
 *
 * Players must "cut" the correct wires in order(via releasing alligator clips) to stop
 * the ticking clock.  If the clock reaches zero (after 60 minutes), the bomb "explodes"
 * with sound effects. If wires are "cut" out of order, the ticking will get faster.
 */
 
#define DEBUG


// CONSTANTS
const byte numWires = 5;
const int wirePins[numWires] = {2, 3, 4, 5, 6};
// Define the number of steps in the sequence that the player must follow


// GLOBALS
int lastState[numWires];
// What is the order in which wires need to be cut
// 0 indicates the wire should not be cut
int wiresToCut[numWires] = {0, 1, 2, 3, 4}; // (blue, red, yellow, green)
byte wiresCutCounter = 1;
// Keep track of the current state of the device
enum State {Inactive, Active, Defused, Exploded};
State state = State::Inactive;
//This is the timestamp at which the bomb will detonate
//It is calculated by adding on the specified number of minutes in the game time
// to the value of millis() when the code is initialised.
unsigned long detonationTime;
//The game length (in minutes)
int gameDuration = 60;

void Activate() {
  state = State::Active;
  // Set the detonation time to the appropriate time in the future
//  detonationTime = millis() + (unsigned long)gameDuration*60*1000;

detonationTime = millis() + 30000;    // twenty-five seconds
  Serial.println("Bomb activated!");
}

void Deactivate() {
  state = State::Inactive;
  Serial.println("inactive. is that mean dead now until reset?");
}

void Detonate() {
  state = State::Exploded;
}



void setup() {

  Serial.begin(9600);
  Serial.println("restarted\n\n");

  // Initialise wire pins
  for(int i=0; i<numWires; i++) {
    pinMode(wirePins[i], INPUT_PULLUP);
    lastState[i] = digitalRead(wirePins[i]);
  }
  
  // Set the detonation time to the appropriate time in the future
  detonationTime = millis() + (unsigned long)gameDuration*60*1000;

  // Print the initial state of the wires
  for(int i=0; i<numWires; i++) {
    Serial.println(F("Wire "));
    Serial.print(i);
    Serial.println(digitalRead(wirePins[i])? " Unconnected" : " Connected");
  }

  // Arm the bomb!
  Activate();

};

void loop() {

  delay(25);  // was there a bouncing problem? this killed it if there was

  // First, see if any of the wires have been recently cut
  for(int i=0; i<numWires; i++) {
    // If the previous reading was LOW, but now it's HIGH, that means this wire must have been cut
    if(digitalRead(wirePins[i]) == HIGH && lastState[i] == LOW) {
      Serial.println("Wire ");
      Serial.print(i);
      Serial.println(" cut");
      lastState[i] = HIGH;

      // Was this the correct wire to cut?
      if(wiresCutCounter == wiresToCut[i]) {
        // Go on to the next counter
        wiresCutCounter++;
      }
      // Incorrect wire cut
      else {
        // Play faster ticking sound effect
      Serial.println("                 WRONG WIRE");

      }
    }
    // If the previous reading was LOW, but now it's HIGH, that means this wire must just have been cut
    else if(digitalRead(wirePins[i]) == LOW && lastState[i] == HIGH) {
      Serial.println(" Wire ");
      Serial.println(i);
      Serial.println( " reconnected");
      lastState[i] = LOW;
    }

  }

  // Now, test the current state of all wires against the solution state
  //First, assume that the correct wires have all been cut
  bool allWiresCut = true;
  // Then, loop over the wires array
  for(int i=0; i<numWires; i++) {
    // Every wire that has a number > 0 in the wiresToCut array should be cut (at some point), after which they will read HIGH,
    // So if any of them still read LOW, that means that there is at least one wire still to be cut
    if (wiresToCut[i] !=0 && lastState[i] == LOW) {
      allWiresCut = false;
    }
  }

  // What to do next depends on the current state of the device
  if(state == State::Active) {
    // Retrieve the current timestamp
    unsigned long currentTime = millis();
    if(currentTime > detonationTime) {
      Detonate();
      Serial.println("time is up, so BOOM!");

    }
    else if(allWiresCut == true ) {
      Deactivate();
      Serial.println("Bomb defused!");
    }
    else {

    }
  }
}