
#ifndef AUTIL_CONIFIG_DATA__HH
#define AUTIL_CONIFIG_DATA__HH

#include <string>

#include <pspell/config_impl.hh>

#include "emulation.hh"
#include "exception.hh"

namespace autil {

  typedef PspellMutableContainer MutableContainer;

  typedef PspellKeyInfo          KeyInfo;
  typedef PspellKeyInfoType      KeyInfoType;

  static const KeyInfoType KeyInfoString = PspellKeyInfoString;
  static const KeyInfoType KeyInfoInt    = PspellKeyInfoInt;
  static const KeyInfoType KeyInfoBool   = PspellKeyInfoBool;
  static const KeyInfoType KeyInfoList   = PspellKeyInfoList;

  class ConfigData {
    mutable PspellConfigImpl config_;
  private:
    void throw_exception(const char * key) const;
    void throw_exception(const char * key, const char * value) const; 
    void throw_file_exception(const char * file) const;
   
  public:

    typedef PspellModule   Module;
    typedef PspellNotifier Notifier;

    ConfigData(const char * name,
	       const KeyInfo  * mainbegin, const KeyInfo * mainend) 
      : config_(name, mainbegin, mainend)
    {}
    virtual ~ConfigData() {}
    
    typedef PspellNotifierEmulation                      NotifierVirEmul;
    typedef Emulation<const Notifier *, NotifierVirEmul> NotifierEmul;

    typedef PspellKeyInfoEmulation                   PossibleElementsVirEmul;
    typedef Emulation<const KeyInfo *, PossibleElementsVirEmul>
            PossibleElementsEmul;

    NotifierVirEmul * notifiers() const 
    {
      return config_.notifiers();
    }

    bool add_notifier   (      Notifier * n) 
    {
      return config_.add_notifier(n);
    }
    bool remove_notifier(const Notifier * n) 
    {
      return config_.remove_notifier(n);
    }
    bool replace_notifier(const Notifier * o, Notifier * n) 
    {
      return config_.replace_notifier(o,n);
    }

    void set_modules(const Module * begin, const Module * end)
    {
      config_.set_modules(begin,end);
    }

    void set_extra(const KeyInfo * begin, const KeyInfo * end) 
    {
      config_.set_extra(begin,end);
    }

    const KeyInfo * keyinfo(const char * key) const
    {
      const KeyInfo * temp = config_.keyinfo(key);
      if (temp == 0) throw_exception(key);
      return temp;
    }

    PspellKeyInfoEmulation * possible_elements(bool include_extra = true) const
    {
      return config_.possible_elements(include_extra);
    }

    string get_default(const char * key) const
    {
      const char * temp = config_.get_default(key);
      if (temp == 0) throw_exception(key);
      return temp;
    }

    PspellStringPairEmulation * elements() const
    {
      return config_.elements();
    }

    void replace(const char * key, const char * value)
    {
      if (!config_.replace(key,value))
	throw_exception(key,value);
    }

    virtual bool remove(const char * key) 
    {
      bool temp = config_.remove(key);
      if (!temp && config_.error_number() != 0)
	throw_exception(key);
      return temp;
    }

    bool have(const char * key) const 
    {
      return config_.have(key);
      
    }

    string retrieve (const char * key) const
    {
      const char * temp = config_.retrieve(key);
      if (temp == 0) throw_exception(key);
      return temp;
    }

    void retrieve_list (const char * key, 
			PspellMutableContainer & c) const
    {
      if (!config_.retrieve_list(key, c))
	throw_exception(key);
    }

    bool retrieve_bool(const char * key) const
    {
      int temp = config_.retrieve_bool(key);
      if (temp == -1) throw_exception(key);
      return temp;
    }

    int retrieve_int(const char * key) const
    {
      int temp = config_.retrieve_int(key);
      if (temp == -1) throw_exception(key);
      return temp;
    }

    void write_to_stream(ostream & out) const
    {
      config_.write_to_stream(out);
    }

    void read_in_stream(istream & in) 
    {
      if (!config_.read_in_stream(in))
	throw_exception("");
    }

    void read_in_file(const string & file)
    {
      if (!config_.read_in_file(file.c_str()))
	throw_file_exception(file.c_str());
    }

    void read_in_string(const char * str)
    {
      if (!config_.read_in_string(str))
	throw_exception("");
    }
    
    static const char * base_name(const char * name)
    {
      return PspellConfigImpl::base_name(name);
    }

    void merge(const ConfigData & other) 
    {
      config_.merge(other.config_);
    }

    void set_attached(bool a) 
    {
      config_.set_attached(a);
    }

    bool get_attached() const
    {
      return config_.get_attached();
    }

    PspellConfigImpl & real_config() 
    {
      return config_;
    }
    

  };

  struct UnknownKey : public Exception {
    string key;
    UnknownKey(const char * k, const char * m)
      : Exception(m), key(k) {}
    ~UnknownKey() throw() {}
  };
  
  struct CantChangeValue : public Exception {
    string key;
    CantChangeValue(const char * k, const char * m)
      : Exception(m), key(k) {}
    ~CantChangeValue() throw() {}
  };

}

#endif
