#include "Sample/Correlation/Profiles1D.h"

#include "Sample/Correlation/Profiles2D.h"
#include "Tests/GTestWrapper/google_test.h"
#include <memory>

// test 1D

TEST(ProfilesTest, Profile1DCauchyConstructor)
{
    std::unique_ptr<IProfile1D> P_1d_cauchy{new Profile1DCauchy(1.0)};
    EXPECT_EQ(1.0, P_1d_cauchy->omega());
    EXPECT_NEAR(0.961538, P_1d_cauchy->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DCauchyClone)
{
    std::unique_ptr<IProfile1D> P_1d_cauchy{new Profile1DCauchy(5.0)};
    std::unique_ptr<IProfile1D> P_clone{P_1d_cauchy->clone()};

    EXPECT_EQ(5.0, P_clone->omega());
    EXPECT_NEAR(0.5, P_clone->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DGaussConstructor)
{
    std::unique_ptr<IProfile1D> P_1d_gauss{new Profile1DGauss(1.0)};
    EXPECT_EQ(1.0, P_1d_gauss->omega());
    EXPECT_NEAR(0.9801987, P_1d_gauss->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DGaussClone)
{
    std::unique_ptr<IProfile1D> P_1d_gauss{new Profile1DGauss(5.0)};
    std::unique_ptr<IProfile1D> P_clone{P_1d_gauss->clone()};

    EXPECT_EQ(5.0, P_clone->omega());
    EXPECT_NEAR(0.6065307, P_clone->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DGateConstructor)
{
    std::unique_ptr<IProfile1D> P_1d_gate{new Profile1DGate(1.0)};
    EXPECT_EQ(1.0, P_1d_gate->omega());
    EXPECT_NEAR(0.993347, P_1d_gate->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DGateClone)
{
    std::unique_ptr<IProfile1D> P_1d_gate{new Profile1DGate(5.0)};
    std::unique_ptr<IProfile1D> P_clone{P_1d_gate->clone()};

    EXPECT_EQ(5.0, P_clone->omega());
    EXPECT_NEAR(0.841471, P_clone->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DTriangleConstructor)
{
    std::unique_ptr<IProfile1D> P_1d_triangle{new Profile1DTriangle(1.0)};
    EXPECT_EQ(1.0, P_1d_triangle->omega());
    EXPECT_NEAR(0.996671, P_1d_triangle->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DTriangleClone)
{
    std::unique_ptr<IProfile1D> P_1d_triangle{new Profile1DTriangle(5.0)};
    std::unique_ptr<IProfile1D> P_clone{P_1d_triangle->clone()};

    EXPECT_EQ(5.0, P_clone->omega());
    EXPECT_NEAR(0.919395, P_clone->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DCosineConstructor)
{
    std::unique_ptr<IProfile1D> P_1d_cosine{new Profile1DCosine(1.0)};
    EXPECT_EQ(1.0, P_1d_cosine->omega());
    EXPECT_NEAR(0.997389, P_1d_cosine->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DCosineClone)
{
    std::unique_ptr<IProfile1D> P_1d_cosine{new Profile1DCosine(5.0)};
    std::unique_ptr<IProfile1D> P_clone{P_1d_cosine->clone()};

    EXPECT_EQ(5.0, P_clone->omega());
    EXPECT_NEAR(0.936342, P_clone->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DVoigtConstructor)
{
    std::unique_ptr<IProfile1D> P_1d_voigt{new Profile1DVoigt(1.0, .7)};
    EXPECT_EQ(1.0, P_1d_voigt->omega());
    EXPECT_NEAR(0.97460060977626, P_1d_voigt->standardizedFT(0.2), 0.000001);
}

TEST(ProfilesTest, Profile1DVoigtClone)
{
    std::unique_ptr<IProfile1D> P_1d_voigt{new Profile1DVoigt(5.0, .6)};
    std::unique_ptr<IProfile1D> P_clone{P_1d_voigt->clone()};

    EXPECT_EQ(5.0, P_clone->omega());
    EXPECT_NEAR(0.5639183958276, P_clone->standardizedFT(0.2), 0.000001);
}

// test 2D

TEST(ProfilesTest, Profile2DCauchyConstructor)
{
    std::unique_ptr<IProfile2D> P_2d_cauchy{new Profile2DCauchy(1.0, 2.0, 0)};
    EXPECT_EQ(1.0, P_2d_cauchy->omegaX());
    EXPECT_EQ(2.0, P_2d_cauchy->omegaY());
    EXPECT_EQ(pi / 2.0, P_2d_cauchy->delta());
    EXPECT_EQ(0.0, P_2d_cauchy->gamma());
    EXPECT_NEAR(0.343206, P_2d_cauchy->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DCauchyClone)
{
    std::unique_ptr<IProfile2D> P_2d_cauchy{new Profile2DCauchy(5.0, 2.3, 0)};
    std::unique_ptr<IProfile2D> P_clone{P_2d_cauchy->clone()};

    EXPECT_EQ(5.0, P_clone->omegaX());
    EXPECT_EQ(2.3, P_clone->omegaY());
    EXPECT_EQ(pi / 2.0, P_clone->delta());
    EXPECT_EQ(0.0, P_clone->gamma());
    EXPECT_NEAR(0.165121078, P_clone->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DGaussConstructor)
{
    std::unique_ptr<IProfile2D> P_2d_gauss{new Profile2DGauss(1.0, 2.0, 0)};
    EXPECT_EQ(1.0, P_2d_gauss->omegaX());
    EXPECT_EQ(2.0, P_2d_gauss->omegaY());
    EXPECT_EQ(pi / 2.0, P_2d_gauss->delta());
    EXPECT_EQ(0.0, P_2d_gauss->gamma());
    EXPECT_NEAR(0.5945205, P_2d_gauss->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DGaussClone)
{
    std::unique_ptr<IProfile2D> P_2d_gauss{new Profile2DGauss(5.0, 2.3, 0)};
    std::unique_ptr<IProfile2D> P_clone{P_2d_gauss->clone()};

    EXPECT_EQ(5.0, P_clone->omegaX());
    EXPECT_EQ(2.3, P_clone->omegaY());
    EXPECT_EQ(pi / 2.0, P_clone->delta());
    EXPECT_EQ(0.0, P_clone->gamma());
    EXPECT_NEAR(0.3130945, P_clone->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DGateConstructor)
{
    std::unique_ptr<IProfile2D> P_2d_gate{new Profile2DGate(1.0, 2.0, 0)};
    EXPECT_EQ(1.0, P_2d_gate->omegaX());
    EXPECT_EQ(2.0, P_2d_gate->omegaY());
    EXPECT_EQ(pi / 2.0, P_2d_gate->delta());
    EXPECT_EQ(0.0, P_2d_gate->gamma());
    EXPECT_NEAR(0.875513, P_2d_gate->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DGateClone)
{
    std::unique_ptr<IProfile2D> P_2d_gate{new Profile2DGate(5.0, 2.3, 0)};
    std::unique_ptr<IProfile2D> P_clone{P_2d_gate->clone()};

    EXPECT_EQ(5.0, P_clone->omegaX());
    EXPECT_EQ(2.3, P_clone->omegaY());
    EXPECT_EQ(pi / 2.0, P_clone->delta());
    EXPECT_EQ(0.0, P_clone->gamma());
    EXPECT_NEAR(0.736461, P_clone->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DConeConstructor)
{
    std::unique_ptr<IProfile2D> P_2d_cone{new Profile2DCone(1.0, 2.0, 0)};
    EXPECT_EQ(1.0, P_2d_cone->omegaX());
    EXPECT_EQ(2.0, P_2d_cone->omegaY());
    EXPECT_EQ(pi / 2.0, P_2d_cone->delta());
    EXPECT_EQ(0.0, P_2d_cone->gamma());
    EXPECT_NEAR(0.924374, P_2d_cone->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DConeClone)
{
    std::unique_ptr<IProfile2D> P_2d_cone{new Profile2DCone(5.0, 2.3, 0)};
    std::unique_ptr<IProfile2D> P_clone{P_2d_cone->clone()};

    EXPECT_EQ(5.0, P_clone->omegaX());
    EXPECT_EQ(2.3, P_clone->omegaY());
    EXPECT_EQ(pi / 2.0, P_clone->delta());
    EXPECT_EQ(0.0, P_clone->gamma());
    EXPECT_NEAR(0.837410, P_clone->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DVoigtConstructor)
{
    std::unique_ptr<IProfile2D> P_2d_voigt{new Profile2DVoigt(1.0, 2.0, 0, .5)};
    EXPECT_EQ(1.0, P_2d_voigt->omegaX());
    EXPECT_EQ(2.0, P_2d_voigt->omegaY());
    EXPECT_EQ(pi / 2.0, P_2d_voigt->delta());
    EXPECT_EQ(0.0, P_2d_voigt->gamma());
    EXPECT_NEAR(0.468863225459, P_2d_voigt->standardizedFT2D(0.2, 0.5), 0.000001);
}

TEST(ProfilesTest, Profile2DVoigtClone)
{
    std::unique_ptr<IProfile2D> P_2d_voigt{new Profile2DVoigt(5.0, 2.3, 0, .4)};
    std::unique_ptr<IProfile2D> P_clone{P_2d_voigt->clone()};

    EXPECT_EQ(5.0, P_clone->omegaX());
    EXPECT_EQ(2.3, P_clone->omegaY());
    EXPECT_EQ(pi / 2.0, P_clone->delta());
    EXPECT_EQ(0.0, P_clone->gamma());
    EXPECT_NEAR(0.22431047406, P_clone->standardizedFT2D(0.2, 0.5), 0.000001);
}
