#include <SDL2/SDL.h>

#define KEY_LEFT SDL_SCANCODE_LEFT
#define KEY_RIGHT SDL_SCANCODE_RIGHT
#define KEY_UP SDL_SCANCODE_UP
#define KEY_DOWN SDL_SCANCODE_DOWN
#define KEY_SPACE SDL_SCANCODE_SPACE
#define KEY_0 SDL_SCANCODE_0
#define KEY_1 SDL_SCANCODE_1
#define KEY_9 SDL_SCANCODE_9
#define KEY_A SDL_SCANCODE_A
#define KEY_F SDL_SCANCODE_F
#define KEY_G SDL_SCANCODE_G
#define KEY_F2 SDL_SCANCODE_F2
#define KEY_PLUS SDL_SCANCODE_KP_PLUS
#define KEY_MINUS SDL_SCANCODE_KP_MINUS
#define KEY_ENTER SDL_SCANCODE_RETURN
#define KEY_ESC SDL_SCANCODE_ESCAPE
#define KEY_F7 SDL_SCANCODE_F7
#define KEY_F8 SDL_SCANCODE_F8
#define KEY_F9 SDL_SCANCODE_F9
#define KEY_F5 SDL_SCANCODE_F5
#define KEY_F11 SDL_SCANCODE_F11
#define KEY_F12 SDL_SCANCODE_F12
#define SCANCODE_UNKNOWN SDL_SCANCODE_UNKNOWN


SDL_Window *window;
SDL_Renderer *renderer;

void put_pixel(unsigned x, unsigned y, unsigned char color);

void set_color(unsigned char color)
{
  unsigned char r, g, b;

  #define NOINT 0xA0
  #define INTADD (255-NOINT)

  b = (color & 1) ? NOINT : 0;
  g = (color & 2) ? NOINT : 0;
  r = (color & 4) ? NOINT : 0;
  if(color & 8)
  {
    r += INTADD;
    g += INTADD;
    b += INTADD;
  }

  SDL_SetRenderDrawColor(renderer, r, g, b, -1);
}

/*void sdl_fill(unsigned char color)
{
  set_color(color);
  SDL_RenderClear(renderer);
}*/

void show_pixel(unsigned x, unsigned y, unsigned char color)
{
  struct SDL_Point point[4];

  point[0].x = x<<1;
  point[0].y = y<<1;

  point[1].x = (x<<1)+1;
  point[1].y = y<<1;

  point[2].x = x<<1;
  point[2].y = (y<<1)+1;

  point[3].x = (x<<1)+1;
  point[3].y = (y<<1)+1;

  set_color(color);
  SDL_RenderDrawPoints(renderer, point, 4);
}

/*void draw_rectangle(unsigned x, unsigned y, unsigned w,
                    unsigned h, unsigned char color)
{
  struct SDL_Rect sdlrect;

  sdlrect.x = x<<1;
  sdlrect.y = y<<1;
  sdlrect.w = w<<1;
  sdlrect.h = h<<1;

  set_color(color);
  SDL_RenderFillRect(renderer, &sdlrect);
}*/

unsigned char get_pixel(unsigned x, unsigned y);

SDL_Surface *surface;

int create_surface(void)
{
  surface = SDL_CreateRGBSurfaceWithFormat(0, 320, 200, 32, SDL_PIXELFORMAT_RGBX8888);
  if(!surface)
  {
    puts("Couldn't create SDL2 surface");
    return 1;
  }
  return 0;
}

void update_screenr(unsigned x, unsigned y, unsigned width, unsigned height, unsigned unused)
{
  unsigned c, n;
  unsigned char color;
  int rc;
  SDL_Texture *texture;
  unsigned set_count = width<<2;
  unsigned offset;

  for(n=0;height--;n++,y++)
  {
    offset = (y<<8)+(y<<6)+x;
    memset(&(((uint32_t*)surface->pixels)[offset]), 0, set_count);
    for(c=x,n=width;n--;c++,offset++)
    {
      color = get_pixel(c, y);

      if(color & 1)
        ((uint32_t*)surface->pixels)[offset] |= NOINT << 8;
      if(color & 2)
        ((uint32_t*)surface->pixels)[offset] |= NOINT << 16;
      if(color & 4)
        ((uint32_t*)surface->pixels)[offset] |= NOINT << 24;

      if(color & 8)
        ((uint32_t*)surface->pixels)[offset] += (INTADD << 8) | (INTADD << 16) | (INTADD << 24);
    }
  }

  texture = SDL_CreateTextureFromSurface(renderer, surface);

  if(!texture)
  {
    puts("Could not create SDL2 texture");
  }


  rc = SDL_RenderCopy(renderer, texture, 0, 0);
  if(rc)
  {
    printf("SDL_RenderCopy() error: %s\n", SDL_GetError());
  }

  SDL_DestroyTexture(texture);

/*  for(y=0;y<200;y++)
    for(x=0;x<320;x++)
      show_pixel(x, y, get_pixel(x, y));*/

  SDL_RenderPresent(renderer);
}

#define update_screen() update_screenr(0, 0, 320, 200, 0)

void exit_program(void)
{
  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(window);
  SDL_Quit();
  exit(0);
}

SDL_Scancode get_input(unsigned x, unsigned y)
{
  SDL_Event e;
  static unsigned char color;

  while(1)
  {
    do
    {
      put_pixel(x, y, color++ | 0x8);
      update_screen();
    }
    while(!SDL_WaitEventTimeout(&e, 500));

    if(e.type == SDL_QUIT)
      exit_program();

    if(e.type == SDL_KEYDOWN)
      return e.key.keysym.scancode;

  }
}

#ifdef GAME

SDL_Keycode poll_keycode(void)
{
  SDL_Event e;

  if(SDL_PollEvent(&e))
  {
    if(e.type == SDL_QUIT)
      exit_program();
  }

  if(e.type == SDL_KEYDOWN)
  {
    if(e.key.keysym.sym == '\b' || e.key.keysym.sym == '\r' || e.key.keysym.sym == 0x1b)
      return e.key.keysym.sym;
  }
  if(e.type == SDL_TEXTINPUT)
  {
    return e.text.text[0];
  }

  return 0;
}

SDL_Scancode poll_keypress(void)
{
  SDL_Event e;

  if(SDL_PollEvent(&e))
  {
    if(e.type == SDL_QUIT)
      exit_program();
  }

  if(e.type == SDL_KEYDOWN)
  {
    switch(e.key.keysym.scancode)
    {
      case KEY_LEFT: movekeys.left = 1; break;
      case KEY_RIGHT: movekeys.right = 1; break;
      case KEY_DOWN: movekeys.down = 1; break;
      case KEY_UP: movekeys.up = 1; break;
    }
    return e.key.keysym.scancode;
  }
  else if(e.type == SDL_KEYUP)
  {
    switch(e.key.keysym.scancode)
    {
      case KEY_LEFT: movekeys.left = 0; break;
      case KEY_RIGHT: movekeys.right = 0; break;
      case KEY_DOWN: movekeys.down = 0; break;
      case KEY_UP: movekeys.up = 0; break;
    }
  }

  return SDL_SCANCODE_UNKNOWN;
}

#endif

int init_screen_sdl(char *title)
{
  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
  {
    printf("Could not initialize SDL2: %s\n", SDL_GetError());
    return 1;
  }

  window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                            320*setup.screen_scale, 200*setup.screen_scale, SDL_WINDOW_OPENGL);
  if(!window)
  {
    puts("Error while creating SDL2 window.");
    return 2;
  }

  renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
  if(!renderer)
  {
    puts("Error while creating renderer");
    return 3;
  }

  if(create_surface())
    return 4;

  return 0;
}

volatile unsigned char key_pressed;

int keypress_handler(void *data, SDL_Event *e)
{
  unsigned char *k = (unsigned char*)data;

  if(e->type == SDL_KEYDOWN)
    *k = 1;
}

void set_keypress_handler(void)
{
  key_pressed = 0;
  SDL_AddEventWatch(keypress_handler, (void*)&key_pressed);
}

void unset_keypress_handler(void)
{
  SDL_DelEventWatch(keypress_handler, (void*)&key_pressed);
}
