#include "persifs.h"
#include <nfs3_prot.h>

nfstime3 nfstime()
{
  struct timeval tv;
  gettimeofday(&tv, (struct timezone *) 0);
  nfstime3 t;
  t.seconds = tv.tv_sec;
  t.nseconds = tv.tv_usec * 1000;
  return t;
}

cbe fatalCB = fatalCBMsg("Generic error");

// Descriptions of status values
static struct 
{
  pStat stat;
  str description;
} statuses[] = {
  {PERR_IO, "I/O error"},
  {PERR_INVAL, "Invalid arguments"},
  {PERR_NOENT, "No such entry"},
  {PERR_EXISTS, "Entry already exists"},
  {PERR_NOTDIR, "Not a directory"},
  {PERR_INTERNAL, "Internal error"},
  // POK must be the last entry
  {POK, "No error"},
};

static void
fatalCBHandler(str msg, pStat stat)
{
  str description("Unknown error status");

  // Find the status message
  int i = 0;
  do {
    if (statuses[i].stat == stat) {
      description = statuses[i].description;
      break;
    }
  } while (statuses[i++].stat != POK);

  // Output the message
  fatal << msg << " (" << description << ")";
}

cbe
fatalCBMsg(str msg)
{
  return wrap(fatalCBHandler, msg);
}

void
_trace(const char *file, int line)
{
#if ENABLE_TRACES
  warn << "TRACE: " << file << ":" << line << "\n";
#endif
}

str
debug_unparseStr(str in)
{
  const char *cstr = in.cstr();
  strbuf buf;

  for (unsigned int i = 0; i < in.len(); ++i) {
    if (isprint(cstr[i]))
      buf << str(&cstr[i], 1);
    else if (cstr[i] == '\n')
      buf << "\\n";
    else if (cstr[i] == '\r')
      buf << "\\r";
    else
      buf.fmt("\\%2.2xx", cstr[i]);
  }

  return str(buf);
}

str
debug_fh2hex(nfs_fh3 fh)
{
  char buf[64];
  unsigned int len = fh.data.size();
  char *p = fh.data.base();
  unsigned int i;

  buf[0] = '\0';
  for(i = 0; i < len && i*2+1 < sizeof(buf); i++){
    sprintf(buf + (i * 2), "%02x", p[i] & 0xff);
  }
  
  return str(buf);
}
