/* putil.c */
#include <stdlib.h>
#include <string.h>

#include "putil.h"

static int
pu_redis_prolog_atom_buf_size(TERM* t)
{
  char buf[AZ_MAX_ATOM_LENGTH + 1];

  if (IsAtom(t)) {
    Atom2Asciz(GetAtom(t), buf);
    return strlen(buf);
  }
  else
    return -1;
}

static int
pu_redis_prolog_list_buf_size(TERM* t)
{
  int len;

  if (IsNil(t))
    return 0;

  len = 0;
  while (IsCons(t)) {
    REALVALUE(t);
    t = BODY(t);
    if (IsInt(t)) {
      len++;
    }
    else if (IsAtom(t)) {
      if (GetAtom(t) != ATOM_NIL) { /* ignore ATOM_NIL => "[]" */
        len += pu_redis_prolog_atom_buf_size(t);
      }
    }
    else if (IsCons(t)) {
      len += pu_redis_prolog_list_buf_size(t);
    }
    else {
      return -1; /* error */
    }

    t++;
  }

  return len;
}

extern char*
pu_redis_prolog_list_to_string(TERM* t, char **pp)
{
  int len;
  char *buf;
  char *p;
  TERM *tb;

  if (pp == NULL) {
    len = pu_redis_prolog_list_buf_size(t);
    if (len <= 0)
      return NULL;

#if 0
    fprintf(stderr, "prolog_list_to_buf: %d\r\n", len);
    fflush(stderr);
#endif

    p = buf = (char* )malloc(len + 1);
    if (buf == NULL) {
      return NULL;
    }
    buf[0] = '\0';
  }
  else {
    buf = NULL;
    p = *pp;
  }

  while (IsCons(t)) {
    REALVALUE(t);
    t = BODY(t);
    tb = t;
    REALVALUE(tb);

    if (IsInt(tb)) {
      int v = GetInt(tb);
      if (v > 255 || v < 0) {
      err:
        if (buf != NULL) free(buf);
        return NULL;
      }

      *p = (char )v;
      p++;
      if (pp != NULL) (*pp)++;
    }
    else if (IsAtom(tb)) {
      if (GetAtom(tb) != ATOM_NIL) { /* ignore ATOM_NIL => "[]" */
        Atom2Asciz(GetAtom(tb), p);
        p += pu_redis_prolog_atom_buf_size(tb);
      }
    }
    else if (IsCons(tb)) {
      pu_redis_prolog_list_to_string(tb, &p);
    }
    else {
      goto err;
    }

    t++;
  }
  *p = '\0';

  return buf;
}

extern int pu_redis_is_prolog_string(TERM* t)
{
  if (IsCons(t)) {
    TERM *tb;

    REALVALUE(t);
    t = BODY(t);
    tb = t;
    REALVALUE(tb);
    if (IsInt(tb))
      return 1;
  }

  return 0;
}
