#include <stdio.h>
#include "nfs_prot.h"
#include "mp.h"
#define HASHSIZE 99

static int nextinode = 6;
static p_inode *numtab[HASHSIZE];
static p_inode *namtab[HASHSIZE];

/*
 * Verrry simple hash :-)
 */
static unsigned hash(str)
  char *str;
{
  unsigned i = 0, hashval = 3*HASHSIZE/4;

  while(*str)
    {
      i = *str++;
      hashval = (hashval << (i & 7)) + i;
    }

  return hashval % HASHSIZE;
}

/* Get struct with inode */
p_inode *
get_num(i)
  int i;
{
  p_inode *ptr;

  for(ptr = numtab[i % HASHSIZE]; ptr; ptr = ptr->nextnum)
    if(i == ptr->inode)
      break;
  if(!ptr)
    {
      printf("Inode %d not found (aborting)\n", i);
      abort();
    }
  return ptr;
}

p_inode *
newinode(name, inode)
  char *name;
  int inode;
{
  p_inode *ptr;
  int idx = hash(name);

  ptr = (p_inode *)malloc(sizeof(*ptr));
  ptr->name = (char *)strdup(name);
  ptr->inode = inode;

/* insert into both hashtabs */
  ptr->nextnam = namtab[idx];
  namtab[idx] = ptr;

  ptr->nextnum = numtab[inode % HASHSIZE];
  numtab[inode % HASHSIZE] = ptr;

  return ptr;
}

/* Get/create struct with name */
p_inode *
get_nam(name)
  char *name;
{
  p_inode *ptr;
  int idx = hash(name);

  for(ptr = namtab[idx]; ptr; ptr = ptr->nextnam)
    if(!strcmp(name, ptr->name))
      break;
  if (!ptr)
    ptr = newinode(name, nextinode++);
  if (debug > 1)
    printf("\tget_nam(``%s'') returns %08x->inode = %d\n",
           name, (unsigned int)ptr, ptr->inode);
  return ptr;
}

void
inode2fh(inode, fh)
  int inode;
  char *fh;
{
  bzero(fh, NFS_FHSIZE);
  bcopy(&inode, fh, sizeof(inode));
}

int
fh2inode(fh)
  char *fh;
{
  int inode;

  bcopy(fh, &inode, sizeof(inode));
  return inode;
}



/* Rename: the inode must be conserved */
p_inode *
re_nam(old, new)
  char *old, *new;
{
  p_inode *nptr, *optr, **nampp, **numpp;
  int idx = hash(old);

printf("re_nam: %s->%s\n", old, new);
  for(nampp = &namtab[idx]; *nampp; nampp = &(*nampp)->nextnam)
    if(!strcmp(old, (*nampp)->name))
      break;
  if(!*nampp) return get_nam(new);

  optr = *nampp;
printf("re_nam: %d\n", optr->inode);
  *nampp = optr->nextnam;

  /* delete it from the other hashtab too */
  idx = optr->inode % HASHSIZE;
  for(numpp = &numtab[idx]; *numpp; numpp = &(*numpp)->nextnum)
    if(optr == (*numpp))
      break;
  if(!*numpp)
    {
      printf("Entry in one hashtab only (aborting)\n");
      abort();
    }
  *numpp = optr->nextnum;

  nptr = newinode(new, optr->inode);
printf("re_nam: new entry created\n");
  free(optr->name);
  free(optr);

  return nptr;
}

/* Cache routines */
struct cache *
search_cache(root, inode, offset, len)
  struct cache *root;
  unsigned inode, offset, len;
{
  struct cache *cp;

  for(cp = root; cp; cp = cp->next)
    if(cp->inode == inode && cp->offset == offset && cp->len >= len)
      return cp;
  return 0;
}

struct cache *
add_cache(root, inode, offset, len, data, fp)
  struct cache **root;
  unsigned inode, offset, len;
  unsigned char *data;
  fattr *fp;
{
  struct cache *cp;

  cp = (struct cache *)malloc(sizeof(*cp));
  cp->next = *root;
  *root = cp;
  cp->inode = inode;
  cp->offset = offset;
  cp->len = len;
  if(len)
    cp->data = (unsigned char *)malloc(len);
  else
    cp->data = 0;
  bcopy(data, cp->data, len);
  cp->written = cp->actual_size = 0;
  cp->attr = *fp;
  return cp;
}

void
clean_cache(root)
  struct cache **root;
{
  struct cache *act, *next;

  for(act = *root; act; act = next)
    {
      next = act->next;
      if(act->len)
	free(act->data);
      free(act);
    }
  *root = 0;
}

char *
build_path(dir, file)
  char *dir, *file;
{
  static char namebuf[300];

  if(!strcmp(dir, ""))
    strcpy(namebuf, file);
/* FIXME (rom::)*/
  else if(!strcmp(dir, "rom::"))
    sprintf(namebuf, "%s%s", dir, file);
  else
    sprintf(namebuf, "%s\\%s", dir, file);

  return namebuf;
}

int
getpinode(inode)
  p_inode *inode;
{
  char *p;
  int i;

  if(inode->inode == root_fattr.fileid) /* Root inode */
    i = root_fattr.fileid - 1;			/* RUDI !!! */
  else if(!(p = rindex(inode->name, '\\'))) /* device inode */
    i = root_fattr.fileid;
  else
    {
      *p = 0; i = get_nam(inode->name)->inode; *p = '\\';
    }
  return i;
}

/* FIXME (rom::)*/
char *
dirname(dir)
  char *dir;
{
  static char namebuf[300];

  if(!strcmp(dir, "rom::"))
    return dir;
  sprintf(namebuf, "%s\\", dir);
  return namebuf;
}

/* FIXME rom:: */
char *
filname(dir)
  char *dir;
{
  char *p;
  if(!strncmp(dir, "rom::", 5))
    return dir+5;
  if ((p = rindex(dir, '\\')))
    return p+1;
  else return dir;
}
