#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(),
                                // extracted from the config file


    Distribution d_dist;    // distribution used for spreading d_value.
                            // The distribution may receive the 'spread' and
                            // receives the name of the distribution.
                            // For LC BETA_MALE or BETA_FEMALE is used

                            // meanCheck (VARY_MEAN), posCheck (VARY_NONNEG)
                            // probCheck (VARY_PROB). No checks for BETA_*,
    void (*d_valueCheck)(double &value);

    bool d_exp;
                                                    // addresses of the
    static void (*s_valueCheck[])(double &value);   // ..Check functions

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

            // vary() modifies d_value by calling d_dist.vary(d_orgValue)
            // this modifies d_value, after which value() returns the modified
            // value. The modified value is called using the variation
            // computing function set by Distribution::d_vary, e.g. varyMean,
            // varyNonNeg, etc. The Distribution::vary* functions call the
            // appropriate random-variation functions, which are active
            // because of the 'spread: true' configuration.
        void vary();                        // was: refresh/spread    .f
                                            // sets d_value as a varied
                                            // value through d_dist.value()

        void showVary(std::ostream &out) const; // the actually used and orig.
                                                // values

        double value() const;                   // mean or percentage       .f

                                                // values obtained from d_dist
        DistType distType() const;              // was: dist                .f
        std::string const &distName() const;    // was: name                .f

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

        void ln();                          // change 

                                            // write vary info to 'out'
        static void vary(std::ostream &out, // hdr should end in ':'    // 2
                        unsigned indent, char const *hdr,
                        char const *type, char ch, std::vector<VSD> &vect);

        static void vary(std::ostream &out, // same, no hdr line           3
                        unsigned indent,
                        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 accept(double &value);
        static void posCheck(double &value);
        static void probCheck(double &value);
};

using VSDvect   = std::vector<VSD>;
using VSDmatrix = std::vector<std::vector<VSD>>;

#include "vsd.f"


//                        // 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
