#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include "spi_parser.h"

int reg_written = 0;
int reg_read = 0;

int reg_addr = 0;
int reg_len = 0;
uint8_t reg_buf[64];

static void spi_register_write(
    uint16_t address, const uint8_t *buf, uint16_t len) {
  reg_written = 1;
  reg_addr = address;
  reg_len = len;
  memcpy(reg_buf, buf, len);
}

static void spi_register_read(uint16_t address, uint8_t *buf, uint16_t len) {
  reg_read = 1;
  reg_addr = address;
  reg_len = len;
}

static void reset_reg() {
  reg_written = 0;
  reg_read = 0;
  reg_addr = 0;
  reg_len = 0;
}

struct test_case {
  const uint8_t* s;
  int s_len;
  int is_read;
  int is_write;
  int addr;
  int len;
  const uint8_t* expected;
};

static int check_reg(struct test_case* tc) {
  if (tc->is_read) {
    return reg_read && (reg_addr == tc->addr) && (reg_len == tc->len);
  } else if (tc->is_write) {
    return reg_written && (reg_addr == tc->addr) && (reg_len == tc->len) && (memcmp(reg_buf, tc->expected, tc->len) == 0);
  }
  return !reg_read && !reg_written;
}

static void dump_expected(struct test_case* tc) {
  if (tc->is_read && !reg_read) {
    printf("read bit not set, ");
  } else if (tc->is_write && !reg_written) {
    printf("write bit not set, ");
  } else {
    if (reg_read) {
      printf("read bit SET, should\'nt be \n");
      return;
    }
    if (reg_written) {
      printf("read bit SET, should\'nt be \n");
      return;
    }
  }
  if (tc->addr != reg_addr) {
    printf("got addr %04x, expected %04x, ", reg_addr, tc->addr);
  }
  if (tc->len != reg_len) {
    printf("got len %04x, expected %04x, ", reg_len, tc->len);
  }
  printf("\n");
}

int main() {
  const uint8_t test0[] = "r0102 1\n";
  const uint8_t test1[] = "r1234 1a\n";
  const uint8_t test2[] = "wffe7 3 11 22 33\n";
  const uint8_t test2_buf[] = {0x11, 0x22, 0x33};
  const uint8_t test3[] = "\n";
  const uint8_t test4[] = "w1ae7 8 1122 3344 ffee e0 f5\n";
  const uint8_t test4_buf[] = {0x11, 0x22, 0x33, 0x44, 0xff, 0xee, 0xe0, 0xf5};
  struct test_case cases[] = {
    {test0, sizeof(test0), 1, 0, 0x0102, 1, NULL},
    {test1, sizeof(test1), 1, 0, 0x1234, 0x1a, NULL},
    {test2, sizeof(test2), 0, 1, 0xffe7, 0x3, test2_buf},
    {test3, sizeof(test3), 0, 0, 0, 0, NULL},
    {test4, sizeof(test4), 0, 1, 0x1ae7, 8, test4_buf},
  };

  for (int i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) {
    reset_reg();
    parse_and_execute_cmd(cases[i].s, cases[i].s_len);
    if (!check_reg(&cases[i])) {
      printf("E: test failed\n");
      dump_expected(&cases[i]);
      return -1;
    } else {
      printf("I: test %d passed\n", i);
    }
  }

  return 0;
}
