/*-------------------------------------------------------------------------
    Implementation file for translation table.
    
    Mark Koennecke, October 1997
  
    copyright: see copyright.h
---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "table.h"

/*-------------------------------------------------------------------------*/
typedef struct __SicsTable {
  float *fVal1;
  float *fVal2;
  int iLength;
} STable;
/*-------------------------------------------------------------------------*/
pSTable CreateTable(FILE * fd)
{
  pSTable pNew = NULL;
  long lStart, lEnd, lData, i;
  char *pBuffer = NULL, *pEnd = NULL, *pEndLine, *pPtr;
  int iLength, iRet;
  float fVal1, fVal2;

  assert(fd);

  /* find length of file, create a buffer and read it in */
  lStart = ftell(fd);
  fseek(fd, 0L, SEEK_END);
  lEnd = ftell(fd);
  lData = lEnd - lStart;
  pBuffer = (char *) malloc(lData * sizeof(char));
  if (!pBuffer) {
    return NULL;
  }
  fseek(fd, lStart, SEEK_SET);
  fread(pBuffer, sizeof(char), lData, fd);

  /* find number of lines */
  for (i = 0, iLength = 0; i < lData; i++) {
    if (pBuffer[i] == '\n') {
      iLength++;
    }
  }

  /* allocate the table structure */
  pNew = (pSTable) malloc(sizeof(STable));
  if (!pNew) {
    free(pBuffer);
    return NULL;
  }
  pNew->iLength = iLength;
  pNew->fVal1 = (float *) malloc(sizeof(float) * iLength);
  pNew->fVal2 = (float *) malloc(sizeof(float) * iLength);
  if ((!pNew->fVal1) || (!pNew->fVal2)) {
    free(pBuffer);
    free(pNew);
    return NULL;
  }
  memset(pNew->fVal1, 0, iLength * sizeof(float));
  memset(pNew->fVal2, 0, iLength * sizeof(float));

  /* dodge through the file reading pairs until end */
  pPtr = pBuffer;
  pEnd = pBuffer + lData;
  pEndLine = pBuffer;
  i = 0;
  while (pEndLine < pEnd) {
    if (*pEndLine == '\n') {
      *pEndLine = '\0';
      iRet = sscanf(pPtr, "%f %f", &fVal1, &fVal2);
      if (iRet == 2) {
        pNew->fVal1[i] = fVal1;
        pNew->fVal2[i] = fVal2;
        i++;
      }
      pEndLine++;
      pPtr = pEndLine;
    } else {
      pEndLine++;
    }
  }

  free(pBuffer);
  return pNew;
}

/*--------------------------------------------------------------------------*/
void DeleteTable(pSTable self)
{
  if (self->fVal1) {
    free(self->fVal1);
  }
  if (self->fVal2) {
    free(self->fVal2);
  }
  free(self);
}

/*--------------------------------------------------------------------------*/
int InterpolateVal1(pSTable self, float fKey, float *fResult)
{
  float fFrac;
  int i1, i;

  assert(self);
  assert(self->fVal1);
  assert(self->fVal2);

  /* search the entry point */
  for (i = 0; i < self->iLength; i++) {
    if (self->fVal1[i] >= fKey) {
      i1 = i;
      break;
    }
  }
  if (i1 >= self->iLength) {
    return 0;
  }

  /* interpolate */
  fFrac = (fKey - self->fVal1[i1 - 1])
      / (self->fVal1[i1] - self->fVal1[i1 - 1]);
  *fResult = self->fVal2[i1 - 1]
      + fFrac * (self->fVal2[i1] - self->fVal2[i1 - 1]);
  return 1;
}

/*---------------------------------------------------------------------------*/
int InterpolateVal2(pSTable self, float fKey, float *fResult)
{
  float fFrac;
  int i1, i;

  assert(self);
  assert(self->fVal1);
  assert(self->fVal2);

  /* search the entry point */
  for (i = 0; i < self->iLength; i++) {
    if (self->fVal2[i] <= fKey) {
      i1 = i;
      break;
    }
  }
  if (i1 >= self->iLength) {
    return 0;
  }

  /* interpolate */
  fFrac = (fKey - self->fVal2[i1 - 1])
      / (self->fVal2[i1] - self->fVal2[i1 - 1]);
  *fResult = self->fVal1[i1 - 1]
      + fFrac * (self->fVal1[i1] - self->fVal1[i1 - 1]);
  return 1;
}
