/*
 * 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 <math.h>

#include "gialias.h"
#include "gisutils.h"


/**
 * @defgroup gisutils Spectroscopy Utility Functions
 *
 * TBD
 */

/**@{*/

GiImage *
giraffe_integrate_flux(GiImage *spectrum, GiRange *limits)
{

    cxint i = 0;
    cxint k = 0;
    cxint first = 0;
    cxint last = 0;
    cxint nx = 0;
    cxint status = 0;

    cxdouble wmin = 0.;
    cxdouble wmax = 0.;
    cxdouble wstep = 0.;
    cxdouble fstart = 0.;
    cxdouble fend = 0.;

    cpl_propertylist *properties = giraffe_image_get_properties(spectrum);

    cpl_image *_spectrum = giraffe_image_get(spectrum);
    cpl_image *_flux = NULL;

    GiImage *flux = NULL;


    if (properties == NULL || _spectrum == NULL) {
        return NULL;
    }


    if (!cpl_propertylist_has(properties, GIALIAS_BINWLMIN)) {
        return NULL;
    }

    wmin = cpl_propertylist_get_double(properties, GIALIAS_BINWLMIN);


    if (!cpl_propertylist_has(properties, GIALIAS_BINWLMAX)) {
        return NULL;
    }

    wmax = cpl_propertylist_get_double(properties, GIALIAS_BINWLMAX);


    if (!cpl_propertylist_has(properties, GIALIAS_BINSTEP)) {
        return NULL;
    }

    wstep = cpl_propertylist_get_double(properties, GIALIAS_BINSTEP);


    /*
     * Determine the pixel limits for the integration from the
     * given wavelength range.
     */

    last = cpl_image_get_size_y(_spectrum) - 1;

    if (giraffe_range_get_min(limits) > wmin) {

        cxdouble pixel = (giraffe_range_get_min(limits) - wmin) / wstep;

        first  = ceil(pixel);
        fstart = pixel - first;
    }

    if (giraffe_range_get_max(limits) < wmax) {

        cxdouble pixel = (giraffe_range_get_max(limits) - wmin) / wstep;

        last = floor(pixel);
        fend = pixel - last;
    }


    /*
     * Sum fluxes along the dispersion direction (image y-axis) for
     * the defined window.
     */

    nx = cpl_image_get_size_x(_spectrum);

    _flux = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE);

    if (_flux == NULL) {
        return NULL;
    }
    else {

        cxdouble *data = cpl_image_get_data(_spectrum);
        cxdouble *fx = cpl_image_get_data(_flux);

        for (k = first; k < last; ++k) {

            for (i = 0; i < nx; i++) {
                fx[i] += data[k * nx + i];
            }

        }

    }


    /*
     * Add fluxes for the pixel fractions at the beginning and the end of
     * the image window.
     */

    if ((first - 1) >= 0) {

        cxint j = (first - 1) * nx;

        cxdouble *data = cpl_image_get_data(_spectrum);
        cxdouble *fx = cpl_image_get_data(_flux);


        for (i = 0; i < nx; i++) {
            fx[i] += data[j + i] * fstart;
        }
    }


    if ((last + 1 ) < cpl_image_get_size_y(_spectrum)) {

        cxint j = last * nx;

        cxdouble *data = cpl_image_get_data(_spectrum);
        cxdouble *fx = cpl_image_get_data(_flux);


        for (i = 0; i < nx; i++) {
            fx[i] += data[j + i] * fend;
        }
    }

    flux = giraffe_image_new(CPL_TYPE_DOUBLE);

    status = giraffe_image_set(flux, _flux);
    cpl_image_delete(_flux);

    if (status != 0) {
        giraffe_image_delete(flux);
        return NULL;
    }

    status = giraffe_image_set_properties(flux, properties);

    if (status != 0) {
        giraffe_image_delete(flux);
        return NULL;
    }

    return flux;

}
/**@}*/
