#include "Param/Distrib/ParameterDistribution.h"

#include "Param/Distrib/Distributions.h"
#include "Tests/GTestWrapper/google_test.h"
#include <cmath>

/* #baPool implement tests ParameterDistributionTest

TEST(ParameterDistributionTest, ParameterDistributionConstructor)
{
    std::string name = "MainParameterName";
    DistributionGate distribution(1.0, 2.0);
    EXPECT_THROW(ParameterDistribution(name, distribution, 1, -1.0), std::runtime_error);
    EXPECT_THROW(ParameterDistribution(name, distribution, 0), std::runtime_error);

    // Sigma constructor
    ParameterDistribution pardistr(name, distribution, 1);
    EXPECT_EQ(1.5, pardistr.getDistribution()->mean());
    EXPECT_EQ(1.0, pardistr.getDistribution()->probabilityDensity(1));
    EXPECT_EQ(name, pardistr.getMainParameterName());
    EXPECT_EQ(size_t(1), pardistr.nDraws());
    EXPECT_EQ(0.0, pardistr.sigmaFactor());
    EXPECT_EQ(RealLimits(), pardistr.getLimits());
    EXPECT_EQ(1.0, pardistr.getMinValue());
    EXPECT_EQ(-1.0, pardistr.getMaxValue());

    ParameterDistribution pardistr2(name, distribution, 5, 2.0, RealLimits::limited(1.0, 2.0));
    EXPECT_EQ(size_t(5), pardistr2.nDraws());
    EXPECT_EQ(2.0, pardistr2.sigmaFactor());
    EXPECT_EQ(RealLimits::limited(1.0, 2.0), pardistr2.getLimits());

    // xmin, xmax constructor
    ParameterDistribution pardistr3(name, distribution, 5, 1.0, 2.0);
    EXPECT_EQ(1.5, pardistr3.getDistribution()->mean());
    EXPECT_EQ(1.0, pardistr3.getDistribution()->probabilityDensity(1));
    EXPECT_EQ(name, pardistr3.getMainParameterName());
    EXPECT_EQ(size_t(5), pardistr3.nDraws());
    EXPECT_EQ(0.0, pardistr3.sigmaFactor());
    EXPECT_EQ(RealLimits(), pardistr3.getLimits());
}

TEST(ParameterDistributionTest, ParameterDistributionCopyConstructor)
{
    DistributionGate distribution(1.0, 2.0);
    std::string name = "MainParameterName";
    ParameterDistribution pardistr(name, distribution, 5, 2.0, RealLimits::limited(1.0, 2.0));

    ParameterDistribution pcopy(pardistr);
    EXPECT_EQ(1.5, pcopy.getDistribution()->mean());

    EXPECT_EQ(pardistr.getDistribution()->probabilityDensity(1),
              pcopy.getDistribution()->probabilityDensity(1));
    EXPECT_EQ(pardistr.getMainParameterName(), pcopy.getMainParameterName());
    EXPECT_EQ(pardistr.nDraws(), pcopy.nDraws());
    EXPECT_EQ(pardistr.sigmaFactor(), pcopy.sigmaFactor());
    EXPECT_EQ(pardistr.getLimits(), pcopy.getLimits());
    EXPECT_EQ(pardistr.getMinValue(), pcopy.getMinValue());
    EXPECT_EQ(pardistr.getMaxValue(), pcopy.getMaxValue());
}

TEST(ParameterDistributionTest, ParameterDistributionAssignment)
{
    DistributionGate distribution(1.0, 2.0);
    std::string name = "MainParameterName";
    ParameterDistribution pardistr(name, distribution, 5, 2.0, RealLimits::limited(1.0, 2.0));

    ParameterDistribution pcopy = pardistr;
    EXPECT_EQ(1.5, pcopy.getDistribution()->mean());

    EXPECT_EQ(pardistr.getDistribution()->probabilityDensity(1),
              pcopy.getDistribution()->probabilityDensity(1));
    EXPECT_EQ(pardistr.getMainParameterName(), pcopy.getMainParameterName());
    EXPECT_EQ(pardistr.nDraws(), pcopy.nDraws());
    EXPECT_EQ(pardistr.sigmaFactor(), pcopy.sigmaFactor());
    EXPECT_EQ(pardistr.getLimits(), pcopy.getLimits());
    EXPECT_EQ(pardistr.getMinValue(), pcopy.getMinValue());
    EXPECT_EQ(pardistr.getMaxValue(), pcopy.getMaxValue());
}

TEST(ParameterDistributionTest, GenerateSamples)
{
    const double mean(1.0);
    const double sigma(0.8);
    DistributionGaussian distribution(mean, sigma);

    std::string name = "MainParameterName";
    const int n_samples(3);
    const double sigma_factor(2.0);

    // without Limits
    ParameterDistribution pardistr(name, distribution, n_samples, sigma_factor);
    std::vector<ParameterSample> sample_values = pardistr.generateSamples();
    EXPECT_EQ(sample_values.size(), size_t(3));
    EXPECT_EQ(sample_values[0].value, mean - sigma_factor * sigma);
    EXPECT_EQ(sample_values[1].value, mean);
    EXPECT_EQ(sample_values[2].value, mean + sigma_factor * sigma);

    // with Limits
    ParameterDistribution pardistr2(name, distribution, n_samples, sigma_factor,
                                    RealLimits::lowerLimited(mean));
    sample_values = pardistr2.generateSamples();
    EXPECT_EQ(sample_values.size(), size_t(3));
    EXPECT_EQ(sample_values[0].value, mean);
    EXPECT_EQ(sample_values[1].value, mean + sigma_factor * sigma / 2.0);
    EXPECT_EQ(sample_values[2].value, mean + sigma_factor * sigma);

    // with xmin, xmax defined
    double xmin(-1.0);
    double xmax(2.0);
    ParameterDistribution pardistr3(name, distribution, n_samples, xmin, xmax);
    sample_values = pardistr3.generateSamples();
    EXPECT_EQ(sample_values.size(), size_t(3));
    EXPECT_EQ(sample_values[0].value, xmin);
    EXPECT_EQ(sample_values[1].value, xmin + (xmax - xmin) / 2.0);
    EXPECT_EQ(sample_values[2].value, xmax);
}

*/