//graphics for dice/cards/numerical rolls
#include "graphics.h"

//const char dicePip[]={0,60,126,126,126,126,60,0};
const char dicePip[]={60,126,255,255,255,255,126,60};
const char diceBlank[]={0,0,0,0,0,0,0,0};
const char dispNames[][8]={
    " NUMBER",
    " PIPS  ",
    " CARDS ",
    " COIN  ",
    " NONE  "
};
const char coinString[]=" COIN";
const char notUsedString[]="";

const char rollMin[5]={ //align to graphicsDisplay_t enum
    2,2,52,2,2
};

const char rollMax[5]={ //align to graphicsDisplay_t enum
    100,9,58,2,2    
};

const rollDisplay_t emptyTemplate={.disp=DISP_NULL};

const rollDisplay_t rollTemplates[TEMPLATE_COUNT]={       //default to black for lower power
    {.disp=DISP_NUMBER,.colour=BLACK,.roll=4,.x=34},
    {.disp=DISP_PIPS,.colour=BLACK,.roll=6,.x=36},
    {.disp=DISP_NUMBER,.colour=BLACK,.roll=8,.x=34},
    {.disp=DISP_NUMBER,.colour=BLACK,.roll=10,.x=34},
    {.disp=DISP_NUMBER,.colour=BLACK,.roll=12,.x=34},
    {.disp=DISP_NUMBER,.colour=BLACK,.roll=20,.x=34},
    {.disp=DISP_NUMBER,.colour=BLACK,.roll=100,.x=34},
    {.disp=DISP_COIN,.colour=BLACK,.roll=2,.x=36},
    {.disp=DISP_CARD,.colour=BLACK,.roll=52,.x=34},
    {.disp=DISP_CARD,.colour=BLACK,.roll=53,.x=34},
    {.disp=DISP_CARD,.colour=BLACK,.roll=54,.x=34}
};
/*
//generated by rollName() instead
const char templateNames[][8]={    //matches rollTemplates[]
    "D4     ",
    "D6     ",
    "D8     ",
    "D10    ",
    "D12    ",
    "D20    ",
    "D100   ",
    "COIN   ",
    "52 CARD",
    "53 CARD",
    "54 CARD"
};
*/
const unsigned long pipPattern1[]={
    //4096=centre
    //16777217=top left,bottom right
    //1048592=top right, bottom left
    //4194308=top/bottom
    //17408=left/right
    0,  //0
    4096,//1
    16777217, //2
    16777217+4096,//3
    16777217+1048592,//4
    16777217+1048592+4096,//5
    16777217+1048592+4194308,//6
    16777217+1048592+4194308+4096,//7
    16777217+1048592+4194308+17408,//8
    16777217+1048592+4194308+17408+4096 //9
};

const unsigned long pipPattern2[]={ //alternate display for 2,3,6,7
    //4096=centre
    //16777217=top left,bottom right
    //1048592=top right, bottom left
    //4194308=top/bottom
    //17408=left/right
    0,  //0
    4096,//1
    1048592, //2
    1048592+4096,//3
    1048592+16777217,//4
    1048592+16777217+4096,//5
    1048592+16777217+17408,//6
    1048592+16777217+17408+4096,//7
    1048592+16777217+17408+4194308,//8
    1048592+16777217+17408+4194308+4096 //9
};

void drawPips(unsigned long b,unsigned char m){  //5x5 grid of 8x8, b contains bitmap, lsb at top left, m is xor mask, uses OLEDpage,OLEDcol but leaves unchanged
    char i,j;    
    for(j=0;j<5;j++){
        I2Cstart();
        I2Cbyte(OLED_ADDRESS); //write
        OLEDsetpos(OLEDpage+j,OLEDcol);
        I2Cbyte(0x40); //write data
        for(i=0;i<5;i++){
            if(b&1){
                I2CvramByte(dicePip[0]^m);
                I2CvramByte(dicePip[1]^m);
                I2CvramByte(dicePip[2]^m);
                I2CvramByte(dicePip[3]^m);
                I2CvramByte(dicePip[4]^m);
                I2CvramByte(dicePip[5]^m);
                I2CvramByte(dicePip[6]^m);
                I2CvramByte(dicePip[7]^m);
            }else{
                I2CvramByte(diceBlank[0]^m);
                I2CvramByte(diceBlank[1]^m);
                I2CvramByte(diceBlank[2]^m);
                I2CvramByte(diceBlank[3]^m);
                I2CvramByte(diceBlank[4]^m);
                I2CvramByte(diceBlank[5]^m);
                I2CvramByte(diceBlank[6]^m);
                I2CvramByte(diceBlank[7]^m);                
            }
            b=b>>1;
        }
        I2Cstop();                        
    }   
}

const char normalDiceStyle[]={  //various bitmaps, white on black
    8,  //size
    0,0,192,48,8,8,4,4,  //top left
    4,  //top
    4,4,8,8,48,192,0,0,  //top right
    0,0,255,0,0,0,0,0,  //left border
    0,0,0,0,0,255,0,0,  //right border
    0,0,3,12,16,16,32,32,  //bottom left
    32,  //bottom
    32,32,16,16,12,3,0,0,  //bottom right
};

const char revDiceStyle[]={  //various bitmaps, black on white
    8,  //size
    0,0,192,240,248,248,252,252,  //top left
    252,  //top
    252,252,248,248,240,192,0,0,  //top right
    0,0,255,255,255,255,255,255,  //left border
    255,255,255,255,255,255,0,0,  //right border
    0,0,3,15,31,31,63,63,  //bottom left
    63,  //bottom
    63,63,31,31,15,3,0,0,  //bottom right
};

//narrow versions
const char normalCardStyle[]={
    2,  //size
    240,8,4,8,240,  //top
    255,0,0,255,  //middle
    15,16,32,16,15,  //bottom
};

const char revCardStyle[]={
    2,  //size
    240,248,252,248,240,  //top
    255,255,255,255,  //middle
    15,31,63,31,15,  //bottom
};

/*
//wider versions
const char normalCardStyle[]={
    4,  //size
    0,240,8,4,4,4,8,240,0,  //top
    0,255,0,0,0,0,255,0,  //middle
    0,15,16,32,32,32,16,15,0,  //bottom    
};

const char revCardStyle[]={
    4,  //size
    0,240,248,252,252,252,248,240,0,  //top
    0,255,255,255,255,255,255,0,  //middle
    0,15,31,63,63,63,31,15,0,  //bottom    
};
*/

void drawBorder(char x, char y, char w, char h, const char* s){    //border measures s[0]x8, w,h refer to inside space in cols, pages, s is style
    char i,j;
    char n=s[0];
    char p=1;   //1 past s[0]
    //top row
    I2Cstart();
    I2Cbyte(OLED_ADDRESS); //write
    OLEDsetpos(y,x);
    I2Cbyte(0x40); //write data
    for(i=p;i<(p+n);i++){I2CvramByte(s[i]);}
    p=p+n;
    for(i=0;i<w;i++){I2CvramByte(s[p]);}
    p=p+1;
    for(i=p;i<(p+n);i++){I2CvramByte(s[i]);}
    p=p+n;
    I2Cstop();                        
    //middle rows
    for(j=0;j<h;j++){
        I2Cstart();
        I2Cbyte(OLED_ADDRESS); //write
        OLEDsetpos(y+1+j,x);
        I2Cbyte(0x40); //write data
        for(i=p;i<(p+n);i++){I2CvramByte(s[i]);}
        I2Cstop();                                        
        I2Cstart();
        I2Cbyte(OLED_ADDRESS); //write
        OLEDsetpos(y+1+j,x+n+w);
        I2Cbyte(0x40); //write data
        for(i=p+n;i<(p+n+n);i++){I2CvramByte(s[i]);}
        I2Cstop();                                
    }
    p=p+n+n;
    //bottom row
    I2Cstart();
    I2Cbyte(OLED_ADDRESS); //write
    OLEDsetpos(y+h+1,x);
    I2Cbyte(0x40); //write data
    for(i=p;i<(p+n);i++){I2CvramByte(s[i]);}
    p=p+n;
    for(i=0;i<w;i++){I2CvramByte(s[p]);}
    p=p+1;
    for(i=p;i<(p+n);i++){I2CvramByte(s[i]);}
    I2Cstop();                            
}

const unsigned long* getRandPip(void){
    if(getLFSRbit()){
        return &pipPattern1[0];     //choose one at random
    }else{
        return &pipPattern2[0];        
    }
}

void drawBorderGraphics(rollDisplay_t* r){
    switch(r->disp){
        case DISP_NUMBER:
        case DISP_CARD:
            OLEDcol=r->x;
            OLEDpage=1;
            OLEDblock(NUMBER_TOTAL,7,0);            
            if(r->colour){
                drawBorder(r->x,1,NUMBER_WIDTH,5,revCardStyle);  //white
            }else{
                drawBorder(r->x,1,NUMBER_WIDTH,5,normalCardStyle);  //black       
            }
            break;
        case DISP_PIPS:
            OLEDcol=r->x;
            OLEDpage=1;
            OLEDblock(PIPS_TOTAL,7,0);            
            if(r->colour){
                drawBorder(r->x,1,PIPS_WIDTH,5,revDiceStyle);  //white
            }else{
                drawBorder(r->x,1,PIPS_WIDTH,5,normalDiceStyle);  //black       
            }
            break;
        case DISP_COIN: 
            OLEDcol=r->x;
            OLEDpage=1;
            //OLEDblock(COIN_WIDTH,7,0);//full bitmap, just need to clear area            
            OLEDchar(COIN_BLANK,coinFont);   //empty coin glyph
            break;
        default: break;
    }
}

void drawGraphics(rollDisplay_t* r, unsigned char v){  //v is roll/toss value
    unsigned char t,u;  //tens, units, or suit, values
    unsigned char m=0;
    if(r->colour){m=0xFF;}
    switch(r->disp){
        case DISP_NUMBER:
            OLEDcol=r->x+NUMBER_BORDER;
            OLEDpage=2;            
            if(v<10){   //pad for single digit
                OLEDblock(NUMBER_WIDTH/4,5,m);   //padding since it is only one glyph
                if(r->colour){
                    OLEDcharRev(v,font2840);
                }else{
                    OLEDchar(v,font2840);
                }                
                OLEDblock(NUMBER_WIDTH/4,5,m);   //padding since it is only one glyph
            }else{
                u=v%10;
                t=v/10; //note that this can be the '10' character for v=100
                if(r->colour){
                    OLEDcharRev(t,font2840);
                    OLEDcharRev(u,font2840);
                }else{
                    OLEDchar(t,font2840);
                    OLEDchar(u,font2840);
                }                                
            }
            break;
        case DISP_CARD:
            OLEDcol=r->x+NUMBER_BORDER;
            OLEDpage=2;
            if(v>52){   //joker                
                OLEDblock(NUMBER_WIDTH/4,5,m);   //padding since it is only one glyph
                if(r->colour){
                    OLEDcharRev(CARD_JOKER,font2840);
                }else{
                    OLEDchar(CARD_JOKER,font2840);
                }
                OLEDblock(NUMBER_WIDTH/4,5,m);   //padding since it is only one glyph                
            }else{      //face card
                t=((v-1)/13)+CARD_HEART; //0-3-> suits
                u=cardValues[(v-1)%13]; //0-12-> A-K
                if(r->colour){
                    OLEDcharRev(u,font2840);
                    OLEDcharRev(t,font2840);
                }else{
                    OLEDchar(u,font2840);
                    OLEDchar(t,font2840);                    
                }                
            }
            break;
        case DISP_PIPS:
            OLEDcol=r->x+PIPS_BORDER;
            OLEDpage=2;
            drawPips(getRandPip()[v],m);
            break;
        case DISP_COIN: //full bitmap, just need to clear area            
            v=v&1;  //make valid
            if(r->colour){v=v|2;}   //make into index for font
            OLEDcol=r->x;
            OLEDpage=1;
            OLEDchar(v,coinFont);            
            break;
        default: break;
    }
    
}

const char* rollName(rollDisplay_t r){   //return a char array with text describing r
    static char res[8]="";
    char i;
    for(i=0;i<8;i++){res[i]=0;}
    OLEDscanshort(r.roll);
    OLEDlzb(8);
    i=0;    //use as ptr
    switch(r.disp){
        case DISP_NUMBER:
        case DISP_PIPS:
            res[i++]=' ';
            if(r.roll<100){res[i++]=' ';}
            res[i++]='D';
            if(OLEDbuf[7]!=OLED_BLANK_CHAR){res[i++]=OLEDbuf[7];}
            if(OLEDbuf[8]!=OLED_BLANK_CHAR){res[i++]=OLEDbuf[8];}
            res[i++]=OLEDbuf[9];
            break;
        case DISP_CARD:
            res[0]=OLEDbuf[8];
            res[1]=OLEDbuf[9];
            res[2]=' ';
            res[3]='C';
            res[4]='A';
            res[5]='R';
            res[6]='D';
            break;
        case DISP_COIN:
            return coinString;
            break;
        case DISP_NULL:
            return notUsedString;
            break;
        default: break;     //returns "" in res
    }
    return res;
}