#include <IRremote.hpp>
#include <SPI.h>
#include <MFRC522.h>

#include "melody.h"
#include "ledindicator.h"

#define IR_RECEIVE_PIN 7

#define RST_RFID 9
#define CS_RFID 10
MFRC522 mfrc522(CS_RFID, RST_RFID);


const int DOOR_SENSOR_PIN = 4;



/* Connections:
*  Door Sensor: Gnd & 13
*  Buzzer: Gnd & 8
*  Led Receptor: 7 & Gnd & 5V
*/

int currentDoorState; // current state of door sensor
int lastDoorState;    // previous state of door sensor
bool isArmed = true;
bool isFired = false;
bool muted = false;
bool ledOn = true;
bool silent = true;
long int delta = 0;

void setup()
{

  Serial.begin(115200); // // Establish serial communication

  setupLeds();
  // IR Control
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK); // Start the receiver

  //Door Sensor
  pinMode(DOOR_SENSOR_PIN, INPUT_PULLUP);

  //Card Reader
  SPI.begin();        //Iniciamos el Bus SPI
	mfrc522.PCD_Init(); // Iniciamos  el MFRC522

  currentDoorState = digitalRead(DOOR_SENSOR_PIN); // read state

  isArmed = currentDoorState == LOW;
  Serial.println("Alarm is " + String(isArmed ? "Armed" : "Disarmed"));
  

  pinMode(TONE_PIN, OUTPUT);

  updateIndicator();
  delta=millis();
  
}
int lastCmd;
unsigned long lastTime;

void updateIndicator()
{
  if(!ledOn)
  {
    offLed();
    return;
  }
  if(isFired)
  {
    showRed();
    return;
  }
  if(currentDoorState==HIGH)
  {
    showYellow();
    return;
  }
  if(isArmed)
  {
    showBlue();
    return;
  }
  showGreen();
}

void loop() {

  // IrReceiver.stopTimer();
  handleCard();
  // IrReceiver.restartTimer(); 
  handleDoor();
 
  handleIR();
  handleFire();
}


byte ActualUID[4]; //almacenará el código del Tag leído
byte Usuario1[4]= {0x23, 0x14, 0x1F, 0x2D} ; //código del usuario 1
byte Usuario2[7]= {0x04, 0x38, 0x76, 0x8A, 0x2C, 0x6A, 0x80} ; //código del usuario 2
void handleCard(){
  
  // Revisamos si hay nuevas tarjetas  presentes
	if ( !mfrc522.PICC_IsNewCardPresent()) 
  {
    return;
  }

  if(millis() < delta +2000){
    Serial.print(".");
    return;
  }
  delta=millis();

  //Seleccionamos una tarjeta
  if (! mfrc522.PICC_ReadCardSerial()) 
  {
    Serial.println("not readable");
    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
    showErrorReader();
    return;
  }
  
  // Enviamos serialemente su UID
  Serial.print(F("Card UID:"));
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);   

    ActualUID[i]=mfrc522.uid.uidByte[i];          
  } 
  Serial.print("     ");                 
  //comparamos los UID para determinar si es uno de nuestros usuarios  
  if(!grantAccess()){
    Serial.println("Acceso denegado...");
    showErrorReader();
    return;
  }
  Serial.println("Acceso concedido!");

  isArmed=false;
  isFired=false;
  updateIndicator();
  // Serial.println("Alarm is " + String(isArmed ? "Armed" : "Disarmed"));

  // Terminamos la lectura de la tarjeta tarjeta  actual
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

bool grantAccess(){
  if(compareArray(ActualUID,Usuario1)){
    return true;
  }else if(compareArray(ActualUID,Usuario2)){
    return true;
  }
  return false;
}
//Función para comparar dos vectores
bool compareArray(byte array1[],byte array2[])
{
  if(array1[0] != array2[0])return(false);
  if(array1[1] != array2[1])return(false);
  if(array1[2] != array2[2])return(false);
  if(array1[3] != array2[3])return(false);
  return(true);
}


void handleIR(){
  if (!IrReceiver.decode()) return;
  if(IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT)
  {
    IrReceiver.resume();
    return;
  }
  switch(IrReceiver.decodedIRData.command)
  {
    case 67:
      Serial.println("Play");
      isArmed=!isArmed;
      updateIndicator();
      Serial.println("Alarm is " + String(isArmed ? "Armed" : "Disarmed"));
      // playTone();
      break;
    case 70:
      Serial.println("Led on/off");
      ledOn=!ledOn;
      updateIndicator();
      break;
    case 9:
      silent=!silent;
      Serial.println("Silent: "+ String(silent));
      break;
    case 0:
      Serial.println("-");break;
    default:
      Serial.print("unk: ");
      Serial.println(IrReceiver.decodedIRData.command);
  }
  

  IrReceiver.resume();
  
}

void handleDoor(){
  if(isFired) return;
  lastDoorState = currentDoorState;              // save the last state
  currentDoorState  = digitalRead(DOOR_SENSOR_PIN); // read new state

  // state change: LOW -> HIGH
  if (lastDoorState == LOW && currentDoorState == HIGH) { 
    Serial.println("The door-opening");
    if(!isArmed)
    {
      Serial.println("Alarm is dissarmed, not fireing");

      
      updateIndicator();
      return;
    }
    Serial.println("Alarm is armed, firing");
    isFired=true;
    updateIndicator();
    
  }
  else
  if (lastDoorState == HIGH && currentDoorState == LOW) { // state change: HIGH -> LOW
    delay(500);
    Serial.println("The door-closing");
    isArmed=true;
    updateIndicator();
    // TODO: turn off alarm, light or send notification ...
  }
}

void showErrorReader(){
  showRed();
  delay(100);
  offLed();
  delay(100);
  showRed();
  delay(100);
  offLed();
  delay(100);
  updateIndicator();
}

void handleFire(){
  if(muted || !isFired)
    return;

  IrReceiver.stopTimer();
  // playTone();
  playAlarm(silent);
  IrReceiver.restartTimer(); 
}




