#ifndef INCLUDED_VSD_
#define INCLUDED_VSD_

#include <iosfwd>
#include <vector>

#include "../distribution/distribution.h"

class VSD
{
    friend std::istream &operator>>(std::istream &in, VSD &vsd);
    friend std::ostream &operator<<(std::ostream &out, VSD const &vsd);
    friend std::ostream &operator<<(std::ostream &out, 
                                    std::vector<VSD> const &vect);

    double d_value = 0;
    double d_orgValue = 0;                  // initial config. value,
                                            //  used by vary()

    Distribution d_dist;                    // distribution used for spreading
                                            // d_value. The distribution
                                            // receives the 'spread' and the
                                            // name of the distribution

    void (*d_valueCheck)(double &value);    // mean, stddev, proportion

                                                    // functions checking 
    static void (*s_valueCheck[])(double &value);   // d_value
    static VaryType s_varyType[];

    static unsigned s_indent;
    static char const *s_type;
    static char     s_ch;
    static unsigned s_width;
    static unsigned s_prec;

    public:
        VSD(VaryType varyType);

        void vary();                            // was: refresh/spread
        void showVary(std::ostream &out) const; // the actually used and orig.
                                                // values
        
        
        double value() const;                   // mean or proportion
        double spread() const;                  // Distribution's value

        DistType distType() const;              // was: dist
        std::string const &distName() const;    // was: name

        Distribution const &distribution() const;

        static void fmt(unsigned valueIntWidth, unsigned valuePrec,     // 1
                        unsigned distValueWdith, unsigned distPrec);

        static void fmt(unsigned indent, char const *type, char ch,     // 2
                        unsigned valueIntWidth, unsigned valuePrec,    
                        unsigned distValueWidth, unsigned distPrec);

        static void vary(std::ostream &out,                             // 2
                        unsigned indent, char const *hdr, 
                        char const *type, char ch, std::vector<VSD> &vect);
                         
    private:
        std::ostream &insert(std::ostream &out) const;                  // 1
        
        static std::ostream &insert(std::ostream &out,                  // 2
                                    std::vector<VSD> const &vect);

        std::istream &extract(std::istream &in);

        static void meanCheck(double &value);
        static void posCheck(double &value);
        static void probCheck(double &value);
};

typedef std::vector<VSD> VSDvect;

inline Distribution const &VSD::distribution() const
{
    return d_dist;
}

inline void VSD::vary()
{
    d_value = d_dist.vary(d_orgValue);
}

inline double VSD::value() const
{
    return d_value;
}

inline double VSD::spread() const
{
    return d_dist.value();
}
    
inline DistType VSD::distType() const
{
    return d_dist.type();
}
        
inline std::string const &VSD::distName() const
{
    return Distribution::name(d_dist.type());
}
        
inline std::ostream &operator<<(std::ostream &out, VSD const &vsd)
{
    return vsd.insert(out);
}

inline std::ostream &operator<<(std::ostream &out, VSDvect const &vect)
{
    return VSD::insert(out, vect);
}

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

//                        // charShift != 0 then idx is converted to char 
//                        // indent: initial indentation
//        static std::ostream &insert(std::ostream &out, char const *label, // 1
//                             char const *type, 
//                             std::vector<VSD> const &vect,
//                             unsigned indent, unsigned mPrecision,
//                             unsigned sdPrecision, char ch = 0);
//
//        std::ostream &insert(std::ostream &out,                           // 2
//                             unsigned mPrec, unsigned sdPrec) const;
//


#endif


