#ifndef OPTIONS_H
#define OPTIONS_H

#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <algorithm>
#include <cctype>

#include "StrUtils.h"

using std::string;
using std::cout;
using std::endl;
using std::stringstream;
using std::map;
using std::ostream;

namespace FCUtils {

  struct Option {
    Option(): name("error"), val("false"), 
	      help("no description"){};
    Option(
	   const string &n, 
	   const string &v="false", 
	   const string &h="no description")
      : name(ToLower(n)), val(v), help("-"+ToLower(n)+" : "+h){};
    Option(const char *n,
	 const char *v="false", 
	   const char *h="no description")
      : name(ToLower(n)), val(v){ SetHelp(h); }
    
    void SetHelp(const string &h){help="-"+name+" : "+h;}
    void SetHelp(const char *h){SetHelp(string(h));}
    
    void Help() const { cout << help << endl; }
    void Print() const { 
      cout << " Option : " << name << ", value : " << val << endl; 
      cout << "          help : " << help << endl;  
    }
    
    void operator >> ( int & v) {
      stringstream temp(val);
      temp >> v;
    }
    
    void operator >> ( float & v) const {
      stringstream temp(val);
      temp >> v;
    }
    
    void operator >> ( double & v) const {
      stringstream temp(val);
      temp >> v;
    }
    
    void operator >> ( bool & v) const {
      stringstream temp(val);
      temp << std::boolalpha;
      temp >> v;
    }
    
    void operator >> ( string & v) const {
      v=val;
    }
    
    string name;
    string val;
    string help; 
    
  }; // struct Option


  typedef map<string, Option > OptMap;
  
  class Options {
    
  public:
    
    static Options * Get();
    
    bool IsOptionDef( const string &name);
    bool IsOptionDef( const char *name){
      return IsOptionDef( string(name));
    }
    
    void SetOption(const string &name, 
		   const string &val="false", 
		   const string &help="No description")
    { options_[ToLower(name)] = Option(name,val,help); }
    
    void SetOption(const char *name, 
		   const char *val="false", 
		   const char *help="No description")
    { SetOption(string(name),val,help); }
    
    bool UpdateOption( const string &name, const string &val);
    bool UpdateOption( const char *name, const char *val){
      return UpdateOption(string(name),val);
    }
    
    //Option const & GetOption(string const &name);    
    Option & GetOption(string const &name);
    
    Option & operator[] ( string const & name) { return options_[name]; }
    void Help() const;
    void Print() const;
    
  private:
    static Options * instance_;
    OptMap options_;
    Option error_;
    
    Options(); 
    
  }; // class Options
  
}; // namespace FCUtils
#endif // OPTIONS_H
