//-----------------------------------------------------------------------------
//
//  Peter Richter (prichter@princeton.edu)
//  Princeton Plasma Physics Laboratory
//  August 2000
//
//  table.cpp - Implementation of table management procedures.
//
//-----------------------------------------------------------------------------
 
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
#include <string.h>
#include "preact/util.h"
#include "preact/fortran.h"
 
using namespace std ;

#define N 180
 
//-----------------------------------------------------------------------------
 
void getParamFileName(char *pf, char *str)
{
  int i, j, ierr;
  char ptr[N];
 
  // (MPI change DMC Nov 2008) strcpy(ptr, getenv("PREACTDIR"));
  F77NAME(cmpi_sget_env)("PREACTDIR", ptr, &ierr);
  strcat(ptr, "/tables/");
  for (i = 0; i < strlen(ptr); i++)
    pf[i] = ptr[i];
  j = i;
  for (i = 0; i < strlen(str); i++)
    pf[j++] = str[i];
 
  // CAL: this does not work:
  //for (i = strlen(pf) - 1; pf[i] != '/'; i--)
  //pf[i] = '\0';
  pf[j] = '\0';
  for (i = j; pf[i] != '/'; i--)
    pf[i] = '\0';
  strcat(pf, "tableParameters");
 
}
 
//-----------------------------------------------------------------------------
 
int identicalParameters(char *buf, char *prevTable, int *p)
{
  char *ptr;
  int i, c, match = TRUE;
  if (buf[strlen(buf)- 1] == '*')
    ptr = buf + strlen(buf) - 2;
  else
    ptr = buf + strlen(buf);
  c = (p[4] == -1) ? 4 : 8;
  for (i = c - 1; i >= 0; i--) {
    *ptr = '\0';
    while (*(--ptr) != ' ') ;
    if ( (atoi(ptr + 1)) != p[i])
      match = FALSE;
  }
  *ptr = '\0';
  strcpy(prevTable, buf);
  return match;
}
 
//-----------------------------------------------------------------------------
 
void getArrayFromInt(char *buf, int n)
{
  // assume n > 0
 
  int i, j;
  buf[N - 1] = '\0';
  for (i = N - 2; n > 0; n /= 10, i--)
    buf[i] = (n % 10) + '0';
  for (j = 0; j < N - (i + 1); j++)
    buf[j] = buf[(i + 1) + j];
}
 
//-----------------------------------------------------------------------------
 
void updateCurrentTable(char *prevTable, char *table, char *paramFile)
{
  fstream f;
  ifstream fin;
  int n = 0;
  char buf[100 * N];
  fin.open(paramFile, ios :: in);
  while (fin.getline(buf + n, N)) {
    if (!strncmp(buf + n, prevTable, strlen(prevTable))) {
      n += strlen(buf + n) + 1;
      if (buf[n - 2] != '*') {
	n += 2;
	strcpy(buf + n - 3, " *");
      }
      strcpy(buf + n - 1, "\n");
    }
    else if (!strncmp(buf + n, table, strlen(table))) {
      n += strlen(buf + n) + 1;
      if (buf[n - 2] == '*')
	n -= 2;
      strcpy(buf + n - 1, "\n");
    }
    else {
      n += strlen(buf + n) + 1;
      strcpy(buf + n - 1, "\n");
    }
  }
  fin.close();
  f.open(paramFile, ios :: trunc | ios :: out);
  f << buf;
  f.close();
}
 
//-----------------------------------------------------------------------------
 
void addCurrentTable(char *newTable, char *table, char *paramFile, int *p)
{
  int c;
  fstream f;
  ifstream fin;
  int n = 0;
  char buf[100 * N];
  fin.open(paramFile, ios :: in);
  while (fin.getline(buf + n, N)) {
    if (!strncmp(buf + n, table, strlen(table))) {
      n += strlen(buf + n) + 1;
      if (buf[n - 2] == '*')
	n -= 2;
      strcpy(buf + n - 1, "\n");
    }
    else {
      n += strlen(buf + n) + 1;
      strcpy(buf + n - 1, "\n");
    }
  }
  fin.close();
  f.open(paramFile, ios :: trunc | ios :: out);
  f << buf;
  f << newTable;
  c = (p[4] == -1) ? 4 : 8;
  for (int i = 0; i < c; i++)
    f << ' ' << p[i];
  f << " *\n";
  f.close();
}
 
//-----------------------------------------------------------------------------
 
void maptable(char rootdir[], char table[], char pathname[])
{
  // table    - path prefix to new table from $PREACTDIR/tables/,
  //            e.g. 'cx/cxtabl/coldTarget'  <- terminating integer omitted.
  // pathname - full pathname to currently active table
 
  char paramFile[N], tablf[N], buf[N], flag;
  ifstream pfile;
 
  strcpy(tablf, rootdir);
  strcat(tablf, table);
 
  getParamFileName(paramFile, tablf);
  pfile.open(paramFile);
  if ( ! pfile ) {
    cerr << "?maptable: can not open " << paramFile << endl;
  }
  strcpy(pathname, "");
  flag = 'x';
  while(pfile.getline(buf, N)) {
    if (!strncmp(buf, tablf, strlen(tablf)) && buf[strlen(buf) - 1] == '*') {
      int i,ierr;
 
      // (MPI change DMC Nov 2008) strcpy(pathname, getenv("PREACTDIR"));
      F77NAME(cmpi_sget_env)("PREACTDIR", pathname, &ierr);
      strcat(pathname, "/tables/");
      for (i = 0; buf[i] != ' '; i++) ;
      buf[i] = '\0';
      strcat(pathname, buf);
      flag = 'o';
      break;
    }
  }
  if ( flag == 'x' ) {
    cerr << "?maptable: " << table << " no match in:" << endl;
    cerr << "   " << paramFile << endl;
  }
  pfile.close();
}
 
//-----------------------------------------------------------------------------
 
void addtable(char table[], fp_64 parameters[])
{
  // table      - path prefix to new table from $PREACTDIR/tables/,
  //              e.g. 'cx/cxtabl/coldTarget'  <- terminating integer omitted.
  // parameters - parameters for new table, e.g. Emin, Emax, ...
 
  char paramFile[N], buf[N];
  char prevTable[N], newTable[N];
  ifstream pfile;
  int n, iflag, ii;
  int iparams[8];
 
  // convert parameters to integer form
 
  cout << table << endl;
 
  // (debug)  cout << table << endl;
  iflag=0;
  for ( ii=0; ii<8; ii++ ) {
    if ( parameters[ii] < 0 ) iflag=1;
    if ( iflag == 1 ) {
      iparams[ii] = -1;
    }
    else {
      if ( ii == 0 || ii == 4 ) {
	iparams[ii] = int( 10000.000001 * parameters[ii] );
      }
      else {
	iparams[ii] = int( 1.0000000001 * parameters[ii] );
      }
    }
    // (debug)
    cout << iparams[ii] << endl;
  }
 
  // check to see if table with same parameters already exists
  getParamFileName(paramFile, table);
  pfile.open(paramFile);
  strcpy(prevTable, "");
  while (pfile.getline(buf, N)) {
    if (!strncmp(buf, table, strlen(table))) {
      if (identicalParameters(buf, prevTable, iparams)) {
	updateCurrentTable(prevTable, table, paramFile);
	pfile.close();
        return;
      }
    }
  }
  pfile.close();
 
  // make new table entry with specified parameters
  if (!strcmp(prevTable, "")) {
    strcpy(newTable, table);
    strcat(newTable, "0");
  }
  else {
    n = atoi(prevTable + strlen(table)) + 1;
    getArrayFromInt(buf, n);
    strcpy(newTable, table);
    strcat(newTable, buf);
  }
  cout << endl << newTable;
  addCurrentTable(newTable, table, paramFile, iparams);
}
 
//-----------------------------------------------------------------------------
 
void getparam(char table[], fp_64 parameters[])
{
  // table      - path prefix to table from $PREACTDIR/tables/,
  //              e.g. 'cx/cxtabl/coldTarget'  <- terminating integer omitted.
  // parameters - table parameters, e.g. Emin, Emax, ...
 
  char paramFile[N], buf[N];
  int iparams[8], iflag, ii;
  ifstream pfile;
 
  getParamFileName(paramFile, table);
  pfile.open(paramFile);
  if ( ! pfile ) {
    cerr << "?getparam: can not open" << paramFile << endl;
  }
  while(pfile.getline(buf, N)) {
    if (!strncmp(buf, table, strlen(table)) && buf[strlen(buf) - 1] == '*') {
      int i, j = strlen(buf) - 2;
      for (i = 7; ; i--) {
	buf[j] = '\0';
	while (j > 0 && buf[--j] != ' ') ;
	if (j == 0)
	  break;
	iparams[i] = atoi(buf + j + 1);
      }
      iflag = 8;
      if (i == 3) {
	for (j = 0; j < 4; j++)
	  iparams[j] = iparams[4 + j];
	iparams[j] = -1;
	iflag = 4;
      }
      break;
    }
  }
  pfile.close();
 
  // convert integer form to fp_64 form
 
  for (ii = 0; ii < 8; ii++) {
    if ( ii > iflag ) {
      parameters[ii] = -1;
    }
    else {
      if ( ii == 0 || ii == 4 ) {
	parameters[ii] = iparams[ii]*0.0001;
      }
      else {
	parameters[ii] = iparams[ii];
      }
    }
  }
}
 
//-----------------------------------------------------------------------------
 
void table_errchk(fp_64 x[], fp_64 f[], int n, char xlbl[],
		  range& xrange, int& warn, int& halt)
{
  int under = 0, over = 0;
 
  for (int i=0; i < n; i++) {
    if (x[i] < xrange.minimum ) {
      if ( xrange.min_policy == IGNORE_CLEAR ||
	   xrange.min_policy == WARN_CLEAR )    f[i] = double(0);
      if ( xrange.min_policy != IGNORE &&
	   xrange.min_policy != IGNORE_CLEAR )  under++;
    }
    if (x[i] > xrange.maximum ) {
      if ( xrange.max_policy == IGNORE_CLEAR ||
	   xrange.max_policy == WARN_CLEAR )    f[i] = double(0);
      if ( xrange.min_policy != IGNORE &&
	   xrange.min_policy != IGNORE_CLEAR )  over++;
    }
  }
  if ( under > 0 ) {
    warn = TRUE;
    if( xrange.min_policy == HALT )  halt = TRUE;
    cerr << under << " out-of-range low value(s) in "
         << xlbl << " interpolation." << endl;
    cerr << " table minimum " << xlbl << " is: " << xrange.minimum << endl;
  }
  if ( over > 0 ) {
    warn = TRUE;
    if( xrange.max_policy == HALT )  halt = TRUE;
    cerr << over << " out-of-range high value(s) in "
         << xlbl << " interpolation." << endl;
    cerr << " table maximum " << xlbl << " is: " << xrange.maximum << endl;
  }
}
 
//-----------------------------------------------------------------------------
