#ifndef INCLUDED_MODBASE_
#define INCLUDED_MODBASE_


// see ../modalities/README


#include <iomanip>
#include <unordered_map>

#include "../err/err.h"
#include "../typedefs/typedefs.h"
#include "../agegroupvsd/agegroupvsd.h"

class ModBase
{
    friend std::ostream &operator<<(std::ostream &, ModBase const &);

    std::string const d_id;

    uint16_t d_cost = 0;
    SizeVect d_count;
    uint16_t d_falsePositives;

    public:
        ModBase(std::string const &id);
        virtual ~ModBase();

        void vary(std::ostream &out);            // see Growth::vary()


        double sensitivity(size_t idx) const;
        double specificity(double age) const;
        uint16_t cost() const;
        void resetCounters(size_t nRounds);
        void count(size_t round);
        void falsePositive();
        std::string const &id() const;
        VSDvect const *dose() const;
        double dose(uint16_t idx) const;

//        void roundHeader(std::ostream &out) const;
//        void count(std::ostream &out, size_t round) const;
        
        size_t operator[](size_t round) const;

    protected:
        void costBase(StringVect &keywords);         // sets "costs:"

                                    // ageGroup and specificity 
                                    // sets keywords: [2]: Specificity
                                    //                [3]: ageGroup
        void specificityBase(AgeGroupVSDvect &dest, StringVect &keywords);


        void doseBase(VSDvect &dose, StringVect &keywords);


    private:
        virtual VSDvect const *vDose() const = 0;
        virtual double vDose(uint16_t idx) const = 0;
        virtual void vInsert(std::ostream &out) const = 0;
        virtual double vSensitivity(size_t idx) const = 0;
        virtual double vSpecificity(double age) const = 0;
        virtual void vVary(std::ostream &out) = 0;

        static void outSpec(std::ostream &out, char const *prefix, 
                            unsigned fill, AgeGroupVSD const &spec);
};


inline void ModBase::count(size_t round)
{
    ++d_count[round];
}

inline size_t ModBase::operator[](size_t idx) const
{
    return d_count[idx];
}

//inline void ModBase::count(std::ostream &out, size_t round) const
//{
//    out << ',' << std::setw(7) << d_count[round];
//}

inline uint16_t ModBase::cost() const
{
    return d_cost;
}

inline void ModBase::falsePositive()
{
    ++d_falsePositives;
}

inline std::string const &ModBase::id() const
{
    return d_id;
}

inline VSDvect const *ModBase::dose() const
{
    return vDose();
}

inline double ModBase::dose(uint16_t idx) const
{
    return vDose(idx);
}


inline double ModBase::sensitivity(size_t idx) const
{
    return vSensitivity(idx);
}

inline double ModBase::specificity(double age) const
{
    return vSpecificity(age);
}

inline void ModBase::vary(std::ostream &out)
{
    return vVary(out);
}

//inline void ModBase::roundHeader(std::ostream &out) const
//{
//    out << ", #" << d_id;
//}    

#endif

