#include "includes.h"
#include "dsfont.h"
#include "main.h"
#include "graphics.h"

extern SDL_Surface *screen;
extern Uint32 col[256];

extern SDL_MouseMotionEvent mousepos;
extern Sint8 mouse[3];

extern int screenx, screeny, fullscreen;

static void plot_circle(int x, int y, int x_center, int y_center, Uint32 c);

void init_sdl(void) {
    int x, y, z, n;

    if(SDL_Init(SDL_INIT_VIDEO) == -1)
        fatal_error("Can't init SDL");

    init_graphics(0, 0);

    for(x = n = 0; x < 256; x += 51) {
        for(y = 0; y < 256; y += 51) {
            for(z = 0; z < 256; z += 51) {
                col[n++] = SDL_MapRGB(screen->format, x, y, z);
            }
        }
    }
}

void init_graphics(int xsize, int ysize) {
    if(xsize || ysize) screen = SDL_SetVideoMode(xsize, ysize, 8, SDL_SWSURFACE
        | (fullscreen ? SDL_FULLSCREEN : 0));
    else screen = SDL_SetVideoMode(320, 200, 8, SDL_SWSURFACE);

    if(screen == NULL) fatal_error("Can't init graphics mode");

    SDL_WM_SetCaption("Sail the Seas by DWK", NULL);
}

void start_frame(void) {
    if(SDL_LockSurface(screen) < 0) {
        fatal_error("Can't lock screen");
    }

    SDL_FillRect(screen, NULL, col[COL_BLACK]);
}

void paint_button(SDL_Surface *f, const char *s, int size, int xp, int yp) {
    int x, y;
    int n = in_button(xp, yp, size, f->h/10+12) && mouse[0];  /* if clicking */
    int hov = in_button(xp, yp, size, f->h/10+12);  /* if hovering */
    SDL_Rect rect;

    for(x = 0; x < size-4; x ++) {
        wp(xp+x+2, yp, col[n?1:15]);
        wp(xp+x+2, yp+11+f->h/10, col[n?15:1]);

        wp(xp+x+2, yp+1, col[n?3:11]);
        wp(xp+x+2, yp+10+f->h/10, col[n?11:3]);
    }

    for(y = 0; y < f->h/10+8; y ++) {
        wp(xp, yp+y+2, col[n?1:15]);
        wp(xp+size-1, yp+y+2, col[n?15:1]);

        wp(xp+1, yp+y+2, col[n?3:11]);
        wp(xp+size-2, yp+y+2, col[n?11:3]);
    }

    wp(xp+1, yp+1, col[n?1:15]), wp(xp+1, yp+(f->h/10)+10, col[n?15:1]);

    wp(xp+size-2, yp+1, col[n?1:15]);
    wp(xp+size-2, yp+(f->h/10)+10, col[n?15:1]);

    /* colour 5 */
    rect.x = xp+2, rect.y = yp+2, rect.w = size-4, rect.h = 8+f->h/10;
    SDL_FillRect(screen, &rect, col[5]);

    dsfont(f, s, xp+ (size-strlen(s)*(f->w/10))/2 +n, yp+6+n,
        col[hov?71:66]);
}

int in_button(int x, int y, int w, int h) {
    return (mousepos.x >= x && mousepos.y >= y
        && mousepos.x <= x+w
        && mousepos.y <= y+h);
}

void wp(int x, int y, Uint32 pixel) {
    int bpp = screen->format->BytesPerPixel;
    Uint8 *p = (Uint8 *)screen->pixels + y * screen->pitch + x * bpp;

    if(x < 0 || y < 0 || x >= screenx || y >= screeny) return;

    switch(bpp) {
    case 1: *p = pixel; break;
    case 2: *(Uint16 *)p = pixel; break;
    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        }
        else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4: *(Uint32 *)p = pixel; break;
    }
}

Uint32 gp(SDL_Surface *surface, int x, int y) {
    int bpp = surface->format->BytesPerPixel;
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    if(x < 0 || y < 0 || x >= surface->w || y >= surface->h) return 0;

    switch(bpp) {
    case 1: return *p; break;
    case 2: return *(Uint16 *)p; break;
    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;
        break;
    case 4: return *(Uint32 *)p; break;
    }

    return 0;
}

void line(int startx, int starty, int endx, int endy, Uint32 color) {
    int t, distance;
    int xerr = 0, yerr = 0, delta_x, delta_y;
    int incx, incy;

    /* compute the distances in both directions */
    delta_x = endx-startx;
    delta_y = endy-starty;

    /* Compute the direction of the increment,
       an increment of 0 means either a horizontal or vertical
       line.
    */
    if(delta_x > 0) incx = 1;
    else if(!delta_x) incx = 0;
    else incx = -1;

    if(delta_y > 0) incy = 1;
    else if(!delta_y) incy = 0;
    else incy = -1;

    /* determine which distance is greater */
    delta_x = abs(delta_x);
    delta_y = abs(delta_y);
    if(delta_x > delta_y) distance = delta_x;
    else distance = delta_y;

    /* draw the line */
    for(t = 0; t <= distance+1; t++) {
        wp(startx, starty, col[color]);
        
        xerr += delta_x;
        yerr += delta_y;
        if(xerr > distance) {
            xerr -= distance;
            startx += incx;
        }
        if(yerr > distance) {
            yerr -= distance;
            starty += incy;
        }
    }
}

void circle(int x_center, int y_center, int radius, Uint32 c) {
    int x, y = radius, delta = 3 - 2*radius;

    for(x = 0; x < y; x ++) {
        plot_circle(x, y, x_center, y_center, c);

        if(delta < 0) {
            delta += 4*x + 6;
        }
        else {
            delta += 4*(x-y) + 10;
            y--;
        }
    }

    x = y;
    if(y) plot_circle(x, y, x_center, y_center, c);
}

static void plot_circle(int x, int y, int x_center, int y_center, Uint32 c) {
    int startx = x, endx = x+1, x1, starty = y, endy = y+1, y1;

    for(x1 = startx; x1 < endx; x1 ++) {
        wp(x1+x_center, y+y_center, c);
        wp(x1+x_center, y_center-y, c);
        wp(x_center-x1, y_center-y, c);
        wp(x_center-x1, y+y_center, c);
    }

    for(y1 = starty; y1 < endy; y1 ++) {
        wp(y1+x_center, x+y_center, c);
        wp(y1+x_center, y_center-x, c);
        wp(x_center-y1, y_center-x, c);
        wp(x_center-y1, x+y_center, c);
    }
}

