program Pong;
const
  SDL_WINDOW_SHOWN = 4;
  SDL_RENDERER_ACCELLERATED = 2;
  SDL_QUIT = 256;
  SDL_KEYDOWN = 768;
  SDL_KEYUP = 769;
  SDLK_ESCAPE = 27;

  WIDTH = 1280;
  HEIGHT = 720;

  title = 'Pong';
  filename = 'font.ttf';
  EXIT_FAILURE = 1;

  SCALE_W = 640;
  SCALE_H = 360;

  SDL_SCANCODE_DOWN = 81;
  SDL_SCANCODE_UP = 82;

  PADDLE_W = 6;
  PADDLE_H = 56;
  PADDLE_STEP = 4;
  PADDLE_STEP_AI = 4;

  BALL_W = 6;
  BALL_H = 6;
  BALL_SPEED_X = 4;
  BALL_SPEED_Y = 4;

type
  Point = record
    x: integer;
    y: integer;
  end;

var
  running: boolean;
  event_type_result: integer;
  window_id, renderer, target_id: integer;
  font_id: integer;
  key: integer;
  paddle1, paddle2: Point;
  ball: Point;
  ball_dx, ball_dy: integer;
  score_l, score_r: integer;

procedure draw_box(px, py, pw, ph: integer);
begin
  sdl_fill_rect(renderer, px, py, pw, ph);
end;

procedure reset_ball(to_right: boolean);
begin
  ball.x := (SCALE_W div 2) - (BALL_W div 2);
  ball.y := (SCALE_H div 2) - (BALL_H div 2);
  if to_right = true then ball_dx := BALL_SPEED_X else ball_dx := -BALL_SPEED_X;
  if (sdl_get_ticks() mod 2) = 0 then ball_dy := BALL_SPEED_Y else ball_dy := -BALL_SPEED_Y;
end;

procedure clamp_paddle(p: Point);
begin 
  if p.y < 0 then p.y := 0;
  if p.y + PADDLE_H > SCALE_H then p.y := SCALE_H - PADDLE_H;
end;

function aabb(ax, ay, aw, ah, bx, by, bw, bh: integer): boolean;
begin
  aabb := not ((ax + aw <= bx) or (bx + bw <= ax) or (ay + ah <= by) or (by + bh <= ay));
end;

procedure update_input();
begin
  if sdl_is_key_pressed(SDL_SCANCODE_UP) <> 0 then paddle1.y := paddle1.y - PADDLE_STEP;
  if sdl_is_key_pressed(SDL_SCANCODE_DOWN) <> 0 then paddle1.y := paddle1.y + PADDLE_STEP;
    clamp_paddle(paddle1); 
end;

procedure update_ai();
var
  center_ball, center_p2: integer;
begin
  center_ball := ball.y + (BALL_H div 2);
  center_p2 := paddle2.y + (PADDLE_H div 2);
  if center_ball < center_p2 - 4 then paddle2.y := paddle2.y - PADDLE_STEP_AI
  else if center_ball > center_p2 + 4 then paddle2.y := paddle2.y + PADDLE_STEP_AI;
  clamp_paddle(paddle2);
end;

procedure update_ball();
begin
  ball.x := ball.x + ball_dx;
  ball.y := ball.y + ball_dy;

  if ball.y <= 0 then begin ball.y := 0; ball_dy := -ball_dy; end;
  if ball.y + BALL_H >= SCALE_H then begin ball.y := SCALE_H - BALL_H; ball_dy := -ball_dy; end;

  if aabb(ball.x, ball.y, BALL_W, BALL_H, paddle1.x, paddle1.y, PADDLE_W, PADDLE_H) then
  begin
    ball.x := paddle1.x + PADDLE_W;
    ball_dx := -ball_dx;
  end;

 if aabb(ball.x, ball.y, BALL_W, BALL_H, paddle2.x, paddle2.y, PADDLE_W, PADDLE_H) then
  begin
    ball.x := paddle2.x - BALL_W;
    ball_dx := -ball_dx;
  end;

  if ball.x + BALL_W < 0 then
  begin
    score_r := score_r + 1;
    reset_ball(true);
  end;

  if ball.x > SCALE_W then
  begin
    score_l := score_l + 1;
    reset_ball(false);
  end; 
end;

procedure render_center_line();
var
  yy: integer;
begin
  yy := 0;
  while yy < SCALE_H do
  begin
    draw_box((SCALE_W div 2) - 1, yy, 2, 8);
    yy := yy + 16;
  end;
end;

procedure render();
begin
  sdl_set_render_target(renderer, target_id);
  sdl_set_draw_color(renderer, 0, 0, 0, 255);
  sdl_clear(renderer);

  sdl_set_draw_color(renderer, 255, 255, 255, 255);
  render_center_line();

  draw_box(paddle1.x, paddle1.y, PADDLE_W, PADDLE_H);
  draw_box(paddle2.x, paddle2.y, PADDLE_W, PADDLE_H);
  draw_box(ball.x, ball.y, BALL_W, BALL_H);

  sdl_draw_text(renderer, font_id, 'Score: ' + inttostr(score_l), (SCALE_W div 2) - 100, 8, 255, 255, 255, 255);
  sdl_draw_text(renderer, font_id, 'Score: ' + inttostr(score_r), (SCALE_W div 2) + 20, 8, 255, 255, 255, 255);
end;

procedure init(title: string; xval, yval, wval, hval: integer);
var
  result: integer;
begin
  result := sdl_init();
  if result <> 0 then
  begin
    writeln('failed to init SDL');
    halt(EXIT_FAILURE);
  end;

  window_id := sdl_create_window(title, xval, yval, wval, hval, SDL_WINDOW_SHOWN);
  if window_id = -1 then
  begin
    writeln('Could not create window');
    sdl_quit();
    halt(EXIT_FAILURE);
  end;

  renderer := sdl_create_renderer(window_id, -1, SDL_RENDERER_ACCELLERATED);
  if renderer = -1 then
  begin
    writeln('could not create renderer');
    sdl_destroy_window(window_id);
    sdl_quit();
    halt(EXIT_FAILURE);
  end;

  target_id := sdl_create_render_target(renderer, SCALE_W, SCALE_H);
  if target_id = -1 then
  begin
    writeln('could not create render target');
    sdl_destroy_renderer(renderer);
    sdl_destroy_window(window_id);
    sdl_quit();
    halt(EXIT_FAILURE);
  end;

  if sdl_init_text() <> 1 then
  begin
    writeln('Font subsystem failed to load');
    halt(EXIT_FAILURE);
  end;

  font_id := sdl_load_font(filename, 16);
  if font_id = -1 then
  begin
    writeln('failed to open: ', filename);
    halt(EXIT_FAILURE);
  end;

  paddle1.x := 16;
  paddle1.y := (SCALE_H div 2) - (PADDLE_H div 2);
  paddle2.x := SCALE_W - 16 - PADDLE_W;
  paddle2.y := (SCALE_H div 2) - (PADDLE_H div 2);

  reset_ball(true);

  score_l := 0;
  score_r := 0;
end;

procedure cleanup;
begin
  sdl_destroy_render_target(target_id);
  sdl_destroy_renderer(renderer);
  sdl_destroy_window(window_id);
  sdl_quit_text();
  sdl_quit();
end;

begin
  init(title, 100, 100, WIDTH, HEIGHT);
  running := true;
  while running = true do
  begin
    while sdl_poll_event() <> 0 do
    begin
      event_type_result := sdl_get_event_type();
      if event_type_result = SDL_QUIT then running := false;
      if event_type_result = SDL_KEYDOWN then
      begin
        key := sdl_get_key_code();
        if key = SDLK_ESCAPE then running := false;
      end;
    end;

    update_input();
    update_ai();
    update_ball();
    render();
    sdl_present_scaled(renderer, target_id, WIDTH, HEIGHT);
    sdl_delay(16);
  end;
  cleanup;
end.