#include <stdint.h>
#include <stddef.h>
#include "rbuf/rbuf.h"
#include "spinlock/spinlock.h"
#include "hal/hal.h"
#include "dlmalloc/malloc.h"
#include "errors.h"
#include "pipe.h"
#include "kprintf.h"

int32_t ipc_pipeinit(IpcPipe *pipe, uint64_t pid) {
  hal_memset(pipe, 0, sizeof(*pipe));
  spinlock_init(&pipe->spinlock);
  pipe->ownerpid = pid;
  
  uint8_t *buf = dlmalloc(IPC_PIPE_MAX);
  if (buf == NULL) {
    return E_NOMEMORY;
  }
  
  rbuf_init(&pipe->rbuf, buf, IPC_PIPE_MAX);

  return E_OK;
}

void ipc_pipefree(IpcPipe *pipe) {
  if (pipe->rbuf.buffer != NULL) {
    dlfree(pipe->rbuf.buffer);
  }
}

int32_t ipc_pipewrite(IpcPipe *pipe, const uint8_t *const buffer, size_t n) {
  size_t i = 0;
  spinlock_acquire(&pipe->spinlock);
  for (; i < n; i++) {
    rbuf_push(&pipe->rbuf, buffer[i]);
  }
  spinlock_release(&pipe->spinlock);
  return i;
}

int32_t ipc_piperead(IpcPipe *pipe, uint8_t *const buffer, size_t n) {
  size_t i = 0;
  spinlock_acquire(&pipe->spinlock);
  while (i < n) {
    if (rbuf_pop(&pipe->rbuf, &buffer[i]) < 0) {
      break;
    }
    i++;
  }
  spinlock_release(&pipe->spinlock);
  return i;
}
