#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "integration.h"
#include "logger.h"

extern FILE *logfile;

int f_test_1(double t, double *y, double *dy, void *params) {
    *dy = 1.0;

    return 0;
}

int f_test_2(double t, double *y, double *dy, void *params) {
    *dy = t;

    return 0;
}

int f_test_3(double t, double *y, double *dy, void *params) {
    if( isnan(*y) ) {
        return -1;
    } else {
        *dy = *y;
        return 0;
    }
}

int f_test_4(double t, double *y, double *dy, void *params) {
    double result = *y * *y;

    if( isnan(result) ) {
        return -1;
    } else {
        *dy = result;
        return 0;
    }
}

int f_cos(double t, double *y, double *dy, void *params) {
    double result = cos(t);

    if( isnan(result) ) {
        return -1;
    } else {
        *dy = result;
        return 0;
    }
}

#define INTEGRATE(method, y_start, t0, t1, dy) { \
    *y0 = y_start; \
    if( method(t0, t1, dt, y0, y1, 1, &dy, NULL) ) \
        puts("FAIL"); \
    else \
        printf("y1 for dy = " #dy " using %-12s %.10f\n", #method ":", *y1); \
}
#define COMPARE(y_start, t0, t1, dy) { \
    INTEGRATE(Euler, y_start, t0, t1, dy); \
    INTEGRATE(RungeKutta2, y_start, t0, t1, dy); \
    INTEGRATE(RungeKutta4, y_start, t0, t1, dy); \
}

int main(int argc, char **argv) {
    double y0[1] = {.0}, y1[1] = {.0}, dt;

    if( argc < 2 ) {
        printf("Usage: %s DT\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    dt = atof(argv[1]);
    logfile = fopen("/dev/null", "w");

    COMPARE(.0, .0, 10.0, f_test_1);
    puts("");
    COMPARE(.0, .0, 10.0, f_test_2);
    puts("");
    COMPARE(1.0, .0, 5.0, f_test_3);
    puts("");
    COMPARE(1.0, -1.0, 1.0, f_test_4);
    puts("");
    COMPARE(-1.0, 1.0, 10.0, f_test_4);
    puts("");
    COMPARE(.0, .0, 5.0, f_cos);

    return EXIT_SUCCESS;
}
