#include <KTGame.h>

#define NODE_ABOUT_LAB 13

#define Max7219_pinCLK 10
#define Max7219_pinCS 11
#define Max7219_pinDIN  12
#define ONLED 6
#define SOLVEDLED 7
#define UPPIN 1
#define DOWNPIN 2
#define LEFTPIN 3
#define RIGHTPIN 4
#define DISPLAYPIN 5

#define DOWN B1
#define UP B10
#define LEFT B100
#define RIGHT B1000
#define LANDMARK B10000

KTGame game = KTGame(NODE_ABOUT_LAB,SOLVEDLED,ONLED);

int lab1 [6][6] = {{DOWN+RIGHT, LEFT+RIGHT, DOWN+LEFT, DOWN+RIGHT, LEFT+RIGHT, LEFT},
                   {DOWN+UP+LANDMARK, DOWN+RIGHT, LEFT+UP, UP+RIGHT, LEFT+RIGHT, DOWN+LEFT},
                   {DOWN+UP, UP+RIGHT, DOWN+LEFT, DOWN+RIGHT, LEFT+RIGHT, DOWN+UP+LEFT+LANDMARK},
                   {DOWN+UP, RIGHT, RIGHT+DOWN+LEFT, UP+LEFT, RIGHT, DOWN+UP+LEFT},
                   {DOWN+UP, LEFT+RIGHT, DOWN+LEFT, DOWN+RIGHT, LEFT, UP+DOWN},
                   {RIGHT+UP, LEFT, RIGHT+UP, UP+LEFT, RIGHT, LEFT+UP}
            };
            
volatile int positionX;
volatile int positionY;

int finishX;
int finishY;

volatile boolean blink;

void setup() {
  Serial.begin(9600);
  pinMode(Max7219_pinCLK,OUTPUT);
  pinMode(Max7219_pinCS,OUTPUT);
  pinMode(Max7219_pinDIN,OUTPUT);
  delay(50);  //Initialiser
  Write_Max7219(0x09, 0x00);       //decoding ï¼šBCD
  Write_Max7219(0x0a, 0x03);       //brightness 
  Write_Max7219(0x0b, 0x07);       //scanlimitï¼›8 LEDs
  Write_Max7219(0x0c, 0x01);       //power-down modeï¼š0ï¼Œnormal modeï¼š1
  Write_Max7219(0x0f, 0x00);       //test displayï¼š1ï¼›EOTï¼Œdisplayï¼š0
  
  pciSetup(UPPIN);
  pciSetup(DOWNPIN);
  pciSetup(LEFTPIN);
  pciSetup(RIGHTPIN);
  pinMode(DISPLAYPIN,INPUT_PULLUP);
}

//Ecriture sur une rangee
void Write_Max7219(unsigned char address,unsigned char dat){
  digitalWrite(Max7219_pinCS,LOW);
  Write_Max7219_byte(address);           //addressï¼Œcode of LED
  Write_Max7219_byte(dat);               //dataï¼Œfigure on LED 
  digitalWrite(Max7219_pinCS,HIGH);
}

// Ecriture sur un 8x8
void Write_Max7219_byte(unsigned char DATA) {   
  unsigned char i;
  digitalWrite(Max7219_pinCS,LOW);      
  for(i=8;i>=1;i--) {        
    digitalWrite(Max7219_pinCLK,LOW);
    digitalWrite(Max7219_pinDIN,DATA&0x80);// Extracting a bit data
    DATA = DATA<<1;
    digitalWrite(Max7219_pinCLK,HIGH);
  }                                 
}

void pciSetup(byte pin)
{
    pinMode(pin,INPUT_PULLUP);
    *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
    PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
    PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

ISR (PCINT2_vect) {
  if (digitalRead(UPPIN)==LOW){
    if ((lab1[positionX][positionY]& (UP )) >> 2){
      positionY--;
    } else {
      game.madeAFault();
    }
  }
  if (digitalRead(DOWNPIN)==LOW){
    if ((lab1[positionX][positionY]& (DOWN )) >> 1){
      positionY++;
    } else {
      game.madeAFault();
    }
  }
  if (digitalRead(LEFTPIN)==LOW){
    if ((lab1[positionX][positionY]& (LEFT )) >> 3){
      positionX++;
    } else {
      game.madeAFault();
    }
  }
  if (digitalRead(RIGHTPIN)==LOW){
     if ((lab1[positionX][positionY]& (RIGHT )) >> 4){
      positionX--;
    } else {
      game.madeAFault();
    }
  }
  if (positionX==finishX && positionY==finishY){
    game.moduleSolved();
  }
}  

void display(){
  unsigned char DATA;
  if (digitalRead(DISPLAYPIN)==LOW){
    for(int x=6;x>=1;x--) {
      DATA = B0;
      for(int y=6;y>=1;y--) {
        DATA = DATA<<1;
        if ((lab1[x][y]& (LANDMARK )) >> 5){
           DATA = DATA+B1;
        } else if (blink && x==positionX && y==positionY){
           DATA = DATA+B1;
        }
      }
      Write_Max7219(x, DATA);  
    }
  } else {
    for(int x=6;x>=1;x--) {
      DATA = B0;
      for(int y=6;y>=1;y--) {
        DATA = DATA<<1;
        if (blink && x==positionX && y==positionY){
           DATA = DATA+B1;
        }
        if (x==finishX && y==finishY){
           DATA = DATA+B1;
        }
      }
      Write_Max7219(x, DATA);  
    }
  }
}


//Need 6 analog, can do only 5 with interrupt, but it's not a button, we can wait for next loop
void loop() {
  delay(100);
  blink=!blink;
}
