#include "dmemory.h"

#include "cdi.h"
#include "cdi_int.h"

static void
streamvar_init_recordtable(stream_t *streamptr, int varID, int isub)
{
  streamptr->vars[varID].recordTable[isub].nlevs = 0;
  streamptr->vars[varID].recordTable[isub].recordID = NULL;
  streamptr->vars[varID].recordTable[isub].lindex = NULL;
}

static void
streamvar_init_entry(stream_t *streamptr, int varID)
{
  streamptr->vars[varID].ncvarid = CDI_UNDEFID;
  streamptr->vars[varID].defmiss = false;

  streamptr->vars[varID].subtypeSize = 0;
  streamptr->vars[varID].recordTable = NULL;

  streamptr->vars[varID].gridID = CDI_UNDEFID;
  streamptr->vars[varID].zaxisID = CDI_UNDEFID;
  streamptr->vars[varID].tsteptype = CDI_UNDEFID;
  streamptr->vars[varID].subtypeID = CDI_UNDEFID;
}

static int
streamvar_new_entry(stream_t *streamptr)
{
  int varID = 0;
  int streamvarSize = streamptr->varsAllocated;
  svarinfo_t *streamvar = streamptr->vars;
  /*
    Look for a free slot in streamvar.
    (Create the table the first time through).
  */
  if (!streamvarSize)
    {
      streamvarSize = 2;
      streamvar = (svarinfo_t *) Malloc((size_t) streamvarSize * sizeof(svarinfo_t));
      if (streamvar == NULL)
        {
          Message("streamvarSize = %d", streamvarSize);
          SysError("Allocation of svarinfo_t failed");
        }

      for (int i = 0; i < streamvarSize; i++) streamvar[i].isUsed = false;
    }
  else
    {
      while (varID < streamvarSize)
        {
          if (!streamvar[varID].isUsed) break;
          varID++;
        }
    }
  /*
    If the table overflows, double its size.
  */
  if (varID == streamvarSize)
    {
      streamvarSize = 2 * streamvarSize;
      streamvar = (svarinfo_t *) Realloc(streamvar, (size_t) streamvarSize * sizeof(svarinfo_t));
      if (streamvar == NULL)
        {
          Message("streamvarSize = %d", streamvarSize);
          SysError("Reallocation of svarinfo_t failed");
        }
      varID = streamvarSize / 2;

      for (int i = varID; i < streamvarSize; i++) streamvar[i].isUsed = false;
    }

  streamptr->varsAllocated = streamvarSize;
  streamptr->vars = streamvar;

  streamvar_init_entry(streamptr, varID);

  streamptr->vars[varID].isUsed = true;

  return varID;
}

static void
allocate_record_table_entry(stream_t *streamptr, int varID, int subID, int nlevs)
{
  int *level = (int *) Malloc((size_t) nlevs * sizeof(int));
  int *lindex = (int *) Malloc((size_t) nlevs * sizeof(int));

  for (int levID = 0; levID < nlevs; levID++)
    {
      level[levID] = CDI_UNDEFID;
      lindex[levID] = levID;
    }

  streamptr->vars[varID].recordTable[subID].nlevs = nlevs;
  streamptr->vars[varID].recordTable[subID].recordID = level;
  streamptr->vars[varID].recordTable[subID].lindex = lindex;
}

int
stream_new_var(stream_t *streamptr, int gridID, int zaxisID, int tilesetID)
{
  if (CDI_Debug) Message("gridID = %d  zaxisID = %d", gridID, zaxisID);

  int varID = streamvar_new_entry(streamptr);
  int nlevs = zaxisInqSize(zaxisID);

  streamptr->nvars++;

  streamptr->vars[varID].gridID = gridID;
  streamptr->vars[varID].zaxisID = zaxisID;

  int nsub = 1;
  if (tilesetID != CDI_UNDEFID) nsub = subtypeInqSize(tilesetID); /* e.g. no of tiles */
  if (CDI_Debug) Message("varID %d: create %d tiles with %d level(s), zaxisID=%d", varID, nsub, nlevs, zaxisID);
  streamptr->vars[varID].recordTable = (sleveltable_t *) Malloc((size_t) nsub * sizeof(sleveltable_t));
  if (streamptr->vars[varID].recordTable == NULL) SysError("Allocation of leveltable failed!");
  streamptr->vars[varID].subtypeSize = nsub;

  for (int isub = 0; isub < nsub; isub++)
    {
      streamvar_init_recordtable(streamptr, varID, isub);
      allocate_record_table_entry(streamptr, varID, isub, nlevs);
      if (CDI_Debug)
        Message("streamptr->vars[varID].recordTable[isub].recordID[0]=%d", streamptr->vars[varID].recordTable[isub].recordID[0]);
    }

  streamptr->vars[varID].subtypeID = tilesetID;

  return varID;
}
/*
 * Local Variables:
 * c-file-style: "Java"
 * c-basic-offset: 2
 * indent-tabs-mode: nil
 * show-trailing-whitespace: t
 * require-trailing-newline: t
 * End:
 */
