/* event.c
 *
 * Event Handler
 *
 * notes: It would be useful to create a following function
 *        register_signal(SDL_HOLDDOWN, EVENT_ACTION_INCR, float *p, float val)
 *
 *        struct platform is still passed globally
 *
 */

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "client.h"
#include "glframe.h"
#include "platform.h"
#include "window.h"
#include "event.h"

extern int program_running;
static struct platform *p;

/* our function table */
static struct event_vtbl event_tbl;

int event_handler_init(struct platform *plat, struct event_vtbl *tbl)
{
    if (!tbl || !plat)
        return -1;

    p = plat;
    event_tbl = *tbl;

    /* predefined handlers that are automatically provided */
    if (!event_tbl.windowresize)
        event_tbl.windowresize = window_resize;

    return 0;
}

/* process SDL events */
void sdl_process_events(void)
{
    SDL_Event event;
    SDLKey sym;
    static unsigned int keys_held[323];

    /* helper flag for event_keydown() */
    int flag = 0;

    while (SDL_PollEvent(&event))
    {
        sym = event.key.keysym.sym;

        switch (event.type)
        {
            /* keyboard event */
            case SDL_KEYUP:
            {
                /* reset the key to 0 */
                keys_held[sym] = 0;
                break;
            }
            case SDL_KEYDOWN:
            {
                keys_held[sym] = 1;
                if (event_tbl.keydown)
                    event_tbl.keydown(&event.key.keysym, keys_held, flag);
                break;
            }
            case SDL_VIDEORESIZE:
            {
                if (event_tbl.windowresize)
                    event_tbl.windowresize(event.resize.w, event.resize.h);
                break;
            }
            case SDL_QUIT:
            {
                program_running = 0;
                break;
            }
            default:
                break;
        }
    }

    /* below code has to be placed here, check for keys that are being constantly held */
    if (keys_held[SDLK_w] || keys_held[SDLK_s] || keys_held[SDLK_a] || keys_held[SDLK_d] ||
        keys_held[SDLK_UP] || keys_held[SDLK_DOWN] || keys_held[SDLK_LEFT] || keys_held[SDLK_RIGHT] ||
        keys_held[SDLK_n] || keys_held[SDLK_m])
    {
        flag = !flag;
        event_keydown(NULL, keys_held, flag);
    }
    else
        flag = !flag;
}

/* here are the event handler functions */
void event_keydown(SDL_keysym *keysym, const unsigned int *keys_held, const int flag)
{
    if (!flag)
    {
        switch (keysym->sym)
        {
        case SDLK_ESCAPE: program_running = 0; break;
        case SDLK_w: p->c->xrot -= 5.0f; break;
        case SDLK_s: p->c->xrot += 5.0f; break;
        case SDLK_a: p->c->yrot -= 5.0f; break;
        case SDLK_d: p->c->yrot += 5.0f; break;
        case SDLK_UP: glframe_move_forward(&p->camera, 0.5f); break;
        case SDLK_DOWN: glframe_move_forward(&p->camera, -0.5f); break;
        case SDLK_LEFT: glframe_rotate_local_y(&p->camera, 0.1f); break;
        case SDLK_RIGHT: glframe_rotate_local_y(&p->camera, -0.1f); break;
        case SDLK_n: glframe_rotate_local_x(&p->camera, 0.1f); break;
        case SDLK_m: glframe_rotate_local_x(&p->camera, -0.1f); break;
        default: break;
        }
    }
    else
    {
        if (keys_held[SDLK_w])
            p->c->xrot -= 5.0f;
        if (keys_held[SDLK_s])
            p->c->xrot += 5.0f;
        if (keys_held[SDLK_a])
            p->c->yrot -= 5.0f;
        if (keys_held[SDLK_d])
            p->c->yrot += 5.0f;

        if (keys_held[SDLK_UP])
            glframe_move_forward(&p->camera, 0.05f);
        if (keys_held[SDLK_DOWN])
            glframe_move_forward(&p->camera, -0.05f);
        if (keys_held[SDLK_LEFT])
            glframe_rotate_local_y(&p->camera, 0.02f);
        if (keys_held[SDLK_RIGHT])
            glframe_rotate_local_y(&p->camera, -0.02f);

        if (keys_held[SDLK_n])
            glframe_rotate_local_x(&p->camera, 0.02f);
        if (keys_held[SDLK_m])
            glframe_rotate_local_x(&p->camera, -0.02f);
    }

    p->c->xrot = (GLfloat) ((const int) p->c->xrot % 360);
    p->c->yrot = (GLfloat) ((const int) p->c->yrot % 360);
}