/*
 *  accelerometer.c
 *  written by Holmes Futrell
 *  use however you want
 */

#include "SDL.h"
#include "math.h"
#include "common.h"

#define DAMPING 0.5f;           /* after bouncing off a wall, damping coefficient determines final speed */
#define FRICTION 0.0008f        /* coefficient of acceleration that opposes direction of motion */
#define GRAVITY_CONSTANT 0.004f /* how sensitive the ship is to the accelerometer */

/*  If we aren't on an iPhone, then this definition ought to yield reasonable behavior */
#ifndef SDL_IPHONE_MAX_GFORCE
#define SDL_IPHONE_MAX_GFORCE 5.0f
#endif

static SDL_Joystick *accelerometer;     /* used for controlling the ship */

static struct
{
    float x, y;                 /* position of ship */
    float vx, vy;               /* velocity of ship (in pixels per millesecond) */
    SDL_Rect rect;              /* (drawn) position and size of ship */
} shipData;

static SDL_Texture *ship = 0;        /* texture for spaceship */
static SDL_Texture *space = 0;       /* texture for space (background */

void
render(SDL_Renderer *renderer, int w, int h, double deltaTime)
{
    double deltaMilliseconds = deltaTime * 1000;
    float speed;

    /* get joystick (accelerometer) axis values and normalize them */
    float ax = SDL_JoystickGetAxis(accelerometer, 0);
    float ay = SDL_JoystickGetAxis(accelerometer, 1);

    /* ship screen constraints */
    Uint32 minx = 0.0f;
    Uint32 maxx = w - shipData.rect.w;
    Uint32 miny = 0.0f;
    Uint32 maxy = h - shipData.rect.h;

#define SINT16_MAX ((float)(0x7FFF))

    /* update velocity from accelerometer
       the factor SDL_IPHONE_MAX_G_FORCE / SINT16_MAX converts between
       SDL's units reported from the joytick, and units of g-force, as reported by the accelerometer
     */
    shipData.vx +=
        ax * SDL_IPHONE_MAX_GFORCE / SINT16_MAX * GRAVITY_CONSTANT *
        deltaMilliseconds;
    shipData.vy +=
        ay * SDL_IPHONE_MAX_GFORCE / SINT16_MAX * GRAVITY_CONSTANT *
        deltaMilliseconds;

    speed = sqrt(shipData.vx * shipData.vx + shipData.vy * shipData.vy);

    if (speed > 0) {
        /* compensate for friction */
        float dirx = shipData.vx / speed;   /* normalized x velocity */
        float diry = shipData.vy / speed;   /* normalized y velocity */

        /* update velocity due to friction */
        if (speed - FRICTION * deltaMilliseconds > 0) {
            /* apply friction */
            shipData.vx -= dirx * FRICTION * deltaMilliseconds;
            shipData.vy -= diry * FRICTION * deltaMilliseconds;
        } else {
            /* applying friction would MORE than stop the ship, so just stop the ship */
            shipData.vx = 0.0f;
            shipData.vy = 0.0f;
        }
    }

    /* update ship location */
    shipData.x += shipData.vx * deltaMilliseconds;
    shipData.y += shipData.vy * deltaMilliseconds;

    if (shipData.x > maxx) {
        shipData.x = maxx;
        shipData.vx = -shipData.vx * DAMPING;
    } else if (shipData.x < minx) {
        shipData.x = minx;
        shipData.vx = -shipData.vx * DAMPING;
    }
    if (shipData.y > maxy) {
        shipData.y = maxy;
        shipData.vy = -shipData.vy * DAMPING;
    } else if (shipData.y < miny) {
        shipData.y = miny;
        shipData.vy = -shipData.vy * DAMPING;
    }

    /* draw the background */
    SDL_RenderCopy(renderer, space, NULL, NULL);

    /* draw the ship */
    shipData.rect.x = shipData.x;
    shipData.rect.y = shipData.y;

    SDL_RenderCopy(renderer, ship, NULL, &shipData.rect);

    /* update screen */
    SDL_RenderPresent(renderer);

}

void
initializeTextures(SDL_Renderer *renderer)
{

    SDL_Surface *bmp_surface;

    /* load the ship */
    bmp_surface = SDL_LoadBMP("ship.bmp");
    if (bmp_surface == NULL) {
        fatalError("could not ship.bmp");
    }
    /* set blue to transparent on the ship */
    SDL_SetColorKey(bmp_surface, 1,
                    SDL_MapRGB(bmp_surface->format, 0, 0, 255));

    /* create ship texture from surface */
    ship = SDL_CreateTextureFromSurface(renderer, bmp_surface);
    if (ship == 0) {
        fatalError("could not create ship texture");
    }
    SDL_SetTextureBlendMode(ship, SDL_BLENDMODE_BLEND);

    /* set the width and height of the ship from the surface dimensions */
    shipData.rect.w = bmp_surface->w;
    shipData.rect.h = bmp_surface->h;

    SDL_FreeSurface(bmp_surface);

    /* load the space background */
    bmp_surface = SDL_LoadBMP("space.bmp");
    if (bmp_surface == NULL) {
        fatalError("could not load space.bmp");
    }
    /* create space texture from surface */
    space = SDL_CreateTextureFromSurface(renderer, bmp_surface);
    if (space == 0) {
        fatalError("could not create space texture");
    }
    SDL_FreeSurface(bmp_surface);

}



int
main(int argc, char *argv[])
{

    SDL_Window *window;         /* main window */
    SDL_Renderer *renderer;
    int done;                   /* should we clean up and exit? */
    int w, h;

    /* initialize SDL */
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
        fatalError("Could not initialize SDL");
    }

    /* create main window and renderer */
    window = SDL_CreateWindow(NULL, 0, 0, 320, 480, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_ALLOW_HIGHDPI);
    renderer = SDL_CreateRenderer(window, 0, 0);
    
    SDL_GetWindowSize(window, &w, &h);
    SDL_RenderSetLogicalSize(renderer, w, h);

    /* print out some info about joysticks and try to open accelerometer for use */
    printf("There are %d joysticks available\n", SDL_NumJoysticks());
    printf("Default joystick (index 0) is %s\n", SDL_JoystickName(0));
    accelerometer = SDL_JoystickOpen(0);
    if (accelerometer == NULL) {
        fatalError("Could not open joystick (accelerometer)");
    }
    printf("joystick number of axis = %d\n",
           SDL_JoystickNumAxes(accelerometer));
    printf("joystick number of hats = %d\n",
           SDL_JoystickNumHats(accelerometer));
    printf("joystick number of balls = %d\n",
           SDL_JoystickNumBalls(accelerometer));
    printf("joystick number of buttons = %d\n",
           SDL_JoystickNumButtons(accelerometer));

    /* load graphics */
    initializeTextures(renderer);

    /* setup ship */
    shipData.x = (w - shipData.rect.w) / 2;
    shipData.y = (h - shipData.rect.h) / 2;
    shipData.vx = 0.0f;
    shipData.vy = 0.0f;

    done = 0;
    /* enter main loop */
    while (!done) {
        double deltaTime = updateDeltaTime();
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                done = 1;
            }
        }
        render(renderer, w, h, deltaTime);
        SDL_Delay(1);
    }

    /* delete textures */
    SDL_DestroyTexture(ship);
    SDL_DestroyTexture(space);

    /* shutdown SDL */
    SDL_Quit();

    return 0;

}
