/*
// Xogo de sumas
//
// Pablo César Galdo Regueiro ([email protected])
// License: GPLv3

LICENSE - LICENZA

Copyright 2015 Pablo César Galdo Regueiro

This program is free software: you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see < http : //www.gnu.org/licenses/>.

Tradución non oficial :

Este programa é un software libre; vostede pode redistribuilo e / ou
modificalo dentro dos termos da Licenza Pública Xeral GNU
publicada pola Fundación do Software Libre (FSF); na versión 3 da
Licenza, ou (á súa elección) calquera versión posterior.

Este programa é distribuído coa esperanza de que poda ser útil,
       mais SEN NINGUNHA GARANTÍA; sen garantia implícita de ADAPTACIÓN
a calquer MERCADO ou APLICACIÓN EN PARTICULAR. Vexa a
Licenza Pública Xeral GNU para maiores detalles.

Vostede debeu recibir unha copia da Licenza Pública Xeral GNU xunto
con este programa. Se non, mire < http: //www.gnu.org/licenses/>.
*/

// LCD 16X2
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// FIM LCD 16X2

// KEYPAD
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'#', '0', '*'}
};
byte rowPins[ROWS] = {A3, A2, A1, A0}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
// FIN KEYPAD

// LEDS
const int verde = A4;
const int vermelho = A5;
// FIN LEDS

// BUZZER
const int buzzer = 10;
// FIN BUZZER

// OUTRAS CONSTANTES
const int lonxitude = 3; // Give enough room for six chars + NULL char
// FIN OUTRAS CONSTANTES

// VARIÁVEIS
boolean operando = 1;
int sumando1;
int sumando2;
int resultado = 100;
int comparar;
char Dato[lonxitude]; // 6 is the number of chars it can hold + the null char = 7
char Resultado[lonxitude] = "99";
byte dato_conta = 0, resultado_conta = 0;
bool correcto;
char customKey;
// FIN VARIÁVEIS

// SONIDO MARIO
#include "notas.h"
/*
  Intro e,e,,e,c,e,g

  C G E
  A B A# A
  G E G A F G
  E C D B
*/

// notes in the melody:
int Mario_melody[] = {
  NOTE_E4, NOTE_E4, REST, NOTE_E4,
  REST, NOTE_C4, NOTE_E4, REST,
  NOTE_G4, REST, REST, NOTE_G3, REST,

  NOTE_C4, REST, REST, NOTE_G3,
  REST, NOTE_E3, REST,
  REST, NOTE_A3, REST, NOTE_B3,
  REST, NOTE_AS3, NOTE_A3, REST,

  NOTE_G3, NOTE_E4, NOTE_G4,
  NOTE_A4, REST, NOTE_F4, NOTE_G4,
  REST, NOTE_E4, REST, NOTE_C4,
  NOTE_D4, NOTE_B3, REST
};

int Mario_Notes[] = {
  4, 4, 4, 4,
  4, 4, 4, 4,
  4, 2, 4, 2, 2,

  4, 4, 4, 4,
  2, 4, 4,
  4, 4, 4, 4,
  4, 4, 4, 4,

  4, 2, 4,
  4, 4, 4, 4,
  4, 4, 4, 4,
  4, 4, 2
};

const int num_elements_in_arr = sizeof(Mario_Notes) / sizeof(Mario_Notes[0]);
// FIN SONIDO MARIO

void setup() {

  Serial.begin(9600);

  pinMode (verde, OUTPUT);
  pinMode (vermelho, OUTPUT);

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  // if analog input pin 6 is unconnected, random analog
  // noise will cause the call to randomSeed() to generate
  // different seed numbers each time the sketch runs.
  // randomSeed() will then shuffle the random function.
  randomSeed(analogRead(6));

  // MENSAXE DE BENVIDA
  digitalWrite(verde, HIGH);
  digitalWrite(vermelho, HIGH);
  delay(333);
  digitalWrite(verde, LOW);
  digitalWrite(vermelho, LOW);
  delay(333);
  digitalWrite(verde, HIGH);
  digitalWrite(vermelho, HIGH);
  delay(333);
  digitalWrite(verde, LOW);
  digitalWrite(vermelho, LOW);
  delay(333);
  digitalWrite(verde, HIGH);
  digitalWrite(vermelho, HIGH);
  lcd.setCursor(0, 0);
  lcd.print("OLA!");
  delay(1000);
  lcd.setCursor(0, 1);
  lcd.print("IMOS SUMAR!");
  // FIN MENSAXE DE BENVIDA

  // MELODIA MARIO AO INICIAR
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < num_elements_in_arr; thisNote++) {

    // to calculate the note duration, take one second
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 200 / Mario_Notes[thisNote];
    tone(buzzer, Mario_melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(buzzer);
  }
  // FIN MELODIA MARIO AO INICIAR

  // PREPARAD@?
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("PREPARATE...");
  delay(1000);
  lcd.setCursor(0, 1);
  lcd.print("COMEZAMOS!");
  delay(1000);
  digitalWrite(verde, LOW);
  digitalWrite(vermelho, LOW);
  // FIN PREPARAD@

}

void loop() {

  digitalWrite(verde, LOW);
  digitalWrite(vermelho, LOW);
  delay(333);
  digitalWrite(verde, HIGH);
  digitalWrite(vermelho, HIGH);
  delay(333);
  digitalWrite(verde, LOW);
  digitalWrite(vermelho, LOW);
  lcd.clear();

  resultado = 100;
  while (resultado > 99 || resultado < 10) { // print a random number from 0 to 299
    sumando1 = random(1, 100);
    delay(50);
    sumando2 = random(1, 100);
    delay(50);
    resultado = sumando1 + sumando2;
    delay(50);
    itoa (resultado, Resultado, 10);
  }

  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 0);
  // print the number of seconds since reset:
  lcd.print("SUMA ");
  lcd.print(sumando1);
  lcd.print(" + ");
  lcd.print(sumando2);
  //lcd.print("=");
  //lcd.print(Resultado);

  operando = 1;
  while (operando == 1) {

    digitalWrite(vermelho, LOW);
    digitalWrite(verde, LOW);

    customKey = keypad.getKey();
    if (customKey) // makes sure a key is actually pressed, equal to (customKey != NO_KEY)
    {
      Dato[dato_conta] = customKey; // store char into data array
      lcd.setCursor(dato_conta, 1); // move cursor to show each new char
      lcd.print(Dato[dato_conta]); // print char at said cursor
      dato_conta++; // increment data array by 1 to store new char, also keep track of the number of chars entered
    }


    if (dato_conta == lonxitude - 1) // if the array index is equal to the number of expected chars, compare data to master
    {
      delay(1000);
      lcd.setCursor(4, 1);

      if (!strcmp(Dato, Resultado)) // equal to (strcmp(Data, Master) == 0)
      {
        lcd.print("CORRECTO!");
        digitalWrite(verde, HIGH);
        tone(buzzer, NOTE_C5, 333);
        delay(433);
        noTone(buzzer);
        tone(buzzer, NOTE_C6, 333);
        delay(433);
        noTone(buzzer);
        tone(buzzer, NOTE_C7, 1000);
        delay(1100);// added 1 second delay to make sure the password is completely shown on screen before it gets cleared.
        noTone(buzzer);
        lcd.clear();
        limparDato();
        lcd.setCursor(0, 0);
        lcd.print("MOI BEN!");
        lcd.setCursor(0, 1);
        lcd.print("OUTRA SUMA...");
        delay(2000);
        lcd.clear();
        operando = 0;
      }
      else
      {
        lcd.print("INCORRECTO");
        digitalWrite(vermelho, HIGH);
        tone(buzzer, NOTE_D2, 500);
        delay(600);
        noTone(buzzer);
        tone(buzzer, NOTE_D2, 500);
        delay(1000);// added 1 second delay to make sure the password is completely shown on screen before it gets cleared.
        noTone(buzzer);
        // Clear the whole of line 1
        lcd.setCursor (0, 1);
        for (int i = 0; i < 16; ++i)
        {
          lcd.write(' ');
        }
        lcd.setCursor (0, 1);
        lcd.write("OUTRA VEZ...");
        delay(2000);
        // Clear the whole of line 1
        lcd.setCursor (0, 1);
        for (int i = 0; i < 16; ++i)
        {
          lcd.write(' ');
        }
        limparDato();
        operando = 1;
      }
    }
  }

}

void limparDato()
{
  while (dato_conta != 0)
  { // This can be used for any array size,
    Dato[dato_conta--] = 0; //clear array for new data
  }
  return;
}