#include <U8x8lib.h>
#include <string.h>
#include <avr/wdt.h>
#include <avr/sleep.h>

//Can use u8x8.print(F("")); to reduce RAM usage

#define testbit(data,bitno) ((data>>bitno)&0x001)   //Bitwise manipulation macros
#define bit_set(var,bitno) ((var) |= 1 << (bitno))
#define bit_clr(var,bitno) ((var) &= ~(1 << (bitno)))

//clk,data,cs,dc,reset//

//U8X8_SSD1306_128X64_NONAME_4W_SW_SPI u8x8(4,5,6,7,8);

//U8X8_SSD1306_128X64_NONAME_4W_HW_SPI u8x8(6,7,8); //D11 - data, D13 - clk (bug, display wont turn on after waking)


//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);   // OLED SSD1306 u8x8.setFlipMode(0);
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);   // OLED SSD1306 chino  u8x8.setFlipMode(0);

//U8X8_SH1107_64X128_HW_I2C u8x8(/*reset=*/ U8X8_PIN_NONE); // OLED SSD1107 ; rota pantalla u8x8.setFlipMode(1);



unsigned int BAUD=9600;
unsigned int power_timeout=25000;
unsigned int power_count=0;
bool sleep_flg=0;

#define BTN A3 //User+Power Button
#define SPKR 10
#define OP  12

const uint8_t EightBall_0[32] = {0x00,0x00,0x00,0xC0,0x20,0x10,0x08,0x08,
                                 0x04,0x02,0x02,0x02,0x01,0x01,0x01,0x01,
                                 0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x04,
                                 0x08,0x08,0x10,0x20,0xC0,0x00,0x00,0x00};
const uint8_t EightBall_1[32] = {0xE0,0x1E,0x01,0x00,0x00,0x00,0x00,0x00,
                                 0x00,0xC0,0xF0,0xF8,0xFC,0x9C,0x6E,0x6E,
                                 0x6E,0x6E,0x9C,0xFC,0xF8,0xF0,0xC0,0x00,
                                 0x00,0x00,0x00,0x00,0x00,0x01,0x1E,0xE0};
const uint8_t EightBall_2[32] = {0x07,0x78,0x80,0x00,0x00,0x00,0x00,0x00,
                                 0x00,0x03,0x0F,0x1F,0x3F,0x38,0x77,0x77,
                                 0x77,0x77,0x38,0x3F,0x1F,0x0F,0x03,0x00,
                                 0x00,0x00,0x00,0x00,0x00,0x80,0x78,0x07};
const uint8_t EightBall_3[32] = {0x00,0x00,0x00,0x03,0x04,0x08,0x10,0x10,
                                 0x20,0x40,0x40,0x40,0x80,0x80,0x80,0x80,
                                 0x80,0x80,0x80,0x80,0x40,0x40,0x40,0x20,
                                 0x10,0x10,0x08,0x04,0x03,0x00,0x00,0x00};

const uint8_t logo_0[32] = {0x00,0x80,0x80,0xE0,0xE0,0x18,0x18,0x1E,0x1E,0x18,0x18,0x1E,0x1E,
                            0x18,0x18,0x1E,0x1E,0x18,0x18,0x9E,0x9E,0x98,0x98,0x9E,0x9E,0x18,
                            0x18,0xE0,0xE0,0x80,0x80,0x00};
const uint8_t logo_1[32] = {0x00,0x99,0x99,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,
                            0x86,0x86,0x86,0x86,0x86,0x86,0x9F,0x9F,0x19,0x19,0x1F,0x1F,0x00,
                            0x00,0xFF,0xFF,0x99,0x99,0x00};
const uint8_t logo_2[32] = {0x00,0x99,0x99,0xFF,0xFF,0x00,0x00,0xF8,0xF8,0x98,0x98,0xF9,0xF9,
                            0x61,0x61,0x61,0x61,0x61,0x61,0x7F,0x7F,0x00,0x00,0x00,0x00,0x00,
                            0x00,0xFF,0xFF,0x99,0x99,0x00};
const uint8_t logo_3[32] = {0x00,0x01,0x01,0x07,0x07,0x18,0x18,0x79,0x79,0x19,0x19,0x79,0x79,
                            0x18,0x18,0x78,0x78,0x18,0x18,0x78,0x78,0x18,0x18,0x78,0x78,0x18,
                            0x18,0x07,0x07,0x01,0x01,0x00};

const uint8_t Hand_0[16] = {0xC0,0x40,0x20,0x10,0x08,0x08,0x04,0x22,
                            0x32,0x2C,0x20,0x20,0x20,0x20,0x20,0xC0};
const uint8_t Hand_1[16] = {0x3F,0x20,0x20,0x55,0x55,0x95,0x95,0x80,
                            0x80,0xA9,0x069,0x1F,0x01,0x01,0x01,0x00};        

const char FONT5x7[] PROGMEM ={0b00000000,0b00000000,0b00000000,0b00000000,0b00000000, // ' '
                               0b00000000,0b00000000,0b01011111,0b00000000,0b00000000, // !
                               0b00000000,0b00000111,0b00000000,0b00000111,0b00000000, // "
                               0b00010100,0b01111111,0b00010100,0b01111111,0b00010100, // #
                               0b00100100,0b00101010,0b01111111,0b00101010,0b00010010, // $
                               0b00100011,0b00010011,0b00001000,0b01100100,0b01100010, // %
                               0b00110110,0b01001001,0b01010101,0b00100010,0b01010000, // &
                               0b00000000,0b00000101,0b00000011,0b00000000,0b00000000, // '
                               0b00000000,0b00011100,0b00100010,0b01000001,0b00000000, // (
                               0b00000000,0b01000001,0b00100010,0b00011100,0b00000000, // )
                               0b00010100,0b00001000,0b00111110,0b00001000,0b00010100, // *
                               0b00001000,0b00001000,0b00111110,0b00001000,0b00001000, // +
                               0b00000000,0b01010000,0b00110000,0b00000000,0b00000000, // ,
                               0b00001000,0b00001000,0b00001000,0b00001000,0b00001000, // -
                               0b00000000,0b01100000,0b01100000,0b00000000,0b00000000, // .
                               0b01000000,0b00100000,0b00010000,0b00001000,0b00000100, // /
              
                               0b00111110,0b01010001,0b01001001,0b01000101,0b00111110, //0
                               0b00000000,0b01000010,0b01111111,0b01000000,0b00000000, //1
                               0b01000010,0b01100001,0b01010001,0b01001001,0b01000110, //2
                               0b00100010,0b01001001,0b01001001,0b01001001,0b00110110, //3
                               0b00011000,0b00010100,0b00010010,0b01111111,0b00010000, //4
                               0b00100111,0b01000101,0b01000101,0b01000101,0b00111001, //5
                               0b00111110,0b01001001,0b01001001,0b01001001,0b00110010, //6
                               0b00000001,0b00000001,0b01110001,0b00001001,0b00000111, //7
                               0b00110110,0b01001001,0b01001001,0b01001001,0b00110110, //8
                               0b00100110,0b01001001,0b01001001,0b01001001,0b00111110, //9
                               0b00000000,0b00110110,0b00110110,0b00000000,0b00000000, // :
                               0b00000000,0b01010110,0b00110110,0b00000000,0b00000000, // ;
                               0b00001000,0b00010100,0b00100010,0b01000001,0b00000000, // <
                               0b00010100,0b00010100,0b00010100,0b00010100,0b00010100, // =
                               0b01000001,0b00100010,0b00010100,0b00001000,0b00000000, // >
                               0b00000010,0b00000001,0b01010001,0b00001001,0b00000110, // ?
             
                               0b00110010,0b01001001,0b01111001,0b01000001,0b00111110, // @
                               0b01111100,0b00010010,0b00010001,0b00010010,0b01111100, //A
                               0b01111111,0b01001001,0b01001001,0b01001001,0b00110110, //B
                               0b00111110,0b01000001,0b01000001,0b01000001,0b00100010, //C
                               0b01111111,0b01000001,0b01000001,0b01000001,0b00111110, //D
                               0b01111111,0b01001001,0b01001001,0b01001001,0b01000001, //E
                               0b01111111,0b00001001,0b00001001,0b00001001,0b00000001, //F
                               0b00111110,0b01000001,0b01001001,0b01001001,0b01111010, //G
                               0b01111111,0b00001000,0b00001000,0b00001000,0b01111111, //H
                               0b00000000,0b01000001,0b01111111,0b01000001,0b00000000, //I
                               0b00100000,0b01000001,0b01000001,0b00111111,0b00000001, //J
                               0b01111111,0b00001000,0b00010100,0b00100010,0b01000001, //K
                               0b01111111,0b01000000,0b01000000,0b01000000,0b01000000, //L
                               0b01111111,0b00000010,0b00001100,0b00000010,0b01111111, //M
                               0b01111111,0b00000100,0b00001000,0b00010000,0b01111111, //N
                               0b00111110,0b01000001,0b01000001,0b01000001,0b00111110, //O
            
                               0b01111111,0b00001001,0b00001001,0b00001001,0b00000110, //P
                               0b00111110,0b01000001,0b01010001,0b00100001,0b01011110, //Q
                               0b01111111,0b00001001,0b00011001,0b00101001,0b01000110, //R
                               0b00100110,0b01001001,0b01001001,0b01001001,0b00110010, //S
                               0b00000001,0b00000001,0b01111111,0b00000001,0b00000001, //T
                               0b00111111,0b01000000,0b01000000,0b01000000,0b00111111, //U
                               0b00011111,0b00100000,0b01000000,0b00100000,0b00011111, //V
                               0b00111111,0b01000000,0b00111000,0b01000000,0b00111111, //W
                               0b01100011,0b00010100,0b00001000,0b00010100,0b01100011, //X
                               0b00000111,0b00001000,0b01110000,0b00001000,0b00000111, //Y
                               0b01100001,0b01010001,0b01001001,0b01000101,0b01000011, //Z
                               0b00000000,0b01111111,0b01000001,0b01000001,0b00000000, // [
                               0b00010101,0b00010110,0b01111100,0b00010110,0b00010101, // Yen
                               0b00000000,0b01000001,0b01000001,0b01111111,0b00000000, // ]
                               0b00000100,0b00000010,0b00000001,0b00000010,0b00000100, // ^
                               0b01000000,0b01000000,0b01000000,0b01000000,0b01000000, // _
            
                               0b00000000,0b00000001,0b00000010,0b00000100,0b00000000, // `
                               0b00100000,0b01010100,0b01010100,0b01010100,0b01111000, //a
                               0b01111111,0b01001000,0b01000100,0b01000100,0b00111000, //b
                               0b00111000,0b01000100,0b01000100,0b01000100,0b00100000, //c
                               0b00111000,0b01000100,0b01000100,0b01001000,0b01111111, //d
                               0b00111000,0b01010100,0b01010100,0b01010100,0b00011000, //e
                               0b00001000,0b01111110,0b00001001,0b00000001,0b00000010, //f
                               0b00001100,0b01010010,0b01010010,0b01010010,0b00111110, //g
                               0b01111111,0b00001000,0b00000100,0b00000100,0b01111000, //h
                               0b00000000,0b01000100,0b01111101,0b01000000,0b00000000, //i
                               0b00100000,0b01000000,0b01000100,0b00111101,0b00000000, //j
                               0b01111111,0b00010000,0b00101000,0b01000100,0b00000000, //k
                               0b00000000,0b01000001,0b01111111,0b01000000,0b00000000, //l
                               0b01111100,0b00000100,0b00011000,0b00000100,0b01111000, //m
                               0b01111100,0b00001000,0b00000100,0b00000100,0b01111000, //n
                               0b00111000,0b01000100,0b01000100,0b01000100,0b00111000, //o
           
                               0b01111100,0b00010100,0b00010100,0b00010100,0b00001000, //p
                               0b00001000,0b00010100,0b00010100,0b00011000,0b01111100, //q
                               0b01111100,0b00001000,0b00000100,0b00000100,0b00001000, //r
                               0b01001000,0b01010100,0b01010100,0b01010100,0b00100100, //s
                               0b00000100,0b00111111,0b01000100,0b01000000,0b00100000, //t
                               0b00111100,0b01000000,0b01000000,0b00100000,0b01111100, //u
                               0b00011100,0b00100000,0b01000000,0b00100000,0b00011100, //v
                               0b00111100,0b01000000,0b00111000,0b01000000,0b00111100, //w
                               0b01000100,0b00101000,0b00010000,0b00101000,0b01000100, //x
                               0b00001100,0b01010000,0b01010000,0b01010000,0b00111100, //y
                               0b01000100,0b01100100,0b01010100,0b01001100,0b01000100, //z
                               0b00000000,0b00001000,0b00110110,0b01000001,0b00000000, // {
                               0b00000000,0b00000000,0b01111111,0b00000000,0b00000000, // |
                               0b00000000,0b01000001,0b00110110,0b00001000,0b00000000, // }
                               0b00001000,0b00001000,0b00101010,0b00011100,0b00001000, // ->
                               0b00001000,0b00011100,0b00101010,0b00001000,0b00001000, // <-
                               };

unsigned char LineBuff[128];
unsigned char displine=1;
//                 "                "
String Messages[]={"Es cierto",
                   "Esta decidido",
                   "Sin duda",
                   "Si, definitivamen",
                   "Puede confiar el",
                   "A mi modo de ver, sí",
                   "Lo mas probable",
                   "Perspectiva Buena",
                   "Si",
                   "Todo apunta que si",
                   
                   "El futuro es gris",
                   "Pregunta mas tarde",
                   "Mejor no decidir",
                   "No decidir ahora",
                   "Pregunte de nuevo",
                   
                   "No cuentes  ello",
                   "Mi respuesta es no",
                   "Mis fuentes dicen no",
                   "no  tan buenas",
                   "Muy dudoso",
                   };

void printchar(int x, char ASCII){
  for(int i=0;i<5;i++){
    LineBuff[x+i]=pgm_read_byte_near(FONT5x7+5*(ASCII-32)+i);
  }
}

void writeString(int x, int y, String str){
  bool chr=0;
  int t=0;
  unsigned char len = str.length();
  unsigned char p;
  while(len-20*t>0){
    for(int i=0;i<20;i++){ //must make sure str is less than 20 characters long
      p=str.charAt(i+20*t);
      if(p==0){i=20;}else{printchar(x+i*(chr+5), p);}
      chr=1;
    }
    u8x8.drawTile(0,y+t,16,LineBuff);
    for(int i=0;i<128;i++){LineBuff[i]=0;}
    t++;
    //Serial.println(t);
  }
  //Serial.println("A");
}

void begin(void){
  u8x8.begin();
}

void setContrast(int a){
  u8x8.setContrast(a);
}

void clear(void){
  u8x8.clear();
}

void drawTile(int a,int b,int c,int d){
  u8x8.drawTile(a,b,c,d);
}

void drawString(int a,int b,int c){
  u8x8.drawString(a,b,c);
}

void setFont(int a){
  u8x8.setFont(a);
}

void setInverseFont(int a){
  u8x8.setInverseFont(a);
}

void setPowerSave(int a){
  u8x8.setPowerSave(a);
}

void setup() {
  //Serial.begin(BAUD);
  //Serial.println("Hello");

  pinMode(BTN,INPUT_PULLUP);
  pinMode(OP,OUTPUT);
  digitalWrite(OP,HIGH);
  pinMode(SPKR,OUTPUT);

  begin();
  setPowerSave(0);
  setContrast(255);
  setFont(u8x8_font_victoriabold8_r);
  //setFont(u8x8_font_5x7_f);
  u8x8.setFlipMode(0);
  //u8x8.inverse();
  clear();
  splashscreen();
  beep(3000,25);
  delay(5000);
  clear();
  drawString(2,0,"Magic 8 Ball");
}

void tile_animate(int row,int x,bool j){
  unsigned char c=0;
  u8x8.clearLine(row);
    for(int i=0;i<24;i++){
      if(i>=x%8&&c<16){
        if(j==1){
          LineBuff[i]=Hand_1[c];
        }else{
          LineBuff[i]=Hand_0[c];
        }
        c++;
      }
    }
    drawTile(x/8,row,3,LineBuff);
    for(int i=0;i<24;i++){LineBuff[i]=0;}
}

void splashscreen(void){
  clear();
  writeString(50,2,"Magic 8 Ball");
  writeString(50,3,"v1.0");
  writeString(50,4,"sjm4306");
  writeString(50,5,"2020");
  drawTile(1,2,4,logo_0);
  drawTile(1,3,4,logo_1);
  drawTile(1,4,4,logo_2);
  drawTile(1,5,4,logo_3);
}

void beep(unsigned int f, unsigned int len){  //Blocking beep function: f Hertz, len ms
  unsigned long temp1= ((double) len * (double) f) / 1000;
  unsigned int temp= (double) 500000/ (double) f;
  while(temp1>0){
    //Digital 10 = PB2
    PORTB|=0b00000100;  
    //digitalWrite(SPKR,HIGH);
    delayMicroseconds(temp);
    PORTB&=0b11111011;  
    //digitalWrite(SPKR,LOW);
    delayMicroseconds(temp);
    temp1--;
  }
}

void pinInterrupt(void){
  detachInterrupt(0);
}

void loop() {  
  bool flash=0;
  bool dir=0;
  unsigned int cnt=20;
  while(digitalRead(BTN)){   //Bloqueo de giro, esperando a que se presione el botón
    if(cnt<10){
      cnt++;
    }else{
      cnt=0;
      flash^=1;
      if(flash==1){
        writeString(35,3,"Pulsar Boton");
        writeString(35,4,"Para Agitar");
      }else{
        u8x8.clearLine(3);
        u8x8.clearLine(4);
        //writeString(35,3,"               ");
        //writeString(35,4,"               ");
      }
      drawTile(0,2,4,EightBall_0);
      drawTile(0,3,4,EightBall_1);
      drawTile(0,4,4,EightBall_2);
      drawTile(0,5,4,EightBall_3);
    }

    unsigned char t=0;
    if(flash==1){t=50+cnt;}else{t=60-cnt;}
    tile_animate(6,t,0);
    tile_animate(7,t,1);
    
    delay(50);

    if(power_count>power_timeout){
      sleep_flg=1;
      //Serial.println("Sleeping!");
      power_count=0;
      delay(1000);
    }else{
      sleep_flg=0;
      power_count++;
    }

    if(sleep_flg==1){
      attachInterrupt(0,pinInterrupt,LOW);
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);
      setPowerSave(1);
      digitalWrite(OP,LOW);
      for(int i=0;i<18;i++){
        if(i!=2){digitalWrite(i,LOW);pinMode(i,INPUT);}
      }
      //sleep_bod_disable();
      wdt_disable();  //disable watchdog
      ADCSRA &= ~(1<<7);   //ADEN=0, turn off adc
      PRR=0b01101111; //power down individual peripherals to lower current consumption
      MCUCR |= (3<<5); //set both BODS and BODSE at the same time
      MCUCR = (MCUCR & ~(1<<5))|(1<<6); //then set BODS bit and clear BODSE bit at the same time
      sleep_enable();
      sleep_mode();
      sleep_disable();
      PRR=0b00000000;
      setPowerSave(0);
      sleep_flg=0;
      //Serial.println("Awake!");
      pinMode(SPKR,OUTPUT);
      begin();
      drawString(2,0,"Magic 8 Ball");
      delay(500);
    }
  }

  power_count=0;

  u8x8.clearLine(2);
  u8x8.clearLine(3);
  u8x8.clearLine(4);
  u8x8.clearLine(5);
  u8x8.clearLine(6);
  u8x8.clearLine(7);

  unsigned long c=0;
  unsigned char randNumber=0;
  while(!digitalRead(BTN)){   //Count while button is held
    c++;
    writeString(35,4,"Consulting");
    writeString(35,5,"Spirits");
    drawTile(0,c%3+2,4,EightBall_0);
    drawTile(0,c%3+3,4,EightBall_1);
    drawTile(0,c%3+4,4,EightBall_2);
    drawTile(0,c%3+5,4,EightBall_3);
    u8x8.clearLine(c%3+1);
    u8x8.clearLine(c%3+6);
    if(c%3==0){u8x8.clearLine(7);}
    beep(3000,25);
    delay(100);
  }
  for(int i=1;i<8;i++){
    u8x8.clearLine(i);
  }
  randomSeed(c+random());
  delay(1000);
  randNumber=random(20);  //20 messages total
  
  u8x8.clearLine(6);
  u8x8.clearLine(7);
  writeString(0,7,Messages[randNumber]);

  writeString(35,3,"Magic 8 Ball");
  writeString(35,4,"Dice:");

  drawTile(0,2,4,EightBall_0);
  drawTile(0,3,4,EightBall_1);
  drawTile(0,4,4,EightBall_2);
  drawTile(0,5,4,EightBall_3);

  delay(5000);

  //u8x8.clearLine(0);
}