#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);

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

    Distribution d_dist;                    // distribution used for spreading
                                            // d_value

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

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

    public:
        enum Mode
        {
            MEAN,
            NON_NEGATIVE,
            PROPORTION,
        };

        void vary();                            // was: refresh/spread
        
        double value() const;
        double spread() const;                  // Distribution's value

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

        void setMode(Mode mode);

//        void spreadable(VaryType varyType);     // change to spread distr.

        Distribution const &distribution() const;

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

        static void meanCheck(double &value);
        static void stdDevCheck(double &value);
        static void proportionCheck(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());
}
        
std::istream &operator>>(std::istream &in, VSD &vsd);

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

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

#endif

