#ifndef INCLUDED_MODBASE_
#define INCLUDED_MODBASE_

#include <iomanip>
#include <unordered_map>

#include "../err/err.h"
#include "../typedefs/typedefs.h"
#include "../specificity/specificity.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();

        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;
        double 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 costHandler(StringVect &keywords);         // sets "costs:"
        void specificityHandler(SpecificityVect &dest,  // sets "specificity:"
                                StringVect &keywords);

        void doubleHandler(double *dest, StringVect const &keywords,
                           bool  (*proportionCheck)
                                 (double const *, unsigned) = 0);

        static void insertBirads(std::ostream &out, char const *label, 
                                 double const *value);
        static void insertSpecificity(std::ostream &out, unsigned fill,
                                      SpecificityVect const &value);

    private:
        virtual double 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;

        static void outSpec(std::ostream &out, char const *prefix, 
                            unsigned fill, Specificity 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 double 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::roundHeader(std::ostream &out) const
//{
//    out << ", #" << d_id;
//}    

#endif

