#include <SDL.h>
#include <SDL_gfxPrimitives.h>
#include <math.h>
#include <string.h>

/* Make the product of these two constants less than the screen height */
/* Only global variables for the sake of easy adjustment */
int squarecount = 20;
int squaresize = 40;

/* Timer function, pushes SDL_USEREVENT type events into the processing queue */
Uint32 timer(Uint32 ms, void *param) {
    SDL_Event ev;
    ev.type = SDL_USEREVENT;
    SDL_PushEvent(&ev);
    return ms;
}

int prime (int n) {
    if(n < 2) return 0;

    int i;
    double sqrtn = sqrt(n)+1; /* +1 to avoid rounding mistakes with floats */
    for(i = 2; i < sqrtn; i++)
        if(n % i == 0)
            return 0;
    return 1;
}

void print_numbers(SDL_Surface *screen, int i, int j) { /* For debug purposes only */
    int basenumber = j*squarecount*10 + i*10;

    char t1[5];
    char t3[5];
    char t7[5];
    char t9[5];
    sprintf(t1, "%d", basenumber + 1);
    sprintf(t3, "%d", basenumber + 3);
    sprintf(t7, "%d", basenumber + 7);
    sprintf(t9, "%d", basenumber + 9);
    stringRGBA(screen, i*squaresize, j*squaresize, t1, 0, 200, 255, 200);
    stringRGBA(screen, i*squaresize, (j+1)*squaresize-8, t3, 0, 200, 255, 200);
    stringRGBA(screen, (i+1)*squaresize-strlen(t7)*8, (j+1)*squaresize-8, t7, 0, 200, 255, 200);
    stringRGBA(screen, (i+1)*squaresize-strlen(t9)*8, j*squaresize, t9, 0, 200, 255, 200);
}

void Square_draw(SDL_Surface *screen, int i, int j) {
    int x = i*squaresize;
    int y = j*squaresize;
    boxRGBA(screen, x, y, x+squaresize, y+squaresize, 255, 255, 255, 255); /* Square border*/
    boxRGBA(screen, x+1, y+1, x+squaresize-1, y+squaresize-1, 10, 10, 10, 255); /* Square fill */

    int xc = i*squaresize+squaresize/2;
    int yc = j*squaresize+squaresize/2;

    int basenumber = j*squarecount*10 + i*10;
    if(prime(basenumber+1)) thickLineRGBA(screen, xc, yc, xc-squaresize/2, yc-squaresize/2, 1, 255, 255, 255, 255);
    if(prime(basenumber+3)) thickLineRGBA(screen, xc, yc, xc-squaresize/2, yc+squaresize/2, 1, 255, 255, 255, 255);
    if(prime(basenumber+7)) thickLineRGBA(screen, xc, yc, xc+squaresize/2, yc+squaresize/2, 1, 255, 255, 255, 255);
    if(prime(basenumber+9)) thickLineRGBA(screen, xc, yc, xc+squaresize/2, yc-squaresize/2, 1, 255, 255, 255, 255);

    //print_numbers(screen, i, j); /** Uncomment this line to display the numbers associated with the corners */
    SDL_Flip(screen);
}

int main(int argc, char *argv[]) {
    SDL_Event ev;
    SDL_Surface *screen;
    SDL_TimerID id;

    /* Loop variables */
    int i, j;

    /* Screen size variables */
    int WIDTH = squarecount*squaresize+1; /* +1 for right border to look right */
    int HEIGHT = squarecount*squaresize+10;

    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
    screen=SDL_SetVideoMode(WIDTH, HEIGHT, 0, SDL_ANYFORMAT);
    if (!screen) {
        fprintf(stderr, "Error while opening the SDL window!\n");
        exit(1);
    }
    SDL_WM_SetCaption("Prime table", "Prime table");

    char textdisplay[100];
    sprintf(textdisplay, "PRESS THE RETURN KEY TO START");
    stringRGBA(screen, WIDTH/2-strlen(textdisplay)/2*8, HEIGHT/2, textdisplay, 255, 255, 255, 255);
    SDL_Flip(screen);

    /* Waits for user input before the program starts running (for adjusting window position) */
    while (SDL_WaitEvent(&ev) && (ev.type!=SDL_KEYDOWN || ev.key.keysym.sym != SDLK_RETURN)) { /* ENTER breaks loop */
    }

    boxRGBA(screen, 0, 0, WIDTH, HEIGHT, 0, 0, 0, 255); /* Clear screen */
    sprintf(textdisplay, "GRAPHING ALL PRIMES FROM 0 TO %d...", squarecount*squarecount*2);
    stringRGBA(screen, WIDTH/2-strlen(textdisplay)/2*8, HEIGHT-8, textdisplay, 255, 255, 255, 255); /* Update progress text, move to bottom of the screen */

    id = SDL_AddTimer(50, timer, NULL); /* Start generating events */

    for(j = 0; j < squarecount; j++)
        for(i = 0; i < squarecount; i++) {
            //while(SDL_WaitEvent(&ev) && ev.type != SDL_USEREVENT){} /* Waits for next timer event, uncomment to enable timer */
            Square_draw(screen, i, j);                  /* Draws square! */
        }

    boxRGBA(screen, 0, HEIGHT-9, WIDTH, HEIGHT, 0, 0, 0, 255); /* Clear text */
    sprintf(textdisplay, "DONE! GRAPHED ALL PRIME NUMBERS FROM 0 TO %d.", squarecount*squarecount*2);
    stringRGBA(screen, WIDTH/2-strlen(textdisplay)/2*8, HEIGHT-8, textdisplay, 255, 255, 255, 255); /* Update progress text, move to bottom of the screen */
    SDL_Flip(screen);

    while (SDL_WaitEvent(&ev) && ev.type!=SDL_QUIT) {

    }

    SDL_RemoveTimer(id);
    SDL_Quit();

    return 0;
}
