#include <math.h>
#include "models.h"

int f_osc(double t, double *y, double *dy, void *params) {
    // s' = v
    dy[0] = y[1];
    // v' = -k * s
    dy[1] = - PARAM(0) * y[0];

    return 0;
}

int f_forced_osc(double t, double *y, double *dy, void *params) {
    // s' = v
    dy[0] = y[1];
    // v' = -k * s - D * v + sin(w * t)
    dy[1] = - PARAM(0) * y[0] - PARAM(1) * y[1] + sin(PARAM(2) * t);

    return 0;
}

int f_lottka_volt(double t, double *y, double *dy, void *params) {
    // x' = -a * x + c * d * x * y
    dy[0] = - PARAM(0) * y[0] + PARAM(2) * PARAM(3) * y[0] * y[1];
    // y' = b * y - d * x * y
    dy[1] = PARAM(1) * y[1] - PARAM(3) * y[0] * y[1];

    return 0;
}

int f_modified_pp(double t, double *y, double *dy, void *params) {
    // x' = -a * x + c * d * x * y
    dy[0] = - PARAM(0) * y[0] + PARAM(2) * PARAM(3) * y[0] * y[1];
    // y' = b * ( 1 - y / y_m ) * y - d * x * y
    //    = b * y - b * y * y / y_m - d * x * y
    double by = PARAM(1) * y[1];
    dy[1] = by - by * y[1] / PARAM(4) - PARAM(3) * y[0] * y[1];

    return 0;
}

int pos = 0;

int f_pid_control(double t, double *y, double *dy, void *params) {
    int buf_begin = (pos + 1) % buf_size;

    // U(t) = P * s(t - d) + D * v(t - d)
    double U = PARAM(0) * s_buf[buf_begin] + PARAM(1) * v_buf[buf_begin];
    // F(t) = U(t) - a * v(t)
    double F = U - PARAM(2) * y[0];
    // v'(t) = F(t) / M
    dy[0] = F / PARAM(3);
    // s'(t) = v(t)
    dy[1] = y[0];

    v_buf[pos] = y[0];
    s_buf[pos] = y[1];
    pos = buf_begin;

    return 0;
}

int f_gilpin(double t, double *y, double *dy, void *params) {
    // x' = x(1 - 0.001x - 0.001y - 0.01z)
    dy[0] = y[0] * (1.0 - .001 * y[0] - .001 * y[1] - .01 * y[2]);
    // y' = y(1 - 0.001y - 0.0015x - 0.001z)
    dy[1] = y[1] * (1.0 - .001 * y[1] - .0015 * y[0] - .001 * y[2]);
    // z' = z(0.005x - 0.0005y - 1)
    dy[2] = y[2] * (.005 * y[0] + .0005 * y[1] - 1.0);

    return 0;
}
