#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "line.h"
#include "misc.h"

line_t *line_alloc(void)
{
  line_t *l = NULL;

  l = (line_t *)malloc(sizeof(line_t));
  if (l == NULL)
     return NULL;

  memset((line_t *)l, 0, sizeof(line_t));
  return l;
}

/*
   Set up the line buffer
   Allow user to provide a pre-allocated buffer
   for efficiency
*/
int line_init(line_t *l, char *buffer, unsigned long size)
{
  unsigned long s = 0;

  l->grow = DEFAULT_BUFFER_ADD;

  /*
    Pre-allocated buffer
  */
  if (buffer) { 
     if ((buffer != l->data) || (l->size != size)) {
        if (l->data)
           free(l->data);

        l->data = buffer;
        l->size = size;
     }     
  }
  
  /*
     Allocate default space
  */
  else { 
     if (size == 0)
        s = DEFAULT_BUFFER_SIZE;
     else
        s = size;

     l->data = (char *)malloc(s + 1);
     if (l->data == NULL)
        return 0;
 
     l->size = s;
     *(l->data) = '\0';
  }

  return 1;
}

int line_inject(line_t *l, char *data, unsigned long bytes)
{
  void *p = NULL;
  unsigned long addum = 0;

  /*
     Reallocate space
  */
  if ((l->bytes + bytes) > l->size) {
     if (l->grow < ((l->bytes + bytes) - l->size))
        addum = (((l->bytes + bytes) - l->size) + l->grow + 1);

     else
        addum = l->grow;

#ifdef DEBUG
     printf("line_inject: Reallocating: %d -> %d\n",
            l->size, l->size + addum + 1);
#endif
     p = realloc((char *)l->data, (l->size + addum + 1));
     if (p == NULL)
        return 0;

     if (p != l->data)
        l->data = p;

     l->size += addum;

#ifdef DEBUG
     printf("line_inject: Reallocated %p %lu -> %lu\n",
            l->data, (l->size - addum), l->size);
#endif
  }

#ifdef DEBUG
  printf("line_inject: Injected %d [", bytes);
  line_print(data, bytes);
  printf("] -> [");
#endif

  memcpy((char *)(l->data + l->bytes), (char *)data, bytes);
  l->bytes += bytes;

  *(l->data + l->bytes) = '\0';

#ifdef DEBUG
  line_print(data, bytes);
  printf("]\n");
#endif

  return 1;
}

void line_restart(line_t *l)
{
  if (l->bytes) {
     *(l->data) = '\0';
     l->bytes = 0;
  }
}

void line_kill(line_t *l)
{
  if (l->data)
     free(l->data);

  free(l);
}

#ifdef LINE_DEBUG
void line_print(char *b, unsigned long len)
{
  char *p = NULL;

  for (p = b; ((*p) && (p < (b + len))); p++)
      putchar(*p);
}
#endif
