// ConfigFile.h
// Class for reading named values from configuration files
// Richard J. Wagner  v2.1  24 May 2004  wagnerr@umich.edu

// Copyright (c) 2004 Richard J. Wagner
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// Typical usage
// -------------
//
// Given a configuration file "settings.inp":
//   atoms  = 25
//   length = 8.0  # nanometers
//   name = Reece Surcher
//
// Named values are read in various ways, with or without default values:
//   ConfigFile config ("settings.inp");
//   int atoms = config.read<int>( "atoms");
//   double length = config.read ("length", 10.0);
//   string author, title;
//   config.readInto (author, "name");
//   config.readInto (title, "title", string("Untitled"));
//
// See file example.cpp for more examples.

#ifndef CONFIGFILE_H
#define CONFIGFILE_H

#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <sstream>

using std::string;

class ConfigFile {
// Data
protected:
  string                  myDelimiter;  // separator between key and value
  string                  myComment;    // separator between value and comments
  string                  mySentry;     // optional string to signal end of file
  std::map<string,string> myContents;   // extracted keys and values

  typedef std::map<string,string>::iterator mapi;
  typedef std::map<string,string>::const_iterator mapci;

// Methods
public:
  ConfigFile (string filename,
              string delimiter = "=",
              string comment = "#",
              string sentry = "EndConfigFile");
  ConfigFile();

  // Search for key and read value or optional default value
  template<class T> T     read (const string& key) const;  // call as read<T>
  template<class T> T     read (const string& key, const T& value) const;
  template<class T> bool  readInto (T& var, const string& key) const;
  template<class T> bool  readInto (T& var, const string& key, const T& value) const;

  // Modify keys and values
  template<class T> void  add (string key, const T& value);
  void                    remove (const string& key);

  // Check whether key exists in configuration
  bool keyExists (const string& key) const;

  // Check or change configuration syntax
  string getDelimiter() const { return myDelimiter; }
  string getComment() const { return myComment; }
  string getSentry() const { return mySentry; }
  string setDelimiter (const string& s)
    { string old = myDelimiter;  myDelimiter = s;  return old; }
  string setComment (const string& s)
    { string old = myComment;  myComment = s;  return old; }

  // Write or read configuration
  friend std::ostream& operator<<(std::ostream& os, const ConfigFile& cf);
  friend std::istream& operator>>(std::istream& is, ConfigFile& cf);

protected:
  template<class T> static string T_as_string (const T& t);
  template<class T> static T      string_as_T (const string& s);
  static void                     trim (string& s);


// Exception types
public:
  struct file_not_found {
    string filename;
    file_not_found (const string& filename_ = string())
      : filename(filename_) {} };
  struct key_not_found {  // thrown only by T read(key) variant of read()
    string key;
    key_not_found (const string& key_ = string())
      : key(key_) {} };
};


/* static */
template<class T>
string ConfigFile::T_as_string (const T& t)
{
  // Convert from a T to a string
  // Type T must support << operator
  std::ostringstream ost;

  ost << t;
  return ost.str();
}


/* static */
template<class T>
T ConfigFile::string_as_T (const string& s)
{
  // Convert from a string to a T
  // Type T must support >> operator
  T t;
  std::istringstream ist (s);

  ist >> t;
  return t;
}


/* static */
template<>
inline string ConfigFile::string_as_T<string>(const string& s)
{
  // Convert from a string to a string
  // In other words, do nothing
  return s;
}


/* static */
template<>
inline bool ConfigFile::string_as_T<bool>(const string& s)
{
  // Convert from a string to a bool
  // Interpret "false", "F", "no", "n", "0" as false
  // Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true
  bool b = true;
  string sup = s;

  for (string::iterator p = sup.begin();  p != sup.end();  ++p)
    *p = toupper (*p);  // make string all caps
  if (    sup==string ("FALSE")  ||  sup==string ("F")
      ||  sup==string ("NO")  ||  sup==string ("N")
      ||  sup==string ("0")  ||  sup==string ("NONE"))
    b = false;
  return b;
}


template<class T>
T ConfigFile::read (const string& key) const
{
  // Read the value corresponding to key
  mapci p = myContents.find (key);
  if (p == myContents.end()) throw key_not_found (key);
  return string_as_T<T>(p->second);
}


template<class T>
T ConfigFile::read (const string& key, const T& value) const
{
  // Return the value corresponding to key or given default value
  // if key is not found
  mapci p = myContents.find (key);
  if (p == myContents.end()) return value;
  return string_as_T<T>(p->second);
}


template<class T>
bool ConfigFile::readInto (T& var, const string& key) const
{
  // Get the value corresponding to key and store in var
  // Return true if key is found
  // Otherwise leave var untouched
  mapci p = myContents.find (key);
  bool found = (p != myContents.end());

  if (found) var = string_as_T<T>(p->second);
  return found;
}


template<class T>
bool ConfigFile::readInto (T& var, const string& key, const T& value) const
{
  // Get the value corresponding to key and store in var
  // Return true if key is found
  // Otherwise set var to given default
  mapci p = myContents.find (key);
  bool found = (p != myContents.end());

  if (found)
    var = string_as_T<T>(p->second);
  else
    var = value;
  return found;
}


template<class T>
void ConfigFile::add (string key, const T& value)
{
  // Add a key with given value
  string v = T_as_string (value);

  trim (key);
  trim (v);
  myContents[key] = v;
  return;
}

#endif  // CONFIGFILE_H

// Release notes:
// v1.0  21 May 1999
//   + First release
//   + Template read() access only through non-member readConfigFile()
//   + ConfigurationFileBool is only built-in helper class
//
// v2.0  3 May 2002
//   + Shortened name from ConfigurationFile to ConfigFile
//   + Implemented template member functions
//   + Changed default comment separator from % to #
//   + Enabled reading of multiple-line values
//
// v2.1  24 May 2004
//   + Made template specializations inline to avoid compiler-dependent linkage
//   + Allowed comments within multiple-line values
//   + Enabled blank line termination for multiple-line values
//   + Added optional sentry to detect end of configuration file
//   + Rewrote messy trimWhitespace() function as elegant trim()
