/* This file converts Values from one type to another. They all allocate a new
   Value and return it. */

#include "layout.h"
#include <stdio.h>
#include <string.h>
#include <math.h>


void fprintvalue(FILE *f, Value *v) {
  int *il;
  switch (v->t) {
  case ValueString:
    fprintf(f, "[s \"%s\"]", v->v.s);
    break;
  case ValueInt:
    fprintf(f, "[i %d]", v->v.i);
    break;
  case ValueDouble:
    fprintf(f, "[d %lg]", v->v.d);
    break;
  case ValueBool:
    fprintf(f, "[b %s]", v->v.b ? "true" : "false");
    break;
  case ValueIntList:
    fprintf(f, "[il");
    for (il = v->v.il; *il >= 0; il++) fprintf(f, " %d", *il);
    fprintf(f, "]");
    break;
  case ValueEmpty:
    fprintf(f, "[]");
    break;
  }
}


Bool valconvtoInt(Value *v) {
  char *check;
  int i;
  
  switch (v->t) {
    
  case ValueInt:
    return 1;

  case ValueDouble:
    i = v->v.d;
    break;

  case ValueString:
    i = strtol(v->v.s, &check, 0);
    if (*check) return 0;
    freetrace(v->v.s);
    break;
    
  case ValueBool:
    i = v->v.b != 0;
    break;

  case ValueIntList:
    if (v->v.il[0] < 0 || v->v.il[1] >= 0) return 0;
    i = v->v.il[0];
    freetrace(v->v.il);
    break;

  default:
    return 0;
    
  }

  v->t = ValueInt;
  v->v.i = i;
  return 1;
}


Bool valconvtoString(Value *v) {
  char buf[BUFSIZ];

  switch (v->t) {

  case ValueInt:
    sprintf(buf, "%d", v->v.i);
    break;

  case ValueString:
    return 1;

  case ValueDouble:
    sprintf(buf, "%lg", v->v.d);
    break;

  case ValueBool:
    strcpy(buf, v->v.b ? "true" : "false");
    break;

  default:
    return 0;

  }

  v->t = ValueString;
  v->v.s = (char *)malloctrace(strlen(buf) + 1);
  strcpy(v->v.s, buf);
  return 1;
}


Bool valconvtoBool(Value *v) {
  Bool b;

  switch (v->t) {

  case ValueInt:
    b = v->v.i != 0;
    break;

  case ValueString:
    if (!strcasecmp(v->v.s, "true")) b = 1;
    else if (!strcasecmp(v->v.s, "false")) b = 0;
    else if (!strcasecmp(v->v.s, "on")) b = 1;
    else if (!strcasecmp(v->v.s, "off")) b = 0;
    else return 0;
    freetrace(v->v.s);
    break;
    
  case ValueDouble:
    b = v->v.d != 0.0;
    break;

  case ValueBool:
    return 1;

  default:
    return 0;

  }

  v->t = ValueBool;
  v->v.b = b;
  return 1;
}


Bool valconvtoDouble(Value *v) {
  char *check;
  double d;
  
  switch (v->t) {
    
  case ValueInt:
    d = v->v.i;
    break;

  case ValueDouble:
    return 1;

  case ValueString:
    d = strtod(v->v.s, &check);
    if (*check) return 0;
    freetrace(v->v.s);
    break;

  case ValueBool:
    d = v->v.b != 0;
    break;

  case ValueIntList:
    if (v->v.il[0] < 0 || v->v.il[1] >= 0) return 0;
    d = v->v.il[0];
    freetrace(v->v.il);
    break;

  default:
    return 0;
    
  }

  v->t = ValueDouble;
  v->v.d = d;
  return 1;
}


int *addtoendofintlist(int *list, int it, int siz) {
  ++siz;
  list = (int *)realloctrace(list, (siz + 1) * sizeof(int));
  list[siz] = -1;
  list[siz-1] = it;
  return list;
}

Bool valconvtoIntList(Value *v) {
  int *list = (int *)malloctrace(sizeof(int));
  int i, siz = 0;
  char *c;
  Value *nv;
  list[0] = -1;

  switch (v->t) {

  case ValueDouble:
    v->v.i = v->v.d;
    /* fall through to next case */
    
  case ValueInt:
    if (v->v.i < 0) break;
    list = addtoendofintlist(list, v->v.i, 0);
    siz = 1;
    break;

  case ValueIntList:
    freetrace(list);
    return 1;

  case ValueString:
    c = v->v.s;
    siz = 0;
    while (*c) {
      char *result;
      i = strtol(c, &result, 0);
      if (result == c) {
	freetrace(list);
	return 0;
      }
      list = addtoendofintlist(list, i, siz);
      siz++;
      c = result;
      while (isspace(*c) || *c == ',') c++;
    }
    freetrace(v->v.s);
    break;

  default:
    freetrace(list);
    return 0;

  }
  
  v->t = ValueIntList;
  v->v.il = list;
  return 1;
}


void freeinternalvaluestorage(Value *v) {
  if (v->t == ValueString && v->v.s) freetrace(v->v.s);
  if (v->t == ValueIntList && v->v.il) freetrace(v->v.il);
  v->t = ValueEmpty;
}

void valuecpy(Value *v1, Value *v2) {
  memcpy(v1, v2, sizeof(Value));
}


void intlistConcat(Value *v, int i) {
  int siz, *trav;
  if (v->t != ValueIntList || i < 0) return;
  for (siz = 0, trav = v->v.il; *trav >= 0; trav++)
    if (*trav == i) return;
    else siz++;
  v->v.il = (int *)realloctrace(v->v.il, sizeof(int) * (siz + 2));
  v->v.il[siz] = i;
  v->v.il[siz+1] = -1;
  return;
}
