/*
 * This file is part of the VISIR Pipeline
 * Copyright (C) 2012,2015 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  02111-1307  USA
 */

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

/*-----------------------------------------------------------------------------
  Includes
  -----------------------------------------------------------------------------*/

#include "visir_recipe.h"

#include <string.h>

/*-----------------------------------------------------------------------------
  Defines
  -----------------------------------------------------------------------------*/

#define RECIPE_STRING   "visir_util_qc"

/*-----------------------------------------------------------------------------
  Private Functions prototypes
  -----------------------------------------------------------------------------*/

#ifdef VISIR_CHAIN
#define cpl_plugin_get_info visir_util_qc_get_info
#endif
// FIXME:
cpl_recipe_define(visir_util_qc, VISIR_BINARY_VERSION,
                  "Julian Taylor", PACKAGE_BUGREPORT, "2012",
                  "Prepares qc parameters from data where the beam has "
                  "been deteteced and bad images have been removed",
                  "The files listed in the Set Of Frames (sof-file) "
                  "must be tagged:\n"
                  "VISIR-chopnod-corrected-file.fits "VISIR_UTIL_CORRECTED
                  "\nThe product(s) will have a FITS card\n"
                  "'HIERARCH ESO PRO CATG' with a value of: "
                  VISIR_UTIL_QC_PROCATG"\n");

/*----------------------------------------------------------------------------*/
/**
 * @defgroup visir_util_qc   remove stripes
 */
/*----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
  Functions code
  -----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------*/
/**
  @internal
  @brief    Fill the recipe parameterlist
  @param    self  The parameterlist
  @return   0 iff everything is ok

*/
/*----------------------------------------------------------------------------*/
static cpl_error_code
visir_util_qc_fill_parameterlist(cpl_parameterlist * self)
{
    if (self) {}
    return CPL_ERROR_NONE;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    The recipe data reduction part is implemented here
  @param    framelist   the frames list
  @param    parlist     the parameters list
  @return   0 iff everything is ok
  */
/*----------------------------------------------------------------------------*/
static int visir_util_qc(cpl_frameset            * framelist,
                         const cpl_parameterlist * parlist)
{
    cpl_frameset * usedframes = cpl_frameset_new();
    cpl_propertylist * outlist = cpl_propertylist_new();
    irplib_framelist * allframes = irplib_framelist_cast(framelist);
    /* FIXME: macro */
    irplib_framelist * rawframes =
        irplib_framelist_extract(allframes, VISIR_UTIL_CORRECTED);
    const int nrawframes = irplib_framelist_get_size(rawframes);
    cpl_boolean undefined_beampos = CPL_FALSE;
    /* only reading headers file, no cache needed */
    cpl_fits_set_mode(CPL_FITS_STOP_CACHING);

    irplib_framelist_load_propertylist_all(rawframes, 0, ".*", CPL_FALSE);

    double t_exptime = 0;
    double t_eff_exptime = 0;
    cpl_size t_nimages = 0;
    cpl_size t_neff_images = 0;
    double t_bkg_sum = 0;
    double t_min_obsstart = 1e300;
    double t_max_filewrite = 0;

    for (int iframe = 0; iframe < nrawframes; iframe++) {
        cpl_propertylist * plist =
            irplib_framelist_get_propertylist(rawframes, iframe);
        cpl_frame * frm = irplib_framelist_get(rawframes, iframe);
        float imgwgt = visir_pfits_get_img_weight(plist);
        visir_data_type dtype;
        visir_get_data_type(frm, plist, &dtype, NULL);
        t_max_filewrite =
            CX_MAX(cpl_propertylist_get_double(plist, "ESO DRS DATE"),
                   t_max_filewrite);
        t_min_obsstart =
            CX_MIN(cpl_propertylist_get_double(plist, "ESO DRS DATE-OBS"),
                   t_min_obsstart);

        const int ndit = visir_pfits_get_ndit(plist);
        const int navrg = visir_pfits_get_navrg(plist);

        const double dit = visir_pfits_get_dit(plist);
        if (iframe == 0)
            cpl_propertylist_append(outlist, plist);

        const cpl_size ncycles = visir_pfits_get_chop_ncycles(plist);
        const char * beamid = cpl_propertylist_get_string(plist, "ESO QC BEAMID");

        double time_per_img;
        cpl_size nimages;
        if (visir_data_is_burst(dtype)) {
            time_per_img = dit * navrg;
            nimages = ncycles * ndit / navrg;
        }
        else if (dtype == VISIR_DATA_AQU_INT) {
            time_per_img = ncycles * dit * ndit * navrg;
            nimages = 1;
        }
        else {
            time_per_img = dit * ndit * navrg;
            nimages = ncycles / navrg;
        }
        const cpl_size neff_images = cpl_frame_get_nextensions(frm);

        double exptime = nimages * time_per_img;
        double eff_exptime = neff_images * time_per_img;
        double bkg_sum = 0;

        exptime *= imgwgt;
        eff_exptime *= imgwgt;

        char filename[128];
        sprintf(filename, "qc_header_%03d.fits", iframe);

        if (cpl_propertylist_has(plist, "ESO QC BACKGD MEAN"))
            bkg_sum = cpl_propertylist_get_double(plist, "ESO QC BACKGD MEAN");

        if (strcmp(beamid, "UNDEFINED") == 0)
            undefined_beampos = CPL_TRUE;

        cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
        cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));


        cpl_propertylist_append_double(outlist, "ESO DRS IMGWGT", imgwgt);
        /* signal exptime, the real exptime is nbeams times larger due to chop/nodding */
        cpl_propertylist_append_double(outlist, "ESO QC EXPTIME TOTAL", exptime);
        cpl_propertylist_append_double(outlist, "ESO QC EXPTIME EFFECTIVE", eff_exptime);
        cpl_propertylist_append_int(outlist, "ESO QC NIMAGES TOTAL", (int)nimages);
        cpl_propertylist_append_int(outlist, "ESO QC NIMAGES EFFECTIVE",
                                    (int)neff_images);
        cpl_propertylist_append_double(outlist, "ESO QC BACKGD MEAN", bkg_sum);
        cpl_propertylist_update_string(outlist, "ESO QC BEAMID", beamid);
        cpl_propertylist_update_double(outlist, "ESO QC BEAMX",
                                       cpl_propertylist_get_double(plist, "ESO QC BEAMX"));
        cpl_propertylist_update_double(outlist, "ESO QC BEAMY",
                                       cpl_propertylist_get_double(plist, "ESO QC BEAMY"));
        cpl_propertylist_append_double(outlist, "ESO QC EXECTIME",
                                       (t_max_filewrite - t_min_obsstart) * 24 * 3600);

        irplib_dfs_save_propertylist(framelist, parlist, usedframes,
                                     RECIPE_STRING,
                                     nrawframes > 1 ? VISIR_UTIL_QC_PROCATG :
                                     VISIR_UTIL_QC_PROCATG "_COMBINED",
                                     outlist, NULL,
                                     visir_pipe_id, filename);
        skip_if(0);

        t_nimages += nimages;
        t_neff_images += neff_images;
        t_exptime += exptime;
        t_eff_exptime += eff_exptime;
        t_bkg_sum += bkg_sum;
    }

    double mean_bkg = t_bkg_sum / nrawframes;

    cpl_msg_info(cpl_func, "Total exposure time: %gs", t_exptime);
    cpl_msg_info(cpl_func, "Total effective exposure time: %gs", t_eff_exptime);
    cpl_msg_info(cpl_func, "Total input images: %d", (int)t_nimages);
    cpl_msg_info(cpl_func, "Total accepted input images: %d", (int)t_neff_images);
    cpl_msg_info(cpl_func, "Mean input background: %g", mean_bkg);

    if (nrawframes > 1) {
        cpl_propertylist_append_double(outlist, "ESO DRS IMGWGT", 1.);
        cpl_propertylist_append_double(outlist, "ESO QC EXPTIME TOTAL", t_exptime);
        cpl_propertylist_append_double(outlist, "ESO QC EXPTIME EFFECTIVE", t_eff_exptime);
        cpl_propertylist_append_int(outlist, "ESO QC NIMAGES TOTAL", (int)t_nimages);
        cpl_propertylist_append_int(outlist, "ESO QC NIMAGES EFFECTIVE",
                                    (int)t_neff_images);
        cpl_propertylist_append_double(outlist, "ESO QC BACKGD MEAN", mean_bkg);
        cpl_propertylist_append_string(outlist, "ESO QC BEAMID",
                                       undefined_beampos ? "UNDEFINED" : "COMBINED");
        cpl_propertylist_erase(outlist, "ESO QC BEAMX");
        cpl_propertylist_erase(outlist, "ESO QC BEAMY");

        cpl_propertylist_append_double(outlist, "ESO QC EXECTIME",
                               (t_max_filewrite - t_min_obsstart) * 24 * 3600);

        skip_if(irplib_dfs_save_propertylist(framelist, parlist, usedframes,
                                             RECIPE_STRING,
                                             VISIR_UTIL_QC_PROCATG"_COMBINED",
                                             outlist, NULL,
                                             visir_pipe_id, "qc_header_all.fits"));
    }

    end_skip;
    cpl_frameset_delete(usedframes);
    irplib_framelist_delete(allframes);
    irplib_framelist_delete(rawframes);
    cpl_propertylist_delete(outlist);

    return cpl_error_get_code();
}
