// Change and add to this as you see fit.
// The STD and even syscalls are still in flux.
// Do your best to avoid adding bad design.
// Use std abstractions if they exist like logging functionality
import "sysdata/test-programs/hblib/std" as std;


fn rect(reg_x, reg_y, w, h, color) {
  li64(r3, 0);
  li64(r4, 0);
  li64(r5, w);
  li64(r6, h);

  let start_y = label();

  let start_x = label();

  add64(r9, r3, reg_x);
  add64(r10, r4, reg_y);
  pixel(r9, r10, color);

  li64(r1, 1);
  add64(r3, r3, r1);

  jltu(r3, r5, start_x);

  li64(r1, 1);
  add64(r4, r4, r1);

  li64(r3, 0);

  jltu(r4, r6, start_y);
}

fn pixel(reg_x, reg_y, color) {
  let BUFFER = 0xFFFF8000C0000000;
  let WIDTH = 1024;

  // r1 = y * WIDTH
  li64(r1, WIDTH);
  mul64(r1, reg_y, r1);

  // r2 = x + r2
  add64(r2, reg_x, r1);

  // r2 = r2 * 4
  li64(r1, 4);
  mul64(r2, r2, r1);
  
  // store pixel value
  li64(r1, color);
  st(r1, r2, BUFFER, 4);
}

fn clear() {
//   rect(r0, r0, 1024, 768, 0xff222222);

  let BUFFER = 0xFFFF8000C0000000;
  // on arm the FB is at 0xFFFF8000BC430000
  // FIXME: get the framebuffer pointer from the starting arguments

  li64(r1, 0xff222222);
  li64(r2, 0);
  li64(r3, 1);
  li64(r4, 1024 * 768);
  li64(r5, 4);
  let start = label();
  mul64(r6, r2, r5);
  st(r1, r6, BUFFER, 4);
  add64(r2, r2, r3);
  jltu(r2, r4, start);
}

// Define main
fn main(){
  std::Info("Starting the limine framebuffer driver.");

  li64(r100, 300);
  li64(r101, 300);
  li64(r102, 1);
  li64(r103, 1);
  li64(r104, 1024 - 20);
  li64(r105, 768 - 20);
  li64(r106, 0);
  li64(r107, 0);

  clear();

  let start = label();

  rect(r100, r101, 20, 20, 0xff222222);
  //clear();

  add64(r100, r100, r102);
  add64(r101, r101, r103);

  let after_x_right = declabel();
  jltu(r100, r104, after_x_right);
  li64(r102, -1);
  here(after_x_right);

  let after_x_left = declabel();
  jgtu(r100, r106, after_x_left);
  li64(r102, 1);
  li64(r100, 0);
  here(after_x_left);

  let after_y_right = declabel();
  jltu(r101, r105, after_y_right);
  li64(r103, -1);
  here(after_y_right);

  let after_y_left = declabel();
  jgtu(r101, r107, after_y_left);
  li64(r103, 1);
  li64(r101, 0);
  here(after_y_left);

  rect(r100, r101, 20, 20, 0xffffffff);

  li64(r200, 0);
  li64(r201, 1);
  li64(r202, 10000);
  let wait = label();
  add64(r200, r200, r201);
  jltu(r200, r202, wait);

  jeq(r0, r0, start);
  //jmp(start);

  std::Info("done");

  // Terminate execution.
  tx();
}

main();