#ifndef INCLUDED_OPTIONS_
#define INCLUDED_OPTIONS_

#include <iosfwd>
#include <string>
#include <unordered_map>

#include "../enums/enums.h"

namespace FBB
{
    class Arg;
}

class Options
{
    enum Specified
    {
        STARTUP,
        ANALYSIS
    };

    FBB::Arg const &d_arg;

    std::string d_home;                 // current 'HOME' directory

    
    std::string d_specified[2];         // specified options: 
                                        // [0]: command-line, [1]: analysis

    bool d_specificAges = false;
    double d_naturalDeathAge;           // single run, subject age
    double d_tumorAge;                  // single run, tumor self-detect age


    size_t d_lastCase;                  // compute until d_lastCase, report
                                        // d_lastCase's results


    std::string d_base[2];              // guaranteed to end in '/'
                                        // [0]: as specified, [1]: as used 
                                        // in Analysis: sections

    std::string d_config[2];            // [0]: as specified, [1]: as used 
                                        // in Analysis: sections

    std::string d_dataFile[2];          // [0]: as specified, [1]: as used
                                        // after replacing + by base 
    std::string d_parametersFile[2];    
    std::string d_roundsFile[2];
    std::string d_sensitivityFile[2];

    std::string d_spreadFile[2];

    static char const s_base[];
    static char const s_config[];
    static std::unordered_map<int, char const *> s_fileName;

    static Options *s_options;

    public:
        static Options &instance();

        Options(Options const &other) = delete;

        void reset();                           // reset options to the
                                                // default/command-line values

        std::string const &base() const;                // .h
        std::string const &configFile() const;          // .h

        std::string const &parametersFile() const;                // .h
        std::string const &dataFile() const;                    // .h
        std::string const &roundsFile() const;                  // .h
        std::string const &sensitivityFile() const;             // .h

        std::string const &spreadFile() const;                  // .h

        bool specificAges() const;                              // .h

        void fixedNaturalDeathAge(double &deathAge) const; 
        void fixedTumorAge(double &tumorAge) const;
        size_t lastCase() const;                                // .h


        void activate();                        // [ANALYSIS] = [STARTUP]

                                                // try to change this option's
                                                // value in this analysis
        bool alter(int optChar, std::string const &value);

        void actualize();                       // transform ~ and +

    private:
        Options();

        void configOption();
        void baseOption();
        void fileOption(std::string *dest, int option); 

        void deathAgeOption(std::string const &value);
        void tumorAgeOption(std::string const &value);
        void lastCaseOption(std::string const &value);

        void deathAge(std::string const &value);
        void lastCase(std::string const &value);
        void tumorAge(std::string const &value);

        void replaceHome(std::string &path);
        void setBase();

            // dest[0]: as specified, dest[1]: as used

//        void setFile(std::string *dest, std::string const &newValue,    // 2
//                                        int option);

            // fname[0]: as specified, fname[1]: as used
        void replacePlus(std::string &fname);

        void conflictCheck() const;
};

inline std::string const &Options::base() const
{
    return d_base[ANALYSIS];
}

inline std::string const &Options::configFile() const
{
    return d_config[ANALYSIS];
}

inline std::string const &Options::parametersFile() const
{
    return d_parametersFile[ANALYSIS];
}

inline std::string const &Options::dataFile() const
{
    return d_dataFile[ANALYSIS];
}

inline std::string const &Options::roundsFile() const
{
    return d_roundsFile[ANALYSIS];
}

inline std::string const &Options::sensitivityFile() const
{
    return d_sensitivityFile[ANALYSIS];
}

inline std::string const &Options::spreadFile() const
{
    return d_spreadFile[ANALYSIS];
}

inline bool Options::specificAges() const
{
    return d_specificAges;
}

inline size_t Options::lastCase() const
{
    return d_lastCase;
}

#endif

