#include <client_api.h>
#include "parse.h"

pbm_t* player;
pbm_t* player_out;

typedef struct
{
    char* tile;
    pbm_t* pbm;
} bg_t;

bg_t bg[100];
int num_bg = 0;

int grid[10][9];

#define OUTLINE 2

bool load_level(fname);
void unload_bg();

int setup(int a)
{
    player = f_bitmap("/player.pbm");
    player_out = d_expand_bitmap(player, OUTLINE, true, true);

    if (!load_level("/level.txt"))
    {
        return 1;
    }

    return 0;
}

char* last_level = NULL;
void unload_bg()
{
    for (int i = 0; i < num_bg; i++)
    {
        free(bg[i].pbm);
    }
    num_bg = 0;

    if (last_level)
    {
        free(last_level);
        last_level = NULL;
    }
}



bool is_space(char c) { return isspace(c); }
bool is_comma_or_space(char c) { return c == ',' || is_space(c); }

bool load_level(char* fname)
{
    unload_bg();
    memset(grid, 0, sizeof(grid));

    size_t len;
    last_level = (char*)f_contents(fname, &len);
    if (!last_level)
    {
        printf("Couldn't find level: %s\n", fname);
        return false;
    }

    reset_parse = true;

    char* tile_def[] = { NULL, NULL };

    while (true)
    {
        int res = parse(last_level, len, is_space, false);
        //printf("Parse res: %d\n", res);

        if (res == DONE)
        {
            printf("No tile grid given in level %s\n", fname);
            return false;
        }

        if (res == NL)
        {
            if (tile_def[0] == NULL || tile_def[1] == NULL)
            {
                printf("Invalid tile def on line %d\n", parse_line - 1);
                return false;
            }


            bool found = false;
            char f[100];
            sprintf(f, "/%s.pbm", tile_def[1]);
            pbm_t* n = f_bitmap(f);
            if (n)
            {
                found = true;

                bg_t b = { tile_def[0], n };
                bg[num_bg++] = b;

                printf("Tile %s registered as word %s\n", f, tile_def[0]);
            }
            else
            {
                int i = 1;
                sprintf(f, "/%s%d.pbm", tile_def[1], i);
                while (n = f_bitmap(f))
                {
                    found = true;

                    char name[10];
                    sprintf(name, "%s%d", tile_def[0], i);


                    bg_t b = { malloc(strlen(name) + 1), n }; 
                    strcpy(b.tile, name);
                    bg[num_bg++] = b;

                    printf("Tile %s registered as word %s\n", f, name);

                    i++;
                    sprintf(f, "/%s%d.pbm", tile_def[1], i);
                }
            }

            if (!found)
            {
                printf("Not found: graphic with name %s\n", tile_def[1]);
            }

            tile_def[0] = tile_def[1] = NULL;
            continue;
        }

        if (res == BREAK) break;

        if (tile_def[0] == NULL)
        {
            tile_def[0] = parse_word;
        }
        else if (tile_def[1] == NULL)
        {
            tile_def[1] = parse_word;
        }
        else
        {
            printf("Too many words on line %d\n", parse_line);
        }
    }

    int x = 0;
    int y = 0;
    while (true)
    {
        int res = parse(last_level, len, is_comma_or_space, false);
        //printf("Parse res: %d\n", res);
        if (res == DONE || res == BREAK)
        {
            if (y < 9)
            {
                printf("Didn't read full grid, only %d,%d\n", x, y);
                return false;
            }
            break;
        }
        if (res == NL)
        {
            if (x < 10)
            {
                printf("Couldn't read full row, only to index %d on line %d\n", x - 1, parse_line);
                return false;
            }
            x = 0;
            y++;
        }
        if (res == WORD)
        {
            if (x >= 10 || y >= 9)
            {
                printf("Grid is too big, reached %d,%d on line %d\n", x, y, parse_line);
                return false;
            }
            size_t l = strlen(parse_word);
            char* prob = NULL;
            for (int i = 0; i < l; i++)
            {
                if (parse_word[i] == '.')
                {
                    parse_word[i] = 0;
                    prob = parse_word + (i + 1);
                    break;
                }
            }

            //printf("Searching %s\n", parse_word);
            for (int i = 0; i < num_bg; i++)
            {
                //printf("  Check %s\n", bg[i].tile);
                if (strcmp(bg[i].tile, parse_word) == 0)
                {
                    if (prob)
                    {
                        int p = max(0, min(9, atoi(prob)));
                        if (random(1, 10) > p) continue;
                    }
                    //printf("Tile %d on %d,%d\n", i, x, y);
                    grid[x][y] = i + 1;
                }
            }

            x++;

        }
    }


    return 0;
}

float x = 0;
float y = 0;
int rot = 0;

float speed = 80;

bool flipX = false, flipY = false;

void d_pbm_outline(int16_t x, int16_t y, pbm_t* pbm)
{
    for (int i = x - 1; i <= x + 1; i++)
    {
        for (int j = y - 1; j <= y + 1; j++)
        {
            d_pbm(i, j, pbm, 0, 0, 0, 0, WHITE, TRANSPARENT, R_NONE, false, false);
        }
    }
}


int loop(int ms)
{
    d_clear();

    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            if (grid[i][j] != 0)
            {
                d_pbm(4 + i * 16, j * 16, bg[grid[i][j] - 1].pbm, 0,0,0,0, BLACK, TRANSPARENT, R_NONE, false, false);
            }
        }
    }

    //d_fillRect(0, 0, SCREEN_W, SCREEN_H, BLACK);


    d_pbm((uint16_t)roundf(x) - OUTLINE, (uint16_t)roundf(y) - OUTLINE, player_out, 0, 0, 0, 0, WHITE, TRANSPARENT, rot, flipX, flipY);
    d_pbm((uint16_t)roundf(x), (uint16_t)roundf(y), player, 0, 0, 0, 0, BLACK, TRANSPARENT, rot, flipX, flipY);

    if (button_pressed(BUTTON_A))
    {
        rot = (rot + 1) % 4;
    }
    if (button_pressed(BUTTON_B))
    {
        flipX = !flipX;
        if (!flipX)
        {
            flipY = !flipY;
        }
        printf("Flip: %d %d\n", flipX, flipY);
    }

    float t = ms / 1000.0f;
    if (button_down(DPAD_RIGHT)) x += t * speed;
    if (button_down(DPAD_LEFT)) x -= t * speed;
    if (button_down(DPAD_DOWN)) y += t * speed;
    if (button_down(DPAD_UP)) y -= t * speed;
    return 0;
}
