/*
 * This file is part of the GIRAFFE Pipeline
 * Copyright (C) 2002-2019 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif


#include "gialias.h"
#include "gierror.h"
#include "girvcorrection.h"
#include "giastrometry.h"


/**
 * @defgroup giastrometry  Astrometric Utilities
 *
 * TBD
 */

/**@{*/

/**
 * @brief
 *  Add the barycentric and heliocentric corrections to the given fiber setup.
 *
 * @param fibers   The fiber setup to update
 * @param spectra  Reference image.
 *
 * @return
 *  The function returns @c 0 on success, or a non-zero value otherwise.
 *
 * The function takes the information about the telescope location, the
 * observation time and the epoch from the reference image @em image and
 * computes the barycentric, heliocentric and geocentric corrections for
 * each object fiber in the fiber setup @em fibers. The computed corrections
 * are added to @em fibers in the columns @c BCORR, @c HCORR and @c GCORR
 * respectively. The computed corrections are in units of km/s.
 *
 * The position of the object fibers is taken from the fiber configuration
 * @em fibers. In case of an Argus observation, where the individual fiber
 * positions a are not given in the fiber configuration, the telescope
 * pointing direction is used for all Argus fibers.
 *
 * If a property, which is needed to compute the corrections, is not found
 * in the property list of the reference image the function returns a positive
 * value. On any other error a negative value is returned.
 *
 */

cxint
giraffe_add_rvcorrection(GiTable* fibers, const GiImage* spectra)
{

    cxint fiber = 0;
    cxint nr    = 0;

    cxdouble exptime   = 0.;
    cxdouble jd        = 0.;
    cxdouble equinox   = 2000.;
    cxdouble longitude = 0.;
    cxdouble latitude  = 0.;
    cxdouble elevation = 0.;
    cxdouble tel_ra    = 0.;
    cxdouble tel_dec   = 0.;

    const cpl_propertylist* properties = NULL;

    cpl_table* _fibers = NULL;


    if ((fibers == NULL) || (spectra == NULL)) {
        return -1;
    }

    properties = giraffe_image_get_properties(spectra);
    cx_assert(properties != NULL);


    /*
     * Get time related information
     */

    if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
        return 1;
    }
    else {
        exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
    }

    if (cpl_propertylist_has(properties, GIALIAS_MJDOBS) == FALSE) {
        return 1;
    }
    else {

        /*
         * Compute julian date of mid exposure. 2400000.5 is the offset
         * between JD and MJD and corresponds to November 17th 1858 0:00 UT.
         */

        jd = cpl_propertylist_get_double(properties, GIALIAS_MJDOBS);
        jd += 2400000.5 + 0.5 * exptime / (24. * 3600.);

    }

    if (cpl_propertylist_has(properties, GIALIAS_EQUINOX) == FALSE) {
        return 1;
    }
    else {
        equinox = cpl_propertylist_get_double(properties, GIALIAS_EQUINOX);
    }


    /*
     * Get telescope location and elevation.
     */

    if (cpl_propertylist_has(properties, GIALIAS_TEL_LON) == FALSE) {
        return 2;
    }
    else {

        /*
         * The sign of the property TEL.GEOLON is defined as east = positive
         * For the computation we need west = positive.
         */

        longitude = -cpl_propertylist_get_double(properties, GIALIAS_TEL_LON);

    }

    if (cpl_propertylist_has(properties, GIALIAS_TEL_LAT) == FALSE) {
        return 2;
    }
    else {
        latitude = cpl_propertylist_get_double(properties, GIALIAS_TEL_LAT);
    }

    if (cpl_propertylist_has(properties, GIALIAS_TEL_ELEV) == FALSE) {
        return 2;
    }
    else {
        elevation = cpl_propertylist_get_double(properties, GIALIAS_TEL_ELEV);
    }


    /*
     * Get telescope pointing
     */

    if (cpl_propertylist_has(properties, GIALIAS_RADEG) == FALSE) {
        return 4;
    }
    else {
        tel_ra = cpl_propertylist_get_double(properties, GIALIAS_RADEG);
    }

    if (cpl_propertylist_has(properties, GIALIAS_DECDEG) == FALSE) {
        return 4;
    }
    else {
        tel_dec = cpl_propertylist_get_double(properties, GIALIAS_DECDEG);
    }

    properties = NULL;


    /*
     * Get observed objects right ascension and declination
     */

    _fibers = giraffe_table_get(fibers);

    if ((cpl_table_has_column(_fibers, "RA") == FALSE) ||
        (cpl_table_has_column(_fibers, "DEC") == FALSE)) {
        return 3;
    }

    if (cpl_table_has_column(_fibers, "RP") == FALSE) {
        return -1;
    }


    giraffe_error_push();

    if (cpl_table_has_column(_fibers, "GCORR") == FALSE) {
        cpl_table_new_column(_fibers, "GCORR", CPL_TYPE_DOUBLE);
    }

    if (cpl_table_has_column(_fibers, "HCORR") == FALSE) {
        cpl_table_new_column(_fibers, "HCORR", CPL_TYPE_DOUBLE);
    }

    if (cpl_table_has_column(_fibers, "BCORR") == FALSE) {
        cpl_table_new_column(_fibers, "BCORR", CPL_TYPE_DOUBLE);
    }

    if (cpl_error_get_code() != CPL_ERROR_NONE) {
        return -2;
    }

    giraffe_error_pop();


    nr = cpl_table_get_nrow(_fibers);

    for (fiber = 0; fiber < nr; ++fiber) {

        cxint rp = cpl_table_get_int(_fibers, "RP", fiber, NULL);

        GiRvCorrection rv = {0., 0., 0.};


        if (rp != -1) {

            register cxdouble ra  = 0.;
            register cxdouble dec = 0.;


            /*
             * Argus fibers have no associated position. In this case use
             * the telescope pointing to compute the correction. Argus object
             * fibers have rp set to 0.
             */

            if (rp == 0) {

                ra = tel_ra;
                dec = tel_dec;

            }
            else {

                ra = cpl_table_get_double(_fibers, "RA", fiber, NULL);
                dec = cpl_table_get_double(_fibers, "DEC", fiber, NULL);

            }


            /*
             * The right ascension must be in hours
             */

            ra /= 15.;

            giraffe_rvcorrection_compute(&rv, jd, longitude, latitude,
                                         elevation, ra, dec, equinox);


        }

        cpl_table_set_double(_fibers, "GCORR", fiber, rv.gc);
        cpl_table_set_double(_fibers, "HCORR", fiber, rv.hc);
        cpl_table_set_double(_fibers, "BCORR", fiber, rv.bc);

    }

    return 0;
}
/**@}*/
