#include <SDL.h>
#include <SDL_gfxPrimitives.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *freethis;

typedef struct {
    short r, g, b;
} Colour;

int Colour_cmp(Colour x, Colour y) {
    return (x.r == y.r &&
            x.g == y.g &&
            x.b == y.b);
}

void Colour_set(Colour *x, Colour y) {
    x->r = y.r;
    x->g = y.g;
    x->b = y.b;
}

typedef struct {
    int x, y;
    Colour c;
} Toolbaritem;

Toolbaritem Toolbaritem_create(int i, int j, Colour c, int menustrip, int WIDTH) {
    Toolbaritem t;
    t.x = i*menustrip;
    t.y = 0;
    t.c = c;
    return t;
}

/** Doesn't call SDL_Flip! */
void Toolbaritem_draw(SDL_Surface *screen, Toolbaritem t, int menustrip, Colour mousecolour) {
    int margin = Colour_cmp(t.c, mousecolour) ? 10 : 5;
    boxRGBA(screen, t.x, t.y, t.x+menustrip, t.y+menustrip, 50, 50, 50, 255);
    boxRGBA(screen, t.x+margin, t.y+margin, t.x+menustrip-margin, t.y+menustrip-margin, t.c.r, t.c.g, t.c.b, 255);
}

/** Doesn't call SDL_Flip! */
void Toolbar_draw(SDL_Surface *screen, int colourcount, Toolbaritem toolbar[colourcount], int menustrip, Colour mousecolour) {
    int i;
    for (i = 0; i < colourcount; i++)
        Toolbaritem_draw(screen, toolbar[i], menustrip, mousecolour);
}

typedef struct {
    int x, y;
    Colour c;
} Square;

/** Doesn't call SDL_Flip! */
void Square_draw(SDL_Surface *screen, Square s, int squaresize) {
    int margin = 1;
    boxRGBA(screen, s.x+margin, s.y+margin, s.x+squaresize-margin, s.y+squaresize-margin, s.c.r, s.c.g, s.c.b, 255);
}

/** Doesn't call SDL_Flip! */
void Squares_draw(SDL_Surface *screen, int squarecount, Square squares[squarecount][squarecount], int squaresize) {
    int i, j;
    for (i = 0; i < squarecount; i++)
        for (j = 0; j < squarecount; j++)
            Square_draw(screen, squares[i][j], squaresize);
}

/** Set default colour of squares here */
Square Square_create(int i, int j, int squaresize, int menustrip, Colour c) {
    Square s;
    s.x = i*squaresize;
    s.y = menustrip + j*squaresize;
    s.c = c;
    return s;
}

/** Warning: recursive. */
void Square_colour(SDL_Surface *screen, SDL_Event ev, int const i, int const j, int squarecount, Square squares[squarecount][squarecount], Colour bordercolour, Colour mousecolour) {
    if(Colour_cmp(bordercolour, squares[i][j].c) || Colour_cmp(mousecolour, squares[i][j].c)) {
        return;
    }

    squares[i][j].c.r = mousecolour.r;
    squares[i][j].c.g = mousecolour.g;
    squares[i][j].c.b = mousecolour.b;
    Squares_draw(screen, squarecount, squares, 20);
    SDL_Flip(screen);

    Square_colour(screen, ev, i-1, j, squarecount, squares, bordercolour, mousecolour);
    Square_colour(screen, ev, i+1, j, squarecount, squares, bordercolour, mousecolour);
    Square_colour(screen, ev, i, j-1, squarecount, squares, bordercolour, mousecolour);
    Square_colour(screen, ev, i, j+1, squarecount, squares, bordercolour, mousecolour);
}

char *exename(char *path) {
    int length = strlen(path);
    int i, namelength = 0;
    for (i = length; path[i-1] != '\\'; i--)
        namelength++;
    char *exe = malloc(namelength+1+4);
    int j = 0;
    for(i = length-namelength; path[i]!='.'; i++)
        exe[j++] = path[i];
    exe[j++] = '.';
    exe[j++] = 't';
    exe[j++] = 'x';
    exe[j++] = 't';
    exe[j++] = '\0';
    freethis = exe;
    return exe;
}

/** File operations here */
void File_read(int squarecount, Square squares[squarecount][squarecount], int colourcount, Colour *colours, Colour bordercolour, char *path) {
    FILE *fp = fopen(exename(path), "rt");
    int c;
    int i, j;

    for(i = 0; i < colourcount; i++) {
        fscanf(fp, "%hd,%hd,%hd", &colours[i].r, &colours[i].g, &colours[i].b);
        fgetc(fp);
    }

    while((c = fgetc(fp)) != '\n') {}

    i = 1, j = 1;
    while((c = fgetc(fp)) != EOF) {
        if(i == squarecount) c = '\n';
        if(j == squarecount) break;
        switch(c) {
            case '1': case '2': case '3': case '4': case '5':
            case '6': case '7': case '8': case '9': case '0':
                /* Empty */
            break;
            case '\n':
                i = 1;
                j++;
            break;
            case ' ':
                i++;
            break;
            case 'x':
                squares[i][j].c = bordercolour;
                i++;
            break;
            default:
                printf("WHAT?\n");
            break;
        }
    }
    fclose(fp);
}

int mouse_detect(int x, int y, int menustrip, int squaresize, int WIDTH, int HEIGHT, int *i, int *j) {
    if(y <= menustrip) {
        *i = x/menustrip;
        *j = y/menustrip;
        return 0;
    }

    printf("%d, %d", x, y);
    *i = x / squaresize;
    *j = (y-menustrip) / squaresize;
    return 1;
}

Uint32 timer(Uint32 ms, void *param) {
    SDL_Event ev;
    ev.type = SDL_USEREVENT;
    SDL_PushEvent(&ev);
    return ms;
}

int main(int argc, char *argv[]) {
    int i, j;

    int WIDTH = 800;
    int menustrip = 100;
    int HEIGHT = WIDTH+menustrip;
    int squaresize = 20;
    int squarecount = (HEIGHT-menustrip)/squaresize;

    Colour defaultcolour = {200, 200, 200};
    Colour bordercolour = {20, 20, 20};
    Colour mousecolour;

    int colourcount = 8;
    Toolbaritem toolbar[colourcount];
    Colour colours[colourcount];
    SDL_Event ev;
    SDL_Surface *screen;
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
    screen=SDL_SetVideoMode(WIDTH, HEIGHT, 0, SDL_ANYFORMAT);
    if (!screen) {
        fprintf(stderr, "OMG NO WINDOW\n");
        exit(1);
    }
    SDL_WM_SetCaption("Colouring thing", "Colouring thing");

    Square squares[squarecount][squarecount];
    for (i = 0; i < squarecount; i++)
        for (j = 0; j < squarecount; j++)
            squares[i][j] = Square_create(i, j, squaresize, menustrip, defaultcolour);

    for(i = 0; i < squarecount; i++)
        squares[i][0] = Square_create(i, 0, squaresize, menustrip, bordercolour);
    for(i = 0; i < squarecount; i++)
        squares[i][squarecount-1] = Square_create(i, squarecount-1, squaresize, menustrip, bordercolour);

    for(j = 0; j < squarecount; j++)
        squares[0][j] = Square_create(0, j, squaresize, menustrip, bordercolour);
    for(j = 0; j < squarecount; j++)
        squares[squarecount-1][j] = Square_create(squarecount-1, j, squaresize, menustrip, bordercolour);

    File_read(squarecount, squares, colourcount, colours, bordercolour, argv[0]);

    for (i = 0; i < colourcount; i++)
        toolbar[i] = Toolbaritem_create(i, 0, colours[i], menustrip, WIDTH);
    mousecolour = toolbar[0].c;

    Toolbar_draw(screen, colourcount, toolbar, menustrip, mousecolour);
    Squares_draw(screen, squarecount, squares, squaresize);
    SDL_Flip(screen);

    short quit = 0;
    while (SDL_WaitEvent(&ev) && !quit) {
        switch(ev.type) {
            case SDL_KEYDOWN:
                switch(ev.key.keysym.sym) {
                    case SDLK_ESCAPE:
                        quit = 1;
                    break;
                    default:
                    break;
                }
            break;
            case SDL_MOUSEBUTTONDOWN:
                if(mouse_detect(ev.button.x, ev.button.y, menustrip, squaresize, WIDTH, HEIGHT, &i, &j)) {
                    Square_colour(screen, ev, i, j, squarecount, squares, bordercolour, mousecolour);
                }
                else {
                    mousecolour = toolbar[i].c;
                    Toolbar_draw(screen, colourcount, toolbar, menustrip, mousecolour);
                    SDL_Flip(screen);
                }
            break;
            case SDL_QUIT:
                quit = 1;
            break;
            default: break;
        }
    }

    SDL_Quit();
    free(freethis);
    return 0;
}
