/**
 * Copyright (c) 2021 Dominic Masters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */
#include "sdl.h"

game_t *GAME_STATE;

int32_t main(int32_t argc, char *argv[]) {
  game_t *game;
  input_t *input;
  SDL_GLContext context;
  SDL_Window* displayWindow;
  SDL_Event event;
  SDL_Renderer* renderer;
  bool running;
  uint32_t currentTime;
  uint32_t lastTime;
  float timeDelta;

  // Init SEDL
  if(SDL_Init(SDL_INIT_VIDEO) < 0) {
    printf("No init SDL\n");
    return 1;
  }

  // Setup GL Information.
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, OPENGL_MAJOR_VERSION);
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, OPENGL_MINOR_VERSION);

  // Create a window
  displayWindow = SDL_CreateWindow("test",
    SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
    SCREEN_WIDTH, SCREEN_HEIGHT,
    SDL_WINDOW_OPENGL | SDL_RENDERER_ACCELERATED
    // SDL_WINDOW_OPENGL | SDL_RENDERER_ACCELERATED | SDL_WINDOW_FULLSCREEN
  );
  if(displayWindow == NULL) {
    printf("No make window %s\n", SDL_GetError());
    return 1;
  }

  // Create Renderer
  renderer = SDL_CreateRenderer(displayWindow, -1, SDL_RENDERER_ACCELERATED);
  if(renderer == NULL) {
    printf("SDL2 Renderer couldn't be created. Error: %s\n", SDL_GetError());
    return 1;
  }

  // Create a GL Context
  context = SDL_GL_CreateContext(displayWindow);
  if(context == NULL) {
    printf("No make context\n");
    return 1;
  }

  #if SETTING_PLATFORM_USE_GLAD == 1
    // Load glad
    if (!gladLoadGLLoader((GLADloadproc) SDL_GL_GetProcAddress)) {
      printf("Failed to initialize the OpenGL context.\n");
      return 1;
    }
  #endif

  // Bind the GL Context
  SDL_GL_MakeCurrent(displayWindow, context);

  // SDL Time management init
  currentTime = SDL_GetTicks();
  lastTime = currentTime - EPOCH_FIXED_STEP;

  // Initialize the game
  game = malloc(sizeof(game_t));
  GAME_STATE = game;
  printf("Game is %zu bytes.\n", sizeof(game_t));
  renderSetResolution(&game->engine.render, SCREEN_WIDTH, SCREEN_HEIGHT);

  if(gameInit(game)) {
    input = &game->engine.input;

    // Bind initial keys
    inputBind(input, INPUT_NULL,         (inputsource_t)SDLK_ESCAPE);
    inputBind(input, INPUT_DEBUG_UP,     (inputsource_t)SDLK_w);
    inputBind(input, INPUT_DEBUG_DOWN,   (inputsource_t)SDLK_s);
    inputBind(input, INPUT_DEBUG_LEFT,   (inputsource_t)SDLK_a);
    inputBind(input, INPUT_DEBUG_RIGHT,  (inputsource_t)SDLK_d);

    inputBind(input, INPUT_UP,           (inputsource_t)SDLK_UP);
    inputBind(input, INPUT_DOWN,         (inputsource_t)SDLK_DOWN);
    inputBind(input, INPUT_LEFT,         (inputsource_t)SDLK_LEFT);
    inputBind(input, INPUT_RIGHT,        (inputsource_t)SDLK_RIGHT);
    inputBind(input, INPUT_UP,           (inputsource_t)SDLK_w);
    inputBind(input, INPUT_DOWN,         (inputsource_t)SDLK_s);
    inputBind(input, INPUT_LEFT,         (inputsource_t)SDLK_a);
    inputBind(input, INPUT_RIGHT,        (inputsource_t)SDLK_d);
    inputBind(input, INPUT_ACCEPT,       (inputsource_t)SDLK_e);
    inputBind(input, INPUT_ACCEPT,       (inputsource_t)SDLK_RETURN);
    inputBind(input, INPUT_ACCEPT,       (inputsource_t)SDLK_SPACE);

    // Update window title.
    SDL_SetWindowTitle(displayWindow, SETTING_GAME_NAME);
    running = true;

    while(running) {
      // Poll for SDL Events
      while(SDL_PollEvent(&event)) {
        switch(event.type) {
          case SDL_QUIT:
            running = false;
            break;

          case SDL_KEYDOWN:
            input->buffer[(inputsource_t)event.key.keysym.sym] = true;
            break;

          case SDL_KEYUP:
            input->buffer[(inputsource_t)event.key.keysym.sym] = false;
            break;
            
          default:
            break;
        }
      }
      
      if(!running) break;

      // Calc time delta
      lastTime = currentTime;
      currentTime = SDL_GetTicks();
      timeDelta = (currentTime - lastTime) / 1000.0f;

      // Tick Game
      if(!gameUpdate(game, timeDelta)) break;

      // Swap buffers
      SDL_GL_SwapWindow(displayWindow);
    }

    // Game has finished running, cleanup.
    gameDispose(game);
  }
  free(game);

  // Cleanup SDL
  SDL_GL_DeleteContext(context);
  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(displayWindow);
  SDL_Quit();

  return 0;
}