// (C) 2002 Jasper Bedaux, ITFA, University of Amsterdam
// http://www.bedaux.net/jasper/
// C++ template to read parameters from input file

#ifndef READ_PARMS_H
#define READ_PARMS_H

#include <fstream>
#include <sstream>
#include <string>
#include <vector>

// tries to read value, on fail throws string with error description
template <typename T>
T readValue(const char* filename, const char* parameter,
    int position = 0) throw (std::string) {
  T value;
  std::ifstream in(filename, std::ios::in);
  if (!in) throw std::string("unable to open '") + filename + "' for input";
  std::string line;
  while (std::getline(in, line)) {
    std::istringstream is(line);
    std::string s;
    is >> s; // read first string from line
    if (s == std::string(parameter)) { // parameter found
// skip strings untill right position is reached
      for (int i = 0; i < position; ++i) is >> s;
      is >> value; // now try to read the desired value
      if (is.fail())
        throw std::string("error reading '") + parameter + "' from '" + filename + "'";
      return value;
    }
  }
  throw std::string("parameter '") + parameter + "' not found in '" + filename + "'";
}

// returns default value instead of throwing exception when not found or on error
template <typename T>
T readValue(T value, const char* filename, const char* parameter,
    int position = 0) {
  T t;
  try { t = readValue<T>(filename, parameter, position); }
  catch (std::string&) { t = value; } // on error set to default
  return t;
}

// return vector with range of values from start to end
template <typename T>
std::vector<T> readRange(const char* filename, const char* parameter, int size) {
  std::vector<T> range(size);
  range[0] = readValue<T>(filename, parameter); // first value
  range[size - 1] = readValue<T>(range[0], filename, parameter, 1); // last
  for (int i = 1; i < size - 1; ++i) {
    double value = range[0] + (static_cast<double>(i) / (size - 1.)) *
      (range[size - 1] - range[0]);
    range[i] = static_cast<T>(value);
// for int type values, round instead of truncate
    if ((value - range[i]) > .5) ++range[i];
    else if ((value - range[i]) < -.5) --range[i];
  }
  return range;
}

// same, but with default value
template <typename T>
std::vector<T> readRange(T value, const char* filename, const char* parameter, int size) {
  std::vector<T> range(size);
  try { range = readRange<T>(filename, parameter, size); }
  catch (std::string&) { range = std::vector<T>(size, value); } // default
  return range;
}

#endif // READ_PARMS_H