#include "LedControl.h"
#include "Timer.h"

/*
 MAX7129 8x8 led matrix indexing
   7 6 ... 1 0
 0 x x ... x x
 1 x x ... x x
 . ...
 . ...
 6 x x ... x x
 7 x x ... x x
*/

/* https://wokwi.com/projects/300754474795794957" 
   this https://wokwi.com/projects/291779699024069128
   face https://randomnerdtutorials.com/guide-for-8x8-dot-matrix-max7219-with-arduino-pong-game/
*/

/*************************************************
*   General stuffs 
*************************************************/
#define CS_PIN  PB0
#define CLK_PIN PB1
#define DIN_PIN PB2
#define BTN_PIN PB4
#define RND_PIN A0
#define MAX_SEG 1
#define LED_ON  1
#define LED_OFF 0

enum MachineState{
  ON, OFF
};
MachineState currentMachineState;

LedControl matrix = LedControl(DIN_PIN, CLK_PIN, CS_PIN, MAX_SEG); // MAX7219
bool waitRefresh = false;

/*************************************************
*   for Avoid Collosion Game
*************************************************/
const byte MAX_NUMBER_ENEMIES  = 4;
const byte FIX_AVOID_COL_INDEX = 7;
const byte STR_AVOID_ROW_INDEX = 7;

byte currAvoidRowIndex   = 0;
byte prevAvoidRowIndex   = 0;

byte currEnemiesR[MAX_NUMBER_ENEMIES] = { 1, 3, 5, 7 }; // row
byte currEnemiesC[MAX_NUMBER_ENEMIES] = { 0, 0, 0, 0 }; // column
byte currEnemiesL[MAX_NUMBER_ENEMIES] = { 1, 2, 3, 4 }; // length
byte prevEnemiesC[MAX_NUMBER_ENEMIES] = { 7, 7, 7, 7 }; // prev column
int currEnemiesRnd[MAX_NUMBER_ENEMIES] = { 100, 100, 100, 100  };
Timer currEnemyiesTimer[MAX_NUMBER_ENEMIES];

Timer currEnemyTimer1;
Timer currEnemyTimer2;
Timer currEnemyTimer3;
Timer currEnemyTimer4;


/*************************************************
*   General functions
*************************************************/
/* pin change interrupt wakes us up */
ISR (PCINT0_vect) {
  currentMachineState = ON;
}

void setup() {
  cli();
  PCMSK |= (1 << BTN_PIN);  
  GIMSK |= (1 << PCIE);             
  pinMode(BTN_PIN, INPUT_PULLUP);   

  randomSeed(analogRead(RND_PIN));
  currentMachineState = OFF;
  sei();

  currAvoidRowIndex = STR_AVOID_ROW_INDEX;
  prevAvoidRowIndex = 0;

  matrix.shutdown(0, false);
  matrix.setIntensity(0, 7);
  matrix.clearDisplay(0);

  for(int i=0;i<MAX_NUMBER_ENEMIES;i++){
    currEnemiesRnd[i] = random(150, 300);
    currEnemyiesTimer[i].setInterval(currEnemiesRnd[i]);
    switch(i){
     case 0: currEnemyiesTimer[i].setCallback(AvoidCollosionBoth0); break;
     case 1: currEnemyiesTimer[i].setCallback(AvoidCollosionBoth1); break;
     case 2: currEnemyiesTimer[i].setCallback(AvoidCollosionBoth2); break;
     case 3: currEnemyiesTimer[i].setCallback(AvoidCollosionBoth3); break;
    }
    currEnemyiesTimer[i].start();
  }
}

void loop() {
  AvoidCollosionGame();
}

void AvoidCollosionBoth0(){
  AvoidCollosionEnemiesOff(0);
  AvoidCollosionEnemiesOn(0);
}

void AvoidCollosionBoth1(){
  AvoidCollosionEnemiesOff(1);
  AvoidCollosionEnemiesOn(1);
}

void AvoidCollosionBoth2(){
  AvoidCollosionEnemiesOff(2);
  AvoidCollosionEnemiesOn(2);
}

void AvoidCollosionBoth3(){
  AvoidCollosionEnemiesOff(3);
  AvoidCollosionEnemiesOn(3);
}

void AvoidCollosionEnemiesOff(byte i){
    prevEnemiesC[i] = currEnemiesC[i];
    currEnemiesC[i] = ( currEnemiesC[i] + 1 ) % 8;
    matrix.setLed(0, currEnemiesR[i], prevEnemiesC[i], LED_OFF);
    if(currEnemiesC[i] == 0){
      int a = 2*i;
      int b = 2*i+1;
     currEnemiesR[i] = random(a,b);
    // if(i == 0){currEnemiesR[0] = 0,1;}
    //  currEnemiesR[1] = random(2,3);
    //  currEnemiesR[2] = random(4,5);
    //  currEnemiesR[3] = random(6,7); 
    }
}

void AvoidCollosionEnemiesOn(byte i){
    matrix.setLed(0, currEnemiesR[i], currEnemiesC[i], LED_ON);
}

void AvoidCollosionGame(){
    /* update parameters of all enemies */
    for(int i=0;i<MAX_NUMBER_ENEMIES;i++){
      currEnemyiesTimer[i].update();
    }

    /* button pushed so move up the ball and enemies */
    if( !digitalRead(BTN_PIN) && currentMachineState == ON ){
      
      if( 0 < currAvoidRowIndex ){
       prevAvoidRowIndex = currAvoidRowIndex;
       currAvoidRowIndex = currAvoidRowIndex - 1;
      }else{
       prevAvoidRowIndex = 0;
       currAvoidRowIndex = STR_AVOID_ROW_INDEX;
      };
      matrix.setLed(0, currAvoidRowIndex, FIX_AVOID_COL_INDEX, LED_ON);

      delay(50);

      matrix.setLed(0, prevAvoidRowIndex, FIX_AVOID_COL_INDEX, LED_OFF);
      currentMachineState = OFF;
    }else{
     delay(50);
    }
}
ATTINY8520PU