#include "l3rt.h"

#define OFFSET	0
#define SIZE	1

int* _allocHeap(int size) {
  return _alloc(size*sizeof(int));
}

int** _allocHeapWithPointer(int size) {
  int* heap = _alloc(size*sizeof(int));
  int** fptr = (int**) _alloc(3*sizeof(int));
  
  fptr[0] = heap;
  fptr[1] = (int*)0;
  fptr[2] = (int*)size;
  
  return fptr;
}

int** _addressToFatPointer(int* address) {

  int** fptr = _alloc(12);
  fptr[0] = address;
  fptr[1] = (int*)0;
  fptr[2] = (int*)1;

  return fptr;
}

int** _allocNullFatPointer() {
  int** fptr = _alloc(12);
  
  fptr[0] = NULL;
  fptr[1] = (int*)0;
  fptr[2] = (int*)0;
  
  return fptr;
}

int _pointerInfo(int** ref, int side) {
  
  if (side == OFFSET) {
    return (int)ref[1];
  }
  else {
    return (int)ref[2];
  }
   
}

int** _copyFatPointer(int** fptr) {
  int** nfptr = (int**) _alloc(12);

  nfptr[0] = fptr[0];
  nfptr[1] = (int*)fptr[1];
  nfptr[2] = (int*)fptr[2];

  return nfptr;
}

int _pointerEquality(int** left, int** right, int equal) {
  //fprintf(stdout, "left[0]: 0x%x left[1]: 0x%x left[2]:0x%x\n", 
  //  (int)left[0], (int)left[1], (int)left[2]);
  
  //fprintf(stdout, "right[0]: 0x%x right[1]: 0x%x right[2]:0x%x\n", 
  //  (int)right[0], (int)right[1], (int)right[2]);

  if (equal)
    return (left[0] == right[0] && (int)left[1] == (int)right[1]);
  else
    return !((left[0] == right[0] && (int)left[1] == (int)right[1]));
}

int** _pointerAddition(int** fptr, int exp, int addition) {
  
  int** nfptr = _alloc(12);

  if (addition == 1)
    nfptr[1] = (int*)((int)fptr[1]+exp);
  else
    nfptr[1] = (int*)((int)fptr[1]-exp);
  
  nfptr[0] = fptr[0];
  nfptr[2] = fptr[2];

  return nfptr;
}

void _fancy_pointer_error (const char *srcfile, unsigned int line,
                     const char *errmsg)
{
  if (srcfile == NULL){
    if (errmsg == NULL)
      fprintf (stderr, "RUNTIME: PTRERROR: No message\n");
    else
      fprintf (stderr, "RUNTIME: PTRERROR: %s\n", errmsg);
  } else {
    if (errmsg == NULL)
      fprintf (stderr, "RUNTIME: %s:%d PTRERROR: No Message\n", srcfile, line);
    else fprintf (stderr, "RUNTIME: %s:%d PTRERROR: %s\n", srcfile, line, errmsg);
  }

  exit(-1);
}

int* _checkFatHeapPointer(int** fptr, char* srcfile, int line) {

  char buffer[256];

  if ((int)fptr[1] < 0) {
      _fancy_pointer_error(srcfile,line,"Index < 0");
      return 0;
  }	
  else if ((int)fptr[1] >= (int)fptr[2]) {
      sprintf(buffer, "Index >= Size (Index: %d Size: %d)", (int)fptr[1], (int)fptr[2]);
      _fancy_pointer_error(srcfile,line,buffer);
      return 0;
  }
  else {
    return fptr[0] + (int)fptr[1];
  }

}






