/* $Id$
C interface code to connect Perl to mopsephem.c library.
*/

#include <stdlib.h>
#include <mopsephem.h>
#include "cwrap.h"


void ssd_init_c(void) {
    mopsephem_init();             ///< initialize JPL stuff
}


void ssd_compute_ephemeris_c(
    double t_epoch_mjd,
    double q_au, double e, double i_deg, double node_deg, double arg_peri_deg, double time_peri_mjd,
    double h_v, 
    char *obscod, 
    double t_eph_ut_mjd, 
    double *out_ra_deg, 
    double *out_dec_deg, 
    double *out_mag,
    int *out_errcod
) {
    EPHEM_BLK ephem_blk;
    ORBIT_BLK orbit_blk;
    int errcod;

    orbit_blk.t_epoch_mjd = t_epoch_mjd;
    orbit_blk.q_au = q_au;
    orbit_blk.e = e;
    orbit_blk.i_deg = i_deg;
    orbit_blk.node_deg = node_deg;
    orbit_blk.arg_peri_deg = arg_peri_deg;
    orbit_blk.time_peri_mjd = time_peri_mjd;
    orbit_blk.h_v = h_v;
    orbit_blk.g = 0;                            ///< default
    orbit_blk.covar = NULL;                     ///< no covariance 

    errcod = mopsephem_compute_ephemerides(
        &orbit_blk,
        &ephem_blk,
        &t_eph_ut_mjd,                  ///< time of ephemeris
        1,
        obscod
    );

    // Shred our stuff back into Perl-land.
    *out_errcod = errcod;
    if (0 == errcod) {
        *out_ra_deg = ephem_blk.ra_deg;
        *out_dec_deg = ephem_blk.dec_deg;
        *out_mag = ephem_blk.mag;
    }
}


void ssd_compute_ephemeris_with_src_c(
    double t_epoch_mjd,
    double q_au, double e, double i_deg, double node_deg, double arg_peri_deg, double time_peri_mjd,
    double h_v, 
    char *obscod, 
    double t_eph_ut_mjd, 
    double src_01,		/* Stupid Perl XS! */
    double src_02,
    double src_03,
    double src_04,
    double src_05,
    double src_06,
    double src_07,
    double src_08,
    double src_09,
    double src_10,
    double src_11,
    double src_12,
    double src_13,
    double src_14,
    double src_15,
    double src_16,
    double src_17,
    double src_18,
    double src_19,
    double src_20,
    double src_21, 
    double *out_ra_deg, 
    double *out_dec_deg, 
    double *out_mag,
    double *out_smaa_sec,
    double *out_smia_sec,
    double *out_pa_deg,
    int *out_errcod
) {
    EPHEM_BLK ephem_blk;
    ORBIT_BLK orbit_blk;
    int errcod;
    double src_array[21] = {src_01,
			    src_02,
			    src_03,
			    src_04,
			    src_05,
			    src_06,
			    src_07,
			    src_08,
			    src_09,
			    src_10,
			    src_11,
			    src_12,
			    src_13,
			    src_14,
			    src_15,
			    src_16,
			    src_17,
			    src_18,
			    src_19,
			    src_20,
			    src_21};
    
    
    orbit_blk.t_epoch_mjd = t_epoch_mjd;
    orbit_blk.q_au = q_au;
    orbit_blk.e = e;
    orbit_blk.i_deg = i_deg;
    orbit_blk.node_deg = node_deg;
    orbit_blk.arg_peri_deg = arg_peri_deg;
    orbit_blk.time_peri_mjd = time_peri_mjd;
    orbit_blk.h_v = h_v;
    orbit_blk.g = 0;                            ///< default
    orbit_blk.covar = src_array;

    errcod = mopsephem_compute_ephemerides(
        &orbit_blk,
        &ephem_blk,
        &t_eph_ut_mjd,                  ///< time of ephemeris
        1,
        obscod
    );

    // Shred our stuff back into Perl-land.
    *out_errcod = errcod;
    if (0 == errcod) {
        *out_ra_deg = ephem_blk.ra_deg;
        *out_dec_deg = ephem_blk.dec_deg;
        *out_mag = ephem_blk.mag;
	*out_smaa_sec = ephem_blk.smaa_sec;
	*out_smia_sec = ephem_blk.smia_sec;
	*out_pa_deg = ephem_blk.pa_deg;
    }
}


void ssd_compute_ephemeris_pair_c(
    double t_epoch_mjd,
    double q_au, double e, double i_deg, double node_deg, double arg_peri_deg, double time_peri_mjd,
    double h_v, 
    char *obscod, 
    double t_eph_ut_mjd, 
    double exposure_time_sec,
    double *out_ra_deg, 
    double *out_dec_deg, 
    double *out_mag,
    double *out_ra2_deg, 
    double *out_dec2_deg, 
    int *out_errcod
) {
    /* Compute a pair of positions separated in time by a exposure_time_sec.  This is used to
    generate length and orientation for synthetic trailed detections. */
    EPHEM_BLK ephem_blk1;
    EPHEM_BLK ephem_blk2;
    ORBIT_BLK orbit_blk;
    int errcod;
    double t2;

    orbit_blk.t_epoch_mjd = t_epoch_mjd;
    orbit_blk.q_au = q_au;
    orbit_blk.e = e;
    orbit_blk.i_deg = i_deg;
    orbit_blk.node_deg = node_deg;
    orbit_blk.arg_peri_deg = arg_peri_deg;
    orbit_blk.time_peri_mjd = time_peri_mjd;
    orbit_blk.h_v = h_v;
    orbit_blk.g = 0;                            ///< default
    orbit_blk.covar = NULL;                     ///< no covariance 

    errcod = mopsephem_compute_ephemerides(
        &orbit_blk,
        &ephem_blk1,
        &t_eph_ut_mjd,                  ///< time of ephemeris
        1,
        obscod
    );

    t2 = t_eph_ut_mjd + exposure_time_sec / 86400.0;
    errcod = mopsephem_compute_ephemerides(
        &orbit_blk,
        &ephem_blk2,
        &t2,                            ///< time of ephemeris
        1,
        obscod
    );

    // Shred our stuff back into Perl-land.
    *out_errcod = errcod;
    if (0 == errcod) {
        *out_ra_deg = ephem_blk1.ra_deg;
        *out_dec_deg = ephem_blk1.dec_deg;
        *out_mag = ephem_blk1.mag;
        *out_ra2_deg = ephem_blk2.ra_deg;
        *out_dec2_deg = ephem_blk2.dec_deg;
    }
}


void ssd_compute_xyz_c(
    double t_epoch_mjd,
    double q_au, double e, double i_deg, double node_deg, double arg_peri_deg, double time_peri_mjd,
    double h_v, 
    char *obscod, 
    double t_eph_ut_mjd, 
    double *out_ex, 
    double *out_ey, 
    double *out_ez,
    double *out_ox, 
    double *out_oy, 
    double *out_oz,
    int *out_errcod
) {
    EPHEM_BLK ephem_blk;
    ORBIT_BLK orbit_blk;
    int errcod;

    orbit_blk.t_epoch_mjd = t_epoch_mjd;
    orbit_blk.q_au = q_au;
    orbit_blk.e = e;
    orbit_blk.i_deg = i_deg;
    orbit_blk.node_deg = node_deg;
    orbit_blk.arg_peri_deg = arg_peri_deg;
    orbit_blk.time_peri_mjd = time_peri_mjd;
    orbit_blk.h_v = h_v;
    orbit_blk.g = 0;                            ///< default
    orbit_blk.covar = NULL;                     ///< no covariance 

    /* DOES NOT ACTUALLY EXIST YET!
    errcod = mopsephem_compute_xyz(
        &orbit_blk,
        &ephem_blk,
        &t_eph_ut_mjd,                  ///< time of ephemeris
        1,
        obscod
    );

    OLD WAY
    ssd_run_xyz_f(
        &t_epoch_mjd, elems, obscod, &t_eph_ut_mjd, &h_v, 
        out_ex, out_ey, out_ez,
        out_ox, out_oy, out_oz,
        out_errcod
    ); */

    *out_errcod = EBADINPUT;           ///< return something
}


void ssd_propagate_elements_c(
    double t_epoch_mjd,
    double q_au, double e, double i_deg, double node_deg, double arg_peri_deg, double time_peri_mjd,
    double t_eph_ut_mjd, 
    double *out_q_au, double *out_e, double *out_i_deg, double *out_node_deg, double *out_arg_peri_deg, double *out_time_peri_mjd,
    int *out_errcod
) {
    ORBIT_BLK in_orbit_blk;
    ORBIT_BLK out_orbit_blk;
    int errcod;

    in_orbit_blk.t_epoch_mjd = t_epoch_mjd;
    in_orbit_blk.q_au = q_au;
    in_orbit_blk.e = e;
    in_orbit_blk.i_deg = i_deg;
    in_orbit_blk.node_deg = node_deg;
    in_orbit_blk.arg_peri_deg = arg_peri_deg;
    in_orbit_blk.time_peri_mjd = time_peri_mjd;
    in_orbit_blk.h_v = 0;                          ///< default
    in_orbit_blk.g = 0;                            ///< default
    in_orbit_blk.covar = NULL;                      ///< no covariance 

    errcod = mopsephem_propagate_elements(
        &in_orbit_blk,
        &out_orbit_blk,
        t_eph_ut_mjd                                ///< time of propagation
    );

    // Shred our stuff back into Perl-land.
    *out_errcod = errcod;
    if (0 == errcod) {
        *out_q_au = out_orbit_blk.q_au;
        *out_e = out_orbit_blk.e;
        *out_i_deg = out_orbit_blk.i_deg;
        *out_node_deg = out_orbit_blk.node_deg;
        *out_arg_peri_deg = out_orbit_blk.arg_peri_deg;
        *out_time_peri_mjd = out_orbit_blk.time_peri_mjd;
    }
}
