/** @file main.cpp
 *
 *  @author Cory Alexander Balaton (coryab)
 *  @author Janita Ovidie Sandtrøen Willumsen (janitaws)
 *
 *  @version 0.1
 *
 *  @brief The main program
 *
 *  @bug No known bugs
 * */
#include "data_type.hpp"
#include "monte_carlo.hpp"
#include "utils.hpp"

#include <csignal>
#include <cstdlib>
#include <iostream>
#include <omp.h>

void create_burn_in_time_data()
{
    // Test burn-in time
    monte_carlo_progression(1.0, 20, 20000,
                            "output/burn_in_time/unordered_1_0.txt");
    monte_carlo_progression(1.0, 20, 20000, 1,
                            "output/burn_in_time/ordered_1_0.txt");
    monte_carlo_progression(2.4, 20, 20000,
                            "output/burn_in_time/unordered_2_4.txt");
    monte_carlo_progression(2.4, 20, 20000, 1,
                            "output/burn_in_time/ordered_2_4.txt");
}

void create_pd_estimate_data()
{
    // Estimate pd
    pd_estimate(1.0, 20, 1000000, "output/pd_estimate/estimate_1_0.txt");
    pd_estimate(2.4, 20, 1000000, "output/pd_estimate/estimate_2_4.txt");
}

void test_parallel_speedup()
{
    // Test the openmp speedup
    data_t data;
    double t0, t1, t2;
    int tries = 5;
    t0 = omp_get_wtime();
    for (size_t i = 0; i < tries; i++)
        monte_carlo_serial(20, 1.0, 10000);
    t1 = omp_get_wtime();
    for (size_t i = 0; i < tries; i++)
        monte_carlo_parallel(20, 1.0, 10000);
    t2 = omp_get_wtime();

    std::cout << "Time serial     : " << (t1 - t0) / tries << " seconds"
              << '\n';
    std::cout << "Time parallel   : " << (t2 - t1) / tries << " seconds"
              << '\n';
    std::cout << "Speedup parallel: " << (t1 - t0) / (t2 - t1) << '\n';
}

void create_phase_transition_data()
{
    double t0, t1;

    t0 = omp_get_wtime();
    // Phase transition
    phase_transition(20, 2.1, 2.4, 40, monte_carlo_parallel,
                     "output/phase_transition/size_20.txt");
    phase_transition(40, 2.1, 2.4, 40, monte_carlo_parallel,
                     "output/phase_transition/size_40.txt");
    phase_transition(60, 2.1, 2.4, 40, monte_carlo_parallel,
                     "output/phase_transition/size_60.txt");
    phase_transition(80, 2.1, 2.4, 40, monte_carlo_parallel,
                     "output/phase_transition/size_80.txt");
    phase_transition(100, 2.1, 2.4, 40, monte_carlo_parallel,
                     "output/phase_transition/size_100.txt");
    t1 = omp_get_wtime();

    std::cout << "Time: " << t1 - t0 << std::endl;
}

/** @brief The main function.*/
int main(int argc, char **argv)
{
    if (argc < 2) {
        std::cout << "Need at least 1 argument, got " << argc - 1
                  << " arguments." << std::endl;
        abort();
    }

    int arg = atoi(argv[1]);

    switch (arg) {
    case 1:
        create_burn_in_time_data();
        break;
    case 2:
        create_pd_estimate_data();
        break;
    case 3:
        test_parallel_speedup();
        break;
    case 4:
        create_phase_transition_data();
        break;
    default:
        std::cout << "Not a valid option!" << std::endl;
        abort();
    }

    return 0;
}
