#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USE_NLLIBC
#include <nllibc.h>
#endif

#include "nlllib.h"
#include "memory.h"
#include "fileid.h"

typedef struct fileid {
  int index;
  FILE *fp;
} *fileid_t;

static fileid_t fileids[FILEID_MAXNUM];
static int fileid_num = 0;

static int id2index(fileid_id_t id)
{
  return id - 1;
}

static fileid_id_t index2id(int index)
{
  return index + 1;
}

int fileid_init(void)
{
  fileid_num = 0;
  memset(fileids, 0, sizeof(fileids));
  return 0;
}

int fileid_done(void)
{
  int i;

  for (i = 0; i < FILEID_MAXNUM; i++) {
    if (fileids[i])
      fileid_destroy(index2id(i));
  }

  return 0;
}

int fileid_check(void)
{
  int i;

  if (fileid_num)
    return NLL_ERRCODE_MEMORY_NOT_EMPTY;

  for (i = 0; i < FILEID_MAXNUM; i++) {
    if (fileids[i])
      return NLL_ERRCODE_MEMORY_NOT_EMPTY;
  }

  return 0;
}

static fileid_t _alloc(void)
{
  fileid_t fileid;
  if ((fileid = memory_alloc(sizeof(*fileid))) == NULL)
    return NULL;
  return fileid;
}

static int _free(fileid_t fileid)
{
  memory_free(fileid);
  return 0;
}

static fileid_t fileid_get(fileid_id_t id)
{
  int index;

  index = id2index(id);

  if ((index < 0) || (index >= FILEID_MAXNUM))
    return NULL;

  return fileids[index];
}

FILE *fileid_get_fp(fileid_id_t id)
{
  fileid_t fileid;

  fileid = fileid_get(id);
  if (!fileid)
    return NULL;

  return fileid->fp;
}

int fileid_set_fp(fileid_id_t id, FILE *fp)
{
  fileid_t fileid;

  fileid = fileid_get(id);
  if (!fileid)
    return -1;

  fileid->fp = fp;

  return 0;
}

int fileid_destroy(fileid_id_t id)
{
  fileid_t fileid;
  int r;

  fileid = fileid_get(id);
  if (!fileid)
    return -1;

  fileids[fileid->index] = NULL;

  if (fileid->fp) fclose(fileid->fp);
  memset(fileid, 0, sizeof(*fileid));

  fileid_num--;
  if ((r = _free(fileid)) < 0)
    return r;

  return 0;
}

fileid_id_t fileid_create(FILE *fp)
{
  int index;
  fileid_t fileid = NULL;

  for (index = 0; index < FILEID_MAXNUM; index++) {
    if (!fileids[index])
      break;
  }
  if (index == FILEID_MAXNUM)
    return -1;

  if ((fileid = _alloc()) == NULL)
    return -1;
  fileid_num++;

  memset(fileid, 0, sizeof(*fileid));
  fileid->index = index;
  fileid->fp = fp;

  fileids[index] = fileid;

  return index2id(index);
}
