#include "LedControl.h"

LedControl lc = LedControl(11, 13, 7, 1);

// Variables pour le mouvement aléatoire de la piste
int randNumber;
int currentLine = 3;

// Broche du joystick en axe X
const int joystickXPin = A1;

// Paramètres de vitesse et compteurs de temps pour la piste et le joueur
int routeVitesse = 400;
unsigned long routeCompteurVitesse = 0;
int joueurVitesse = 250;
unsigned long joueurCompteurVitesse = 0;

// Position initiale du joueur
int playerColumn = 3;
int playerLigne = 3;

// Lecture de la valeur de l'axe X du joystick
int joyReadX;

// Tableaux pour stocker l'état des LEDs de la piste et du joueur
uint8_t led[8];
uint8_t trackLine[5];
bool ledState[8][8];

void setup() {
  // Initialisation du générateur de nombres aléatoires avec le bruit de la broche analogique 6
  randomSeed(analogRead(6));

  // Configuration des broches du module MAX7219
  lc.shutdown(0, false);
  lc.setIntensity(0, 8);
  lc.clearDisplay(0);
  
  // Configuration de la piste droite
  led[0] = B11100011;
  led[1] = B11100011;
  led[2] = B11100011;
  led[3] = B11100011;
  led[4] = B11100011;
  led[5] = B11100011;
  led[6] = B11100011;
  led[7] = B11100011;

  // Configurations des différentes lignes de la piste
  //  trackLine[0] = B10011001;
  trackLine[0] = B10001111;
  trackLine[1] = B11000111;
  trackLine[2] = B11100011;
  trackLine[3] = B11110001;

  // Position initiale du joueur
  lc.setLed(0, playerColumn, playerLigne, true);

  // Initialisation de l'état des LEDs
  updateLedState();
}

void loop() {
  // Lecture des valeurs du joystick à intervalles réguliers
  if (millis() > joueurVitesse + joueurCompteurVitesse) {
    lectureValeursJoystick(); 
  }

  // Mise à jour de l'affichage de la piste à intervalles réguliers
  if (millis() > routeVitesse + routeCompteurVitesse) {
    screenUpdate();
    moveTrack();
    checkCollision();

    // Réinitialisation du compteur de temps pour la piste
    routeCompteurVitesse = millis();
  }
}

// Fonction pour déplacer la piste vers le haut
void moveTrack() {
  for (int i = 0; i < 7; i++) {
    led[i] = led[i + 1];
  }

  // Génération d'un nombre aléatoire pour déterminer le tracé
  randNumber = random(3) - 1;

  // Mise à jour de la position de la ligne actuelle
  currentLine = currentLine + randNumber;
  if (currentLine == 0) {
    currentLine = 1;
  }

  if (currentLine == 5) {
    currentLine = 4;
  }

  // Affichage du tracé sur la dernière ligne
  led[7] = trackLine[currentLine - 1];
  
  // Mise à jour de l'état des LEDs
  updateLedState();
}

// Fonction pour mettre à jour l'affichage LED
void screenUpdate() // Fonction pour mettre à jour l'affichage LED avec rotation de 90 degrés vers la droite
 {
  for (byte k = 0; k < 8; k++) {
    for (byte j = 0; j < 8; j++) {
      // Affichage de la piste en effectuant une rotation de 90 degrés vers la droite
      lc.setLed(0, j, 7 - k, bitRead(led[k], j));//bitRead va lire soit 1 soit 0 dans le liste Led[k] situé sur la ligne j
    }
  }

  // Affichage du joueur avec rotation de 90 degrés vers la droite
  lc.setLed(0, playerLigne, 7 - playerColumn, true);
}

// Fonction pour mettre à jour l'état des LEDs dans le tableau ledState
void updateLedState() {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      ledState[i][j] = bitRead(led[i], j);
    }
  }
}

// Fonction pour vérifier la collision entre le joueur et les LEDs allumées
void checkCollision() {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      // Vérification de la collision
      if (ledState[i][j] && i == playerColumn && j == playerLigne) {
        // Collision détectée, déclenchement de la fonction de crash
        crash();
        return;
      }
    }
  }
}

void crash() {   
  lc.clearDisplay(0);
  delay(150); 
  for (int i=0;i<8;i++){lc.setRow(0,i,B11111111);}
  delay(150);
}

void lectureValeursJoystick() {
  int joystickXValue = analogRead(joystickXPin);

  if (joystickXValue < 200) {
    deplacementPlayer(0, 1);
  } else if (joystickXValue > 800) {
    deplacementPlayer(0, -1);}


  joueurCompteurVitesse = millis();
}

void deplacementPlayer(int directionX, int directionY) {
  int nouvelleColonne = playerColumn + directionX;
  int nouvelleLigne = playerLigne + directionY;

  // Vérifier les limites de la matrice LED (0 à 7 pour les colonnes et lignes)
  if (nouvelleColonne >= 0 && nouvelleColonne < 8 && nouvelleLigne >= 0 && nouvelleLigne < 8) {
    // Mettre à jour la position du joueur seulement si elle est dans les limites
    playerColumn = nouvelleColonne;
    playerLigne = nouvelleLigne;

    // Effacer l'ancienne position du joueur et allumer la nouvelle LED du joueur
    lc.setLed(0, playerColumn, playerLigne, true);
  }
}