
#include "SDL.h"
#include "PL_Loop.h"

namespace PL
{

void PL_Loop(PL_State* state, PL_Set& set)
{
    bool tempState = (state == NULL);
    if(tempState)
        state = new PL_State;
    
    state->set = &set;
    state->keystate = SDL_GetKeyState(NULL);
    state->lastTime = SDL_GetTicks();
    SDL_Event event;
    while(!state->done)
    {
        Uint32 startTime = SDL_GetTicks();
        state->dt = (startTime - state->lastTime)/1000.0f;
        state->lastTime = startTime;

        while(SDL_PollEvent(&event))
        {
            if(set.any != NULL)
            {
                if(!set.any->handleEvent(state, event))
                    continue;
            }
            else if(set.anyEventCallback != NULL)
            {
                if(!set.anyEventCallback(state, event))
                    continue;
            }
            
            switch(event.type)
            {
                case SDL_QUIT:
                    if(set.other != NULL)
                        set.other->quit(state);
                    else if(set.quitCallback != NULL)
                        set.quitCallback(state);
                break;
                case SDL_MOUSEBUTTONUP:
                    if(set.mouse != NULL)
                        set.mouse->buttonUp(state, event.button.x, event.button.y, event.button.button);
                    else if(set.mouseButtonUpCallback != NULL)
                        set.mouseButtonUpCallback(state, event.button.x, event.button.y, event.button.button);
                break;
                case SDL_MOUSEBUTTONDOWN:
                    if(set.mouse != NULL)
                        set.mouse->buttonDown(state, event.button.x, event.button.y, event.button.button);
                    else if(set.mouseButtonDownCallback != NULL)
                        set.mouseButtonDownCallback(state, event.button.x, event.button.y, event.button.button);
                break;
                case SDL_MOUSEMOTION:
                    if(set.mouse != NULL)
                        set.mouse->motion(state, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
                    else if(set.mouseMotionCallback != NULL)
                        set.mouseMotionCallback(state, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
                break;
                case SDL_KEYUP:
                    if(set.key != NULL)
                        set.key->keyUp(state, event.key.keysym.sym, event.key.keysym.mod);
                    else if(set.keyUpCallback != NULL)
                        set.keyUpCallback(state, event.key.keysym.sym, event.key.keysym.mod);
                break;
                case SDL_KEYDOWN:
                    if(set.key != NULL)
                        set.key->keyDown(state, event.key.keysym.sym, event.key.keysym.mod);
                    else if(set.keyDownCallback != NULL)
                        set.keyDownCallback(state, event.key.keysym.sym, event.key.keysym.mod);
                break;
            }
        }
        
        
        if(set.update != NULL)
            set.update->update(state);
        else if(set.updateCallback != NULL)
            set.updateCallback(state);
        
        if(set.draw != NULL)
            set.draw->draw(state);
        else if(set.drawCallback != NULL)
            set.drawCallback(state);
        
        if(set.throttle != NULL)
            set.throttle->throttle(state);
        else if(set.throttleCallback != NULL)
            set.throttleCallback(state);
    }
    
    state->set = NULL;
    
    if(tempState)
        delete state;
}



    void PL_Throttle::throttle(PL_State* state)
    {
        if(state != NULL)
        {
            long elapsed = SDL_GetTicks() - state->lastTime;
            if(elapsed < long(maxDelayTime) && elapsed >= 0)
                SDL_Delay(maxDelayTime - elapsed);
        }
    }
    
    void PL_Throttle::setFPS(float frames_per_second)
    {
        if(frames_per_second > 0)
        {
            fps = frames_per_second;
            maxDelayTime = 1000/fps;
        }
    }
    
    void defaultThrottleCallback(PL_State* state)
    {
        if(state != NULL)
        {
            long elapsed = SDL_GetTicks() - state->lastTime;
            if(elapsed < 20)
                SDL_Delay(20 - elapsed);
        }
    }
    
    void defaultKeyDownCallback(PL_State* state, SDLKey key, SDLMod modifier)
    {
        if(state != NULL)
        {
            if(key == SDLK_ESCAPE)
                state->done = true;
        }
    }
    
    void defaultQuitCallback(PL_State* state)
    {
        if(state != NULL)
            state->done = true;
    }
    
    
    PL_Set::~PL_Set()
    {
        if(update != NULL && update->temp)
            delete update;
        if(draw != NULL && draw->temp)
            delete draw;
        if(throttle != NULL && throttle->temp)
            delete throttle;
        if(mouse != NULL && mouse->temp)
            delete mouse;
        if(key != NULL && key->temp)
            delete key;
        if(joy != NULL && joy->temp)
            delete joy;
        if(other != NULL && other->temp)
            delete other;
    }

}

