#include "../spec.h"

Color Palette(Let ch){
    switch(ch)
    {
        case '$': //#00FF00
        case 'g':
            return TG;
            break;
        case '+': //#0000FF
        case 'b':
            return TB;
            break;
        case '#': //#FF0000
        case '-': //#7F0000
        case 'r':
            return TR;
            break;
        case '%': //#FF00FF
        case '*': //#7F007F
        case 'p':
            return TP;
            break;
        case '=': //#00007F
        case 'c':
            return TC;
            break;
        case '&': //#FFFF00
        case 'y':
            return TY;
            break;
        case '>': //#7F7F7F
        case 'k':
            return TK;
            break;
        case '@': //#CCCCCC
        case ';': //#FFFFFF
        case 'w':
            return TW;
            break;
    }       
    return T;
}

Spr SNew()
{
    Spr spr;
    Let i = 0;
    for (i=0;i<Sprites;i++)
    {
        spr.rs[i] = 0;
        //spr.ts[i] = 0;
        spr.xs[i] = 0;
        spr.ys[i] = 0;
    }
    spr.ss = SSBegin;
    spr.map = 0;
    spr.x = 0;
    spr.y = 0;
    spr.w = 0;
    spr.h = 0;
    return spr;
}
void BgSPlot(Co,Cnt,Cnt);
void SMove(Co co, Let spr, Cnt col, Cnt row){
    Cnt ox = co->spr.xs[spr];
    Cnt oy = co->spr.ys[spr];
    co->spr.xs[spr] = col;
    co->spr.ys[spr] = row;
    //if sprite moved from last position, restore the background
    if (col != ox || row != oy)
    BgSPlot(co,ox,oy);
}
Cnt SCol(Co co,Let id){
    return co->spr.xs[id];
}
Cnt SRow(Co co,Let id){
    return co->spr.ys[id];
}

Let SSReq(Co co)
{
    if (co->spr.ss > SSBegin)return 0;
    if (co->spr.ss < SSEnd)return 0;
    if (co->spr.ss == 0)return 0;

    co->spr.ss--;

    return co->spr.ss;
}

void SSFlush(Co co)
{
    //should only remove unclaimed
    for (Let s=SSEnd;s < co->spr.ss;s++)
    if (SCol(co,s) && SRow(co,s))
    SMove(co,s,0,0);
    //then we reset the counter
    co->spr.ss=SSBegin;
}
/*
Let Stm(Co co, Let id){
    return co->spr.ts[id];
}

void Stms(Co co, Let id, Let s)
{
    co->spr.ts[id] = s;
}

*/
void SprFocus(Co co, Let spr)
{
    Cnt x = SCol(co,spr);
    Cnt y = SRow(co,spr);

    if (co->spr.x > x+10)co->spr.x-=10;
    if (co->spr.x+60 < x-10) co->spr.x+=10;
    if (co->spr.y > y+5) co->spr.y-=10;
    if (co->spr.y+25 < y-5) co->spr.y+=5;
}

Let Bg(Co co, Cnt col, Cnt row){
    if (co->spr.map == 0)
    return ' ';

    if (co->spr.w < col)
    return '#';

    if (co->spr.h < row)
    return '#';

    return co->spr.map[row][col];
}



void SMap(Co co, Let ** map, Cnt w, Cnt h)
{
    co->spr.map = map;
    co->spr.x = 0;
    co->spr.y = 0;
    co->spr.w = w;
    co->spr.h = h;
}
/*run each routine once, if they emit a next, reset them */
void SActr(Co co)
{
    Routine tmp = co->routine;
    for (Let i=0;i<Sprites;i++)
    if (co->spr.rs[i] != 0)
    {
        co->routine = 0;
        co->spr.rs[i](co);

        if (co->routine != 0)
        co->spr.rs[i] = co->routine;
    }
    co->routine = tmp;
}

void SNext(Co co, Let spr, Routine routine)
{
    if (routine == 0)
    return;

    co->spr.rs[spr] = routine;
}

/*
function that use function above
*/

void BgSPlot(Co co, Cnt col, Cnt row){
    /* dont draw over any sprites */
    for (Let i=0;i<Sprites;i++)
    if (SCol(co,i) == col)
    if (SRow(co,i) == row)
    if (SCol(co,i) != 0  && SRow(co,i) != 0)
    return;
    /*  */
    Let cs = Bg(co,col,row);
    Let ch = ' ';
    Let cl = Palette(cs);
    CuSPlot(co,ch,col,row,cl);
}

void ClrSpr(Co co){
    for (int i=0; i<Sprites; i++)
    SMove(co,i,0,0);
}
void Say(Co co,Let* msg,Let col,Let row,Color cl){
    CuSay(co,msg,col,row,cl);
}
Let Pressed(Co co, Let key){
    return Peek(co,key);
}

void SStamp(Co co, Let spr, Let ch, Color cl)
{
    Cnt x = SCol(co,spr);
    Cnt y = SRow(co,spr);

    if (x == 0)
    if (y == 0)
    return;

    if (cl == 0)
    return;

    /* avoid stacked sprite to overdraw static one */
    if (spr > SSEnd)
    for (Let i=0;i<SSEnd;i++)
    if(SCol(co,i)==x)
    if(SRow(co,i)==y)
    return;

    if (cl % Black == T)
    cl = cl + Palette(Bg(co,x,y));

    CuSPlot(co,ch,x,y,cl);
}

void SPlot(Co co,Let id, Let ch, Cnt x, Cnt y, Color cl){
    SMove(co,id,x,y);
    SStamp(co,id,ch,cl);
}

void SLvl(Co co, Let * MRKS, Let * FGRS){
    ClrSpr(co);
    for (Cnt row=0;row<co->spr.h;row++)
    for (Cnt col=0;col<co->spr.w;col++)
    for (Let i=0;MRKS[i]!=0 && FGRS[i]!=0;i++)
    if (Bg(co,col,row) == MRKS[i])
    SMove(co,FGRS[i],col,row);
}

Let SAt(Co co, Cnt col, Cnt row){
    Let cell = Bg(co,col,row);

    if (Palette(cell) == T)
    cell = ' ';

    return cell;
}

void SDrw(Co co, Let ** image){
    Cnt w,h,col,row;
    for (h=0; image[h] != 0; h++)
    for (w=0; image[h][w] != 0; w++){
    }

    CuResize(co,w,h);
    SMap(co,image,w,h);

    for (Cnt row=0;row < h;row++)
    for (Cnt col=0;col < w;col++)
    {
        BgSPlot(co,col,row);
    } 
}
   
void SXpmDrw(Co co,char ** xpm)
{
    /* XPM
    static char * exemple_xpm[] = {
    "24 20 3 1",
    "       c None",
    ".      c #3A32E4",
    "+      c #E43232",
    "                        ",
    "    ..                  ",
    "   ....                 ",
    "  ......++++++++        ",
    " .........+++++++       ",
    " ..........+++++++      ",
    " ............++++++     ",
    " .............++++++    ",
    "  ..............++++    ",
    "   +.............+++    ",
    "   ++.............++    ",
    "   +++.............+    ",
    "   +++++.............   ",
    "   ++++++.............. ",
    "   ++++++++............ ",
    "   +++++++++........... ",
    "    +++++++++.........  ",
    "     ++++++++++.......  ",
    "      ++++++++++.....   ",
    "       +++++++++ ...    "};
    */
    Cnt header [5] = { 0 };
    Cnt col = 0,w;
    Cnt row = 0,h;
    Let grid = 1;

    if (xpm == 0) return;
    if (xpm[0] == 0) return;

    /* parse header */
    Let s=0,i;
    for (i=0;xpm[0][i]!=0 && s < 5;i++)
    if (xpm[0][i]==' ')
    s++;
    else
    {
        if (xpm[0][i] >= '0')
        if (xpm[0][i] <= '9')
        header[s] = (header[s]*10) + (xpm[0][i]-'0');
    }
    w = header[0];
    h = header[1];
    grid += header[2];
    if (header[3] != 1) return; /* gtfo */
    if (xpm[grid] == 0) return;

    /* commit XD */
    SMap(co,&(xpm[grid]),w,h);
    CuResize(co,w,h);
    
    /* parse palette */

    /* parse grid */
    for (row=0;row < h && xpm[grid+row]!=0;row++)
    for (col=0;col < w && xpm[grid+row][col]!=0;col++)
    {
        BgSPlot(co,col,row);
    } 

}


/*

Let SSnake(Co co, Let spr,Let ch, Cnt col, Cnt row, Color cl, Let len)
{
    if (len == 0) return;
    if (spr == 0) return;
    if (col == 0) if (row == 0) return;
    if (col == SCol(co,spr)) if (row == SRow(co,spr)) return;

    Let nspr = SSReq(co);
    Cnt ox = SCol(co,spr);
    Cnt oy = SRow(co,spr);

    SMove(co,spr,col,row);
    SStamp(co,spr,ch,cl);

    return SSnake(co,nspr,ch,ox,oy,cl,len-1);
}*/

enum SprStmpEnum
{
    SprClr,
    SprChr,
    SprGrd
};
void SSPrnt(Co co, Cnt col, Cnt row, Let ** spr, Let rev)
{
    if (spr[SprGrd] == 0) return;
    int i=0,c,r;
    for (r=0;spr[SprGrd+r];r++)
    for (c=0;spr[SprGrd+r][c];c++)
    if(spr[SprGrd+r][c]=='!')
    if(rev)
    {
        col+=c;
        row-=r;
    }
    else
    {
        col-=c;
        row-=r;
    }

    for (r=0;spr[SprGrd+r];r++)
    for (c=0;spr[SprGrd+r][c];c++)
    if(spr[SprGrd+r][c]!='.')
    if(spr[SprGrd+r][c]!=' ')
    if(spr[SprGrd+r][c]!='!')
    {
        Let chr = spr[SprGrd+r][c];
        Let clr = spr[SprClr] ? spr[SprClr][i] : T;
        Let sym = SSReq(co);
        if (spr[SprChr] && spr[SprChr][i]!=' ') chr = spr[SprChr][i];
        if (rev)
        {
        /*cheap ass hack*/
        if (chr == '/') chr = '\\';
        else if(chr == '\\') chr = '/';
        SPlot(co,sym,chr, col-c, row+r, clr);
        }
        else
        SPlot(co,sym,chr, col+c, row+r, clr);
        i++;
    }
    else
    {
        i++;
    }
}

Let SLft(Co co, Let spr)
{
    return SAt(co,SCol(co,spr)-1,SRow(co,spr));
}

Let SRgt(Co co, Let spr)
{
    return SAt(co,SCol(co,spr)+1,SRow(co,spr));
}

Let SAbv(Co co, Let spr)
{
    return SAt(co,SCol(co,spr),SRow(co,spr)-1);
}

Let SBtm(Co co, Let spr)
{
    return SAt(co,SCol(co,spr),SRow(co,spr)+1);
}

void SGoLft(Co co, Let spr)
{
    Cnt x = SCol(co,spr);
    Cnt y = SRow(co,spr);
    SMove(co,spr,x-1,y);
}
void SGoRgt(Co co, Let spr)
{
    Cnt x = SCol(co,spr);
    Cnt y = SRow(co,spr);
    SMove(co,spr,x+1,y);
}
void SGoAbv(Co co, Let spr)
{
    Cnt x = SCol(co,spr);
    Cnt y = SRow(co,spr);
    SMove(co,spr,x,y-1);
}
void SGoBtm(Co co, Let spr)
{
    Cnt x = SCol(co,spr);
    Cnt y = SRow(co,spr);
    SMove(co,spr,x,y+1);
}



