#include <stdio.h>
#include <time.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#include "draw.h"

#define PRESCALE 4
#define FORMAT SDL_PIXELFORMAT_RGB565

#define WHITE rgb565(255, 255, 255)
#define BLACK rgb565(0, 0, 0)

typedef struct {
  int size;
  float* points;
} Polygon;

typedef struct {
  int size;
  Polygon* polygons;
} Data;

Data data;

void load(char* filename) {
  FILE* fp = fopen(filename, "r");
  if (!fp) {
    perror(filename);
    exit(1);
  }
  if (1 != fscanf(fp, "%d", &data.size)) goto load_error;
  data.polygons = malloc(sizeof(Polygon) * data.size);
  for (int i = 0; i < data.size; i++) {
    float tmp; // skip bbox
    if (4 != fscanf(fp, "%f %f %f %f", &tmp, &tmp, &tmp, &tmp)) goto load_error;
    if (1 != fscanf(fp, "%d", &data.polygons[i].size)) goto load_error;
    data.polygons[i].size *= 2; // number of values is number of points * 2
    data.polygons[i].points = malloc(sizeof(float) * data.polygons[i].size);
    for (int j = 0; j < data.polygons[i].size; j++) {
      if (1 != fscanf(fp, "%f", &data.polygons[i].points[j])) goto load_error;
    }
  }
  return;
load_error:
  perror(filename);
  exit(1);
}

float center[2] = {WIDTH / 2, 0};
float zoom = 1;

void init() {
  load("ne_10m_land.txt");
}

void deinit() {
}

void update(float dt) {
}

void redraw() {
  clear_screen();
  for (int i = 0; i < data.size; i++) {
    float transformed[data.polygons[i].size];
    for (int j = 0; j < data.polygons[i].size; j += 2) {
      transformed[j] = data.polygons[i].points[j] * zoom * WIDTH / 360 + WIDTH / 2 + center[0] * zoom;
      transformed[j + 1] = -data.polygons[i].points[j + 1] * zoom * HEIGHT / 180 + HEIGHT / 2 + center[1] * zoom;
    }
    //fill(data.polygons[i].size, transformed, WIDTH * zoom, rgb565((i * 128397) % 255, (i * 123551) % 255, (i * 1097123) % 255));
    fill(data.polygons[i].size, transformed, WIDTH * zoom, rgb565(255, 255, 255));
  }
}

//#define on_key(event)
//#define on_mouse(event, kind)
#define on_text(event)

int mouse_pressed = 0;
int mouse_start_x, mouse_start_y;
int center_start_x, center_start_y;

void on_key(SDL_Event event) {
  switch (event.key.keysym.sym) {
    case SDLK_1: zoom = 1; break;
    case SDLK_2: zoom = 4; break;
    case SDLK_3: zoom = 16; break;
    case SDLK_4: zoom = 64; break;
    case SDLK_5: zoom = 128; break;
  }
}

void on_mouse(SDL_Event event, int kind) {
  switch (kind) {
    case 1:
      mouse_pressed = 1;
      mouse_start_x = event.motion.x;
      mouse_start_y = event.motion.y;
      center_start_x = center[0];
      center_start_y = center[1];
      break;
    case 2:
      mouse_pressed = 0;
      break;
    case 0:
      if (mouse_pressed) {
        center[0] = ((event.motion.x - mouse_start_x) / zoom + center_start_x);
        center[1] = ((event.motion.y - mouse_start_y) / zoom + center_start_y);
      }
      break;
    case 3:
      zoom += event.wheel.preciseY / 8;
      break;
  }
}

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

  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    fprintf(stderr, "Failed to init SDL\n"); 
    return 1;
  }

  if(IMG_Init(IMG_INIT_PNG) < 0) {
    fprintf(stderr, "Failed to init SDL_Image\n"); 
    return 1;
  }

  init();

  SDL_Window* window = SDL_CreateWindow("RPG", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 2 * WIDTH, 2 * HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
  SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

  SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
  SDL_Texture* scaled = SDL_CreateTexture(renderer, FORMAT, SDL_TEXTUREACCESS_TARGET, PRESCALE * WIDTH, PRESCALE * HEIGHT);
  SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");

  SDL_RenderSetLogicalSize(renderer, WIDTH, HEIGHT);
  //SDL_RenderSetIntegerScale(renderer, 1);
  //SDL_MaximizeWindow(window);
  SDL_StartTextInput();

  SDL_SetRenderTarget(renderer, scaled);

  int fullscreen = 0;

  SDL_Texture* screen_texture = SDL_CreateTexture(renderer, FORMAT, SDL_TEXTUREACCESS_STATIC, WIDTH, HEIGHT);

  while (1) {
    Uint64 frame_start = SDL_GetPerformanceCounter();

    SDL_Event event;
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) { deinit(); exit(0);
      } else if(event.type == SDL_WINDOWEVENT) {
      } else if (event.type == SDL_KEYDOWN) { 
        if (event.key.keysym.sym == SDLK_RETURN && event.key.keysym.mod & KMOD_ALT) {
          fullscreen = SDL_WINDOW_FULLSCREEN_DESKTOP - fullscreen;
          SDL_SetWindowFullscreen(window, fullscreen);
        } else if (event.key.keysym.sym == SDLK_q && event.key.keysym.mod & KMOD_CTRL) {
          deinit(); exit(0);
        } else on_key(event);
      } else if (event.type == SDL_KEYUP) { on_key(event);
      } else if (event.type == SDL_TEXTINPUT) { on_text(event);
      } else if (event.type == SDL_MOUSEBUTTONDOWN) { on_mouse(event, 1);
      } else if (event.type == SDL_MOUSEMOTION) { on_mouse(event, 0);
      } else if (event.type == SDL_MOUSEBUTTONUP) { on_mouse(event, 2);
      } else if (event.type == SDL_MOUSEWHEEL) { on_mouse(event, 3);
      }
    }

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    SDL_UpdateTexture(screen_texture, NULL, framebuffer, WIDTH * sizeof(Color));
    SDL_RenderCopy(renderer, screen_texture, NULL, NULL); 

    SDL_SetRenderTarget(renderer, NULL);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, scaled, NULL, NULL); 
    SDL_RenderPresent(renderer);

    SDL_SetRenderTarget(renderer, scaled);

    update(1.0f / 60);
    redraw();

    Uint64 frame_end = SDL_GetPerformanceCounter();
    Uint64 duration = (frame_end - frame_start) * 1000 / SDL_GetPerformanceFrequency();
    if (duration > 0) printf("%ld fps\n", 1000 / duration);
    if(duration < 1000 / 60) SDL_Delay(1000 / 60 - duration);
  }

  deinit();

  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(window);
  SDL_Quit();
}
