#include <Keypad.h> // used for the keypad
#include <Stepper.h> // used for the stepper motor

const int ROW_NUM = 4; // Four rows
const int COLUMN_NUM = 4; // Four columns

char keys[ROW_NUM][COLUMN_NUM] = {
  {'1','2','3', 'A'},
  {'4','5','6', 'B'},
  {'7','8','9', 'C'},
  {'*','0','#', 'D'}
};

// Connect to the row pinouts of the keypad
byte pin_rows[ROW_NUM] = {9, 8, 7, 6};

// Connect to the column pinouts of the keypad
byte pin_column[COLUMN_NUM] = {5, 4, 3, 2}; 

// Set up the keypad with the keys above
Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

// Create the array of variables to set the guess array and password array
const int NUMBER_OF_DIGITS = 4;
char guessList[NUMBER_OF_DIGITS] = {'0', '0', '0', '0'};
char passList[NUMBER_OF_DIGITS] = {'1', '1', '1', '1'};

int currentDigit = 0;

// used to tell if we need to reset the password
bool setPassword = true;

// Ignore very last digit entered since it uses the last digit of the password as the first digit of the guess
bool first = true;
bool passwordSet = false; // used to tell us when the password is first set

// Total number of steps
const int TOTAL_STEPS = 200;

// steps per a half turn
const int HALF_TURN = 100;

// time to wait in seconds
const int TIME_TO_WAIT = 10;

// initialize the stepper and pins it uses
Stepper stepper(TOTAL_STEPS, 14, 15, 16, 17);


// Function to change the current digit in the array
void changeDigit(char newDigit){
  guessList[currentDigit] = newDigit;
  ++currentDigit;

  // loop around once we hit the end
  if (currentDigit == NUMBER_OF_DIGITS){
    setPassword = false;
    currentDigit = 0;
  }
}

bool checkPassword(){
  bool passMatch = true;

  for (int i = 0; i < NUMBER_OF_DIGITS; ++i){
    if (guessList[i] != passList[i]){
      passMatch = false;
    }
  }

  return passMatch;
}


// turn the motor to unlock, wait a set amount of time, turn the other way to lock
// we assume the lock is locked when we start the program
void unlockThenLock(){
  //Serial.println("Unlocking!");

  // unlock the lock
  stepper.step(HALF_TURN);

  // wait the set amount of time, using delay since we don't need to do anything while it's waiting
  delay(TIME_TO_WAIT * 1000);

  Serial.println("Locking!");

  // lock the lock
  stepper.step(-HALF_TURN);

  // reset the guess so it doesn't spam unlock and lock
  for (int i = 0; i < NUMBER_OF_DIGITS; ++i){

    // set to X since it's a character the user can't enter on the keypad
    guessList[i] = 'X';
  }
}

void setup() {
  // put your setup code here, to run once:

  // set the speed of the new stepper to 60 RPM
  stepper.setSpeed(60);

  // initialize the serial port at a baud rate of 9600
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  char key = keypad.getKey();

  // Reset the password if the * key is pressed
  if (key == '*'){
    currentDigit = 0;
    setPassword = true;
  }


  // If we need to set the password, and a key is pressed that isn't *, we reset the password
  if (setPassword && key && key != '*'){
    passList[currentDigit] = key;
    ++currentDigit;

    // Loop around to the beginning of the array when we hit the end
    if (currentDigit == NUMBER_OF_DIGITS){
      currentDigit = 0;
      setPassword = false;
      passwordSet = true;
    }
  }
  
  // If we don't need to reset the password, add the digit to the guest list
  if(setPassword == false && key && key != '*' && first == false){
    changeDigit(key);
  }

  // set first to false if we hit the max number of digits so we can edit the guess
  if (first == true && passwordSet == true) first = false;

  // If password matches the guess, unlock then lock
  if (checkPassword() == true){
    unlockThenLock();
  }
}