#ifndef INCLUDED_BOBCAT_ARGCONFIG_
#define INCLUDED_BOBCAT_ARGCONFIG_

#include <unordered_map>
#include <string>

#include <bobcat/arg>
#include <bobcat/configfile>

namespace FBB
{

class ArgConfig__;

class ArgConfig: public Arg, public ConfigFile
{
    static ArgConfig            *s_argconfig; // points to Singleton ArgConfig

    ArgConfig__ *d_ptr;

    public:
        static ArgConfig &initialize(char const *optstring,             // 1
            int argc, char **argv,
            Comment cType = KeepComment, 
            SearchCasing sType = SearchCaseSensitive,
            Indices iType = IgnoreIndices);

        static ArgConfig &initialize(char const *optstring,             // 2
            int argc, char **argv, std::string const &fname,    
            Comment cType = KeepComment, 
            SearchCasing sType = SearchCaseSensitive,
            Indices iType = IgnoreIndices);

        static ArgConfig &initialize(char const *optstring,             // 3
            LongOption const *const begin, LongOption const *const end,
            int argc, char **argv, Comment cType = KeepComment, 
            SearchCasing sType = SearchCaseSensitive,
            Indices iType = IgnoreIndices);

        static ArgConfig &initialize(char const *optstring,             // 4
            LongOption const *const begin, LongOption const *const end,
            int argc, char **argv, std::string const &fname,
            Comment cType = KeepComment, 
            SearchCasing sType = SearchCaseSensitive,
            Indices iType = IgnoreIndices);

        static ArgConfig &instance();        

        size_t option(int option);                                       // 1
        size_t option(std::string const &optchars);                      // 2
        size_t option(std::string *value, int optChar);                  // 3
        size_t option(std::string *value, char const *longOption);       // 4

        size_t option(size_t idx,                               
                        std::string *value, int option) const;  
        size_t option(size_t *idx, 
                        std::string *value, int option) const;  
        size_t option(size_t idx, std::string *value, 
                        char const *longOption) const;          
        size_t option(size_t *idx, std::string *value, 
                char const *longOption) const;                  

        char const *operator[](size_t idx) const;           // Arg's []
        std::string const &line(size_t idx) const;          // ConfigFile's []

    private:
        ArgConfig(ArgConfig const &other) = delete;
        ArgConfig &operator=(ArgConfig const &other) = delete;

                                                                
        ArgConfig(char const *optstring,                        // 1
            int argc, char **argv,
            Comment cType = KeepComment, 
            SearchCasing sType = SearchCaseSensitive,
            Indices iType = IgnoreIndices);

        ArgConfig(char const *optstring,                        // 2
            int argc, char **argv, std::string const &fname,    
            Comment cType = KeepComment, 
            SearchCasing sType = SearchCaseSensitive,
            Indices iType = IgnoreIndices);

        ArgConfig(char const *optstring,                        // 3
            LongOption const *begin, LongOption const *const end,
            int argc, char **argv, Comment cType = KeepComment, 
            SearchCasing sType = SearchCaseSensitive,
            Indices iType = IgnoreIndices);

        ArgConfig(char const *optstring,                        // 4
            LongOption const *begin, LongOption const *const end,
            int argc, char **argv, std::string const &fname,
            Comment cType = KeepComment, 
            SearchCasing sType = SearchCaseSensitive,
            Indices iType = IgnoreIndices);

        RE_iteratorPair findLongOption(int optChar);
        RE_iteratorPair longConfigOpt(std::string const &longOpt);
};

inline size_t ArgConfig::option(size_t idx, std::string *value, 
                                                    int optChar) const
{
    return Arg::option(idx, value, optChar);
}

inline size_t ArgConfig::option(size_t *idx, std::string *value, 
                                                    int optChar) const
{
    return Arg::option(idx, value, optChar);
}

inline size_t ArgConfig::option(size_t idx, std::string *value, 
                                            char const *longOption) const
{
    return Arg::option(idx, value, longOption);
}

inline size_t ArgConfig::option(size_t *idx, std::string *value, 
                                            char const *longOpt) const
{
    return Arg::option(idx, value, longOpt);
}

inline char const *ArgConfig::operator[](size_t idx) const
{
    return Arg::operator[](idx);
}

inline std::string const &ArgConfig::line(size_t idx) const
{
    return ConfigFile::operator[](idx);
}

} // FBB

#endif

