#ifndef INCLUDED_BOBCAT_CONFIGFILE_
#define INCLUDED_BOBCAT_CONFIGFILE_

//    Lines are stored with initial WS removed.
//    If a line ends in \, then the next line (initial WS removed)
//    is appended to the current line.
//    Information at and beyond the first # on individual lines is removed
//    if the rmComment flag is set to true
//    Then, lines containing only blanks and tabs are not stored

#include <vector>
#include <string>
#include <iterator>

namespace FBB
{

class RE_iterator: public std::iterator<std::input_iterator_tag, std::string>
{
    friend class ConfigFile_;

    friend int operator-(RE_iterator const &lhs,        // opneg.f
                         RE_iterator const &rhs);

    friend bool operator==(RE_iterator const &lhs, RE_iterator const &rhs);

                            // contains iterators to lines matching REs
    typedef std::vector<std::string>::const_iterator VsIterator;
    typedef std::vector<VsIterator> VsIterVector;

    VsIterVector const &d_vsIter;
    size_t d_idx;

    public:
        RE_iterator &operator++();

        std::string const &operator*() const;           // opstar.f
        std::string const *operator->() const;          // oparrow.f

    private:
        RE_iterator(VsIterVector const &vsIter, size_t idx);
};

struct CFEnums_
{
        typedef RE_iterator const_RE_iterator;
        typedef std::vector<std::string>::const_iterator const_iterator;
        typedef std::pair<const_RE_iterator, const_RE_iterator> 
                                                        RE_iteratorPair;

        enum Comment
        {
            KeepComment,
            RemoveComment
        };
        enum SearchCasing
        {
            SearchCaseSensitive,
            SearchCaseInsensitive
        };

        enum Indices
        {
            IgnoreIndices,
            StoreIndices
        };
};

class ConfigFile_;
class ConfigFile: public CFEnums_
{
    ConfigFile_ *d_ptr;

    public:
        explicit ConfigFile(Comment cType = KeepComment,        // 1
                   SearchCasing sType = SearchCaseSensitive,
                   Indices iType = IgnoreIndices);
                                                        // 2
        explicit ConfigFile(std::string const &fname,   // config file name
                    Comment cType = KeepComment, 
                    SearchCasing sType = SearchCaseSensitive,
                    Indices iType = IgnoreIndices);

        ConfigFile(ConfigFile &&tmp);                   // 3
        ConfigFile(ConfigFile const &rhs);              // 4

        ~ConfigFile();                          

        ConfigFile &operator=(ConfigFile &&tmp);
        ConfigFile &operator=(ConfigFile const &rhs);   // 2

        void open(std::string const &fname);

        void setCommentHandling(Comment type);
        void setSearchCasing(SearchCasing type);

        const_iterator begin() const;
        const_iterator end() const;

        RE_iteratorPair beginEndRE(std::string const &re) const;    // 1
        RE_iteratorPair beginEndRE() const;                         // 2

        const_iterator find(std::string const &target) const;
        const_iterator findRE(std::string const &re) const;

        std::string findKey(std::string const &key, size_t count = 1) const;

        std::string findKeyTail(std::string const &key, 
                                size_t count = 1) const;

        size_t index(size_t lineNr);                        // 1
        size_t index(const_iterator const &iterator);       // 2

        std::string const &operator[](size_t idx) const;

        size_t size() const;
};

#include "opstar.f"
#include "oparrow.f"

    // Free members:

bool operator==(RE_iterator const &lhs, RE_iterator const &rhs);

#include "opneq.f"                  // RE_iterator != RE_iterator
#include "opsub.f"                  // RE_iterator - RE_iterator


} // FBB

#endif











