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

#include "kernel.h"
#include "swis.h"

#include "buffer.h"

int buffer_area=-1;
char *buffer_address=NULL;
static const char *buffer_name="Pinboard";

_kernel_oserror *buffer_init(void)
{
  _kernel_oserror *e;
  if (buffer_area!=-1) return NULL; // already inited

  e=_swix(OS_DynamicArea,_INR(0,8)|_OUT(1)|_OUT(3),0,-1,0,-1,(1<<7),1024*1024,NULL,0,buffer_name,&buffer_area,&buffer_address); // start out empty

  if (e) {
    buffer_area=-1;
    buffer_address=NULL;
 }
  
  return e;
}

_kernel_oserror *buffer_final(void)
{
  if (buffer_area==-1) return NULL;
  
  _swix(OS_DynamicArea,_INR(0,1),1,buffer_area);
  buffer_area=-1;
  buffer_address=NULL;
  
  return NULL;
}

_kernel_oserror *buffer_push(int size,buffer_entry **inserted_address)
{
  // add to end of list
  _kernel_oserror *e;
  int heap_size=0,buffer_size,needed_size;
  
  if (buffer_area==-1) {
    e=buffer_init();
    if (e) return e;
  }
  
  _swix(OS_DynamicArea,_INR(0,1)|_OUT(2),2,buffer_area,&buffer_size);
  if (buffer_size!=0) {
    heap_size=*((int *)buffer_address);
  } else {
    heap_size=4; // size word at the start
  }

  size=(size+3)&~3;
  
  // see how much to extend the buffer
  needed_size=heap_size+size;
  if (needed_size>buffer_size) {
   e= _swix(OS_ChangeDynamicArea,_INR(0,1),buffer_area,needed_size-buffer_size);
   if (e) return e;
  }

  // update heap size
  *((int *)buffer_address)=needed_size;

  // return insert point address (caller may want to claim the block and copy the path in later to save 2x copy and alloc)
  *inserted_address=(buffer_entry *)(buffer_address+heap_size);
  (*inserted_address)->hdr.size=size;
  
  return NULL;
}
