#include "application.h"
#include "settings.h"
#include "resources.h"
#include "scenes.h"
#include "ui.h"
#include "utils.h"
#include "camera.h"
#include "log.h"
#include "tween.h"
#include "player.h"

unsigned int  running  = 0;

static SDL_Window    *window   = NULL;
static SDL_Renderer  *renderer = NULL;
static int            app_width;
static int            app_height;
static unsigned int   last_time, current_time;
static float          delta_time;
static key_state_t    keys[MAX_KEYS];

rgba_t         bg_color;
rgba_t         bg_black_color;
mouse_button_t mouse_button;

static void _Application_ResetKeys()
{
    Uint32 i = 0;

    for(i = 0; i < MAX_KEYS; ++i)
    {
        keys[i].down  = false;
        keys[i].press = false;
        keys[i].up    = false;
    }
}

static void _Application_CalculateKeys()
{
    Uint32 i = 0;
    const Uint8 *state = SDL_GetKeyboardState(NULL);

    for(i = 0; i < MAX_KEYS; ++i)
    {
        keys[i].down  = false;
        keys[i].up    = false;
    }

    if (state[SDL_SCANCODE_UP])
    {
        if (!keys[KEY_UP].press)
            keys[KEY_UP].down = true;

        keys[KEY_UP].press = true;
    }
    else
    {
        if (keys[KEY_UP].press)
            keys[KEY_UP].up = true;

        keys[KEY_UP].press = false;
    }

    if (state[SDL_SCANCODE_RIGHT])
    {
        if (!keys[KEY_RIGHT].press)
            keys[KEY_RIGHT].down = true;

        keys[KEY_RIGHT].press = true;
    }
    else
    {
        if (keys[KEY_RIGHT].press)
            keys[KEY_RIGHT].up = true;

        keys[KEY_RIGHT].press = false;
    }

    if (state[SDL_SCANCODE_DOWN])
    {
        if (!keys[KEY_DOWN].press)
            keys[KEY_DOWN].down = true;

        keys[KEY_DOWN].press = true;
    }
    else
    {
        if (keys[KEY_DOWN].press)
            keys[KEY_DOWN].up = true;

        keys[KEY_DOWN].press = false;
    }

    if (state[SDL_SCANCODE_LEFT])
    {
        if (!keys[KEY_LEFT].press)
            keys[KEY_LEFT].down = true;

        keys[KEY_LEFT].press = true;
    }
    else
    {
        if (keys[KEY_LEFT].press)
            keys[KEY_LEFT].up = true;

        keys[KEY_LEFT].press = false;
    }

    if (state[SDL_SCANCODE_SPACE])
    {
        if (!keys[KEY_SPACE].press)
            keys[KEY_SPACE].down = true;

        keys[KEY_SPACE].press = true;
    }
    else
    {
        if (keys[KEY_SPACE].press)
            keys[KEY_SPACE].up = true;

        keys[KEY_SPACE].press = false;
    }

    if (state[SDL_SCANCODE_ESCAPE])
    {
        if (!keys[KEY_ESC].press)
            keys[KEY_ESC].down = true;

        keys[KEY_ESC].press = true;
    }
    else
    {
        if (keys[KEY_ESC].press)
            keys[KEY_ESC].up = true;

        keys[KEY_ESC].press = false;
    }
}

static void _Application_Resize(void)
{
    SDL_GetWindowSize(window, &app_width, &app_height);

    Camera_SetViewport(app_width, app_height);
}

void Application_Run(void)
{
    if (running == 0)
    {
        //Log_Delete();
        //Log_Print("run\n");

        SDL_Event event;

        srand((unsigned int)time(NULL));

        SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);

        Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);

        window   = SDL_CreateWindow(APP_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, APP_WIDTH, APP_HEIGHT, SDL_WINDOW_SHOWN/*SDL_WINDOW_RESIZABLE*/);
        renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_PRESENTVSYNC);

        Settings_Init();
        Settings_Load();

        if (Settings_GetFullscreen())
            SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);

        Mix_Volume(-1, Settings_GetVolume());

        //SDL_GetDisplayBounds(0, &display_bounds);

        Camera_Init();
        _Application_Resize();
        _Application_ResetKeys();

        bg_black_color = Utils_GetRGBA(0, 0, 0, 255);
        bg_color       = Utils_GetRGBA(176, 210, 220, 255);

        Application_SetBGColor(bg_black_color);

        Resources_Init();
        Tween_Init();
        Scene_Set(SCENE_INTRO);

        UI_Cursor_Init();
        mouse_button.press = false;
        mouse_button.down  = false;
        mouse_button.up    = false;

        running = 1;

        current_time = SDL_GetTicks();
        last_time    = current_time;

        while(running)
        {
            mouse_button.down  = false;
            mouse_button.up    = false;

            current_time = SDL_GetTicks();
            delta_time   = (float)(current_time - last_time) / 1000;
            last_time    = current_time;

            SDL_PumpEvents();

            while(SDL_PollEvent(&event))
            {
                switch(event.type)
                {
                    case SDL_QUIT            :  Application_Quit();
                                                break;
                    //case SDL_KEYDOWN : printf("key down\n"); break; // иногда даже тут не приходят сигналы от зажатой клавиши ESC :(

                    case SDL_MOUSEBUTTONDOWN :  mouse_button.down  = true;
                                                mouse_button.press = true;
                                                break;

                    case SDL_MOUSEBUTTONUP   :  mouse_button.up    = true;
                                                mouse_button.press = false;
                                                break;

                    case SDL_WINDOWEVENT     :  if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
                                                    _Application_Resize();
                                                break;
                    default: break;
                }
            }

            _Application_CalculateKeys();

            Tween_Update();
            Scene_Update(delta_time);
            SDL_RenderClear(renderer);
            Scene_Draw(renderer);
            SDL_RenderPresent(renderer);
        }

        Scene_Set(SCENE_NONE); // free current scene

        Camera_Quit();
        Tween_Quit();
        Player_Quit();
        Resources_Quit();

        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);

        Mix_Quit();
        SDL_Quit();
    }
}

void Application_Quit(void)
{
    running = 0;
}

SDL_Window* Application_GetWindow(void)
{
    return window;
}

SDL_Renderer* Application_GetRenderer(void)
{
    return renderer;
}

int Application_GetWidth(void)
{
    return app_width;
}

int Application_GetHeight(void)
{
    return app_height;
}

void Application_SetBGColor(rgba_t color)
{
    SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
}

bool Application_IsKeyDown(key_t key)
{
    return keys[key].down;
}

bool Application_IsKeyPress(key_t key)
{
    return keys[key].press;
}

bool Application_IsKeyUp(key_t key)
{
    return keys[key].up;
}

void Application_SetFullscreen(void)
{
    SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
    _Application_Resize();
}

void Application_SetWindowed(void)
{
    SDL_SetWindowFullscreen(window, SDL_FALSE);
    SDL_SetWindowSize(window, APP_WIDTH, APP_HEIGHT);
    SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
    _Application_Resize();
}
