#ifndef INCLUDED_DENSITY_
#define INCLUDED_DENSITY_

#include <iosfwd>
#include <vector>
#include <cstdint>

#include "../agegroup/agegroup.h"
#include "../enums/enums.h"
#include "../globals/globals.h"

// BreastDensities:
// 
//     #                bi-rad:  a      b      c      d
//     ageGroup:    0  - 40:    .05    .30    .48    .17

class Density
{
    enum 
    {
        N_BIRADS = 4,   // bi-rad categories (cf. tech man. section Densities)
    };

    friend std::istream &operator>>(std::istream &in, Density &density);
    friend std::ostream &operator<<(std::ostream &out, Density const &density);

    AgeGroup    d_ageGroup;

    std::vector<double> d_birad;
    std::vector<double> d_cumBirads;

    public:
        Density();
        uint16_t  beginAge() const;
        uint16_t  endAge() const;
        double    birad(size_t idx) const;

        AgeGroup const &ageGroup() const;

        bool contains(double age) const;                            // .ih
        uint16_t indexOf(double prob) const;

        std::vector<double> const &birad() const;
        bool sumOne() const;

    private:
        std::istream &extract(std::istream &in);
        std::ostream &insert(std::ostream &out) const;
};

typedef std::vector<Density> DensityVect;   // ensure sorted by end-age
                                            // and that the full range is
                                            // covered

inline bool Density::sumOne() const
{
    return Globals::isZero(d_cumBirads[N_BIRADS - 1] - 1);
}

inline AgeGroup const &Density::ageGroup() const
{
    return d_ageGroup;
}
        
inline uint16_t Density::beginAge() const
{
    return d_ageGroup.beginAge();
}

inline uint16_t Density::endAge() const
{
    return d_ageGroup.endAge();
}

inline double Density::birad(size_t idx) const
{
    return d_birad[idx];
}

inline std::vector<double> const &Density::birad() const
{
    return d_birad;
}

inline bool Density::contains(double age) const
{
    return d_ageGroup.beginAge() <= age and age < d_ageGroup.endAge();
}

inline std::istream &operator>>(std::istream &in, Density &density)
{
    return density.extract(in);
}

inline std::ostream &operator<<(std::ostream &out, Density const &density)
{
    return density.insert(out);
}

#endif


