/* $Id: visir_spc_phot_ech.c,v 1.77 2012-08-21 09:56:14 jtaylor Exp $
 *
 * This file is part of the VISIR Pipeline
 * Copyright (C) 2002,2003 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
 */

/*
 * $Author: jtaylor $
 * $Date: 2012-08-21 09:56:14 $
 * $Revision: 1.77 $
 * $Name: not supported by cvs2svn $
 */

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


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

#include "visir_recipe.h"
#include "visir_spectro.h"
#include "visir_spc_distortion.h"
#include "visir_spc_photom.h"

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

#define RECIPE_STRING   "visir_old_spc_phot_ech"

/* FITS keys to be loaded for all raw files */
#define RECIPE_KEYS_REGEXP_ALL            \
        VISIR_PFITS_REGEXP_IMG_RECOMBINE  \
    "|" VISIR_PFITS_REGEXP_SPC_GET_RES_WL \
    "|" VISIR_PFITS_REGEXP_SPC_SENSIT

/* FITS keys to be loaded for first raw file */
#define RECIPE_KEYS_REGEXP               \
        RECIPE_KEYS_REGEXP_ALL           \
    "|" VISIR_PFITS_SPC_PHOT_COPY        \
    "|" VISIR_PFITS_REGEXP_CAPA          \
    "|" VISIR_PFITS_REGEXP_SPC_PHOT_PAF

/* FITS keys to be loaded for first raw file, in case WCS is used */
#define RECIPE_KEYS_REGEXP_WCS \
        RECIPE_KEYS_REGEXP \
    "|" IRPLIB_PFITS_WCS_REGEXP

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

static cpl_error_code visir_spc_phot_ech_save(cpl_frameset *,
                                              const cpl_parameterlist *,
                                              const cpl_propertylist *,
                                              const cpl_propertylist *,
                                              const cpl_image *,
                                              const cpl_image *,
                                              const cpl_table *);

VISIR_RECIPE_DEFINE(visir_old_spc_phot_ech,
                    VISIR_PARAM_EMIS_TOL |
                    VISIR_PARAM_ZERODIST | VISIR_PARAM_ORDEROFF |
                    VISIR_PARAM_REFINE | VISIR_PARAM_XCORR |
                    VISIR_PARAM_OFFSETS | VISIR_PARAM_OBJECTS |
                    VISIR_PARAM_NODPOS | VISIR_PARAM_AUTOBPM |
                    VISIR_PARAM_GLITCH | VISIR_PARAM_PURGE |
                    VISIR_PARAM_UNION  | VISIR_PARAM_REJECT |
                    VISIR_PARAM_STRIPITE | VISIR_PARAM_STRIPMOR |
                    VISIR_PARAM_PLOT   | VISIR_PARAM_SLITSKEW |
                    VISIR_PARAM_SPECSKEW | VISIR_PARAM_VERTARC |
                    VISIR_PARAM_REJLEFT | VISIR_PARAM_REJRIGHT |
                    VISIR_PARAM_HORIARC | VISIR_PARAM_FIXCOMBI |
                    VISIR_PARAM_GAIN | VISIR_PARAM_RONOISE |
                    VISIR_PARAM_OXSIGMA | VISIR_PARAM_OXNITER |
                    VISIR_PARAM_OXSMOOTH | VISIR_PARAM_OXKERNEL,
                    "Old DRS detector: Sensitivity computation in echelle spectroscopy",
                    "This recipe estimates the dispersion relation using the "
                    "atmospheric spectrum\n"
                    "in a echelle spectroscopy half-cycle frame.\n"
                    "It also extracts the spectrum of an observed object "
                    "using a combined frame.\n"
                    "Lastly, it computes the spectral photometry of an "
                    "observed standard star.\n"
                    "The files listed in the Set Of Frames (sof-file) "
                    "must be tagged:\n"
                    "VISIR-Echelle-Spectroscopy-file.fits "
                    VISIR_SPC_PHOT_ECH_RAW "\n"
                    "VISIR-Quantum-Efficiency-Calibration-file.fits "
                    VISIR_CALIB_QEFF_SPC "\n"
                    "VISIR-Atmospheric-Emission-Lines-Calibration-file.fits "
                    VISIR_CALIB_LINES_SPC
                    "\n"
                    "VISIR-Spectroscopic-Standard-Star-Catalog.fits "
                    VISIR_CALIB_STDSTAR_SPC "\n"
                    MAN_VISIR_CALIB_BPM_SPC);

/*----------------------------------------------------------------------------*/
/**
 * @defgroup visir_spc_phot_ech   Sensitivity in spectroscopy in Echelle mode
 */
/*----------------------------------------------------------------------------*/

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

/*----------------------------------------------------------------------------*/
/**
  @brief    The recipe data reduction part is implemented here 
  @param    parlist     the parameters list
  @param    framelist   the frames list
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static int visir_old_spc_phot_ech(cpl_frameset            * framelist,
                              const cpl_parameterlist * parlist)
{
    irplib_framelist * allframes = NULL;
    irplib_framelist * rawframes = NULL;
    cpl_propertylist * qclist    = cpl_propertylist_new();
    cpl_propertylist * paflist   = cpl_propertylist_new();
    const char       * badpix;
    const char       * star_cat;
    const char       * spc_cal_qeff;
    const char       * spc_cal_lines;
    const char       * flat;
    cpl_image       ** combinedpair = NULL;
    cpl_image        * combined = NULL;
    cpl_table        * tab = NULL;
    cpl_image        * weight2d = NULL;
    double             wlen, slitw, temp, fwhm;
    visir_spc_resol    resol;
    visir_spc_config   config;
    cpl_boolean        drop_wcs;
    const char       * keys_regexp = "^(" RECIPE_KEYS_REGEXP_WCS
                                      "|" VISIR_PFITS_REGEXP_DIT
                                      ")$";
    const char       * dit_key = VISIR_PFITS_DOUBLE_DIT;

    config.recipename = RECIPE_STRING;
    config.parlist = parlist;

    /* Retrieve input parameters */
    config.do_fixcombi = visir_parameterlist_get_bool(
            parlist, RECIPE_STRING, VISIR_PARAM_FIXCOMBI);
    config.plot = visir_parameterlist_get_int(
            parlist, RECIPE_STRING, VISIR_PARAM_PLOT);
    config.phi = visir_parameterlist_get_double(
            parlist, RECIPE_STRING, VISIR_PARAM_SLITSKEW);
    config.ksi = visir_parameterlist_get_double(
            parlist, RECIPE_STRING, VISIR_PARAM_SPECSKEW);
    config.eps = visir_parameterlist_get_double(
            parlist, RECIPE_STRING, VISIR_PARAM_VERTARC);
    config.delta = visir_parameterlist_get_double(
            parlist, RECIPE_STRING, VISIR_PARAM_HORIARC);
    config.gain = visir_parameterlist_get_double(
            parlist, RECIPE_STRING, VISIR_PARAM_GAIN);
    config.ron = visir_parameterlist_get_double(
            parlist, RECIPE_STRING, VISIR_PARAM_RONOISE);
    config.ox_sigma = visir_parameterlist_get_double(
            parlist, RECIPE_STRING, VISIR_PARAM_OXSIGMA);
    config.ox_niters = visir_parameterlist_get_int(
            parlist, RECIPE_STRING, VISIR_PARAM_OXNITER);
    config.ox_smooth = visir_parameterlist_get_int(
            parlist, RECIPE_STRING, VISIR_PARAM_OXSMOOTH);
    config.ox_kernel = visir_parameterlist_get_int(
            parlist, RECIPE_STRING, VISIR_PARAM_OXKERNEL);
    config.orderoffset = visir_parameterlist_get_int(
            parlist, RECIPE_STRING, VISIR_PARAM_ORDEROFF);
    config.phot_emis_tol = visir_parameterlist_get_double(
            parlist, RECIPE_STRING, VISIR_PARAM_EMIS_TOL);
    config.bkgcorrect = CPL_FALSE;

    skip_if (0);

    /* Identify the RAW and CALIB frames in the input frameset */
    skip_if (visir_dfs_set_groups(framelist));

    /* Objects observation */
    allframes = irplib_framelist_cast(framelist);
    skip_if (allframes == NULL);
    rawframes = irplib_framelist_extract(allframes, VISIR_SPC_PHOT_ECH_RAW);
    skip_if (rawframes == NULL);

    irplib_framelist_empty(allframes);

    skip_if(irplib_framelist_load_propertylist(rawframes, 0, 0, keys_regexp,
                                               CPL_FALSE));

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

    skip_if(visir_dfs_check_framelist_tag(rawframes));
    
    if (cpl_propertylist_has(irplib_framelist_get_propertylist(rawframes, 0),
                             VISIR_PFITS_DOUBLE_SEQ1_DIT))
        dit_key = VISIR_PFITS_DOUBLE_SEQ1_DIT;
    skip_if(0);

    /* Standard star catalog */
    star_cat = irplib_frameset_find_file(framelist, VISIR_CALIB_STDSTAR_SPC);
    if (star_cat == NULL) {
         cpl_msg_error(cpl_func, "The file with the star catalog is missing");
         skip_if(1);
    }

    /* Quantum efficiency file */
    spc_cal_qeff = irplib_frameset_find_file(framelist, VISIR_CALIB_QEFF_SPC);

    /* Spectral lines calibration file */
    spc_cal_lines = irplib_frameset_find_file(framelist, VISIR_CALIB_LINES_SPC);

    /* Bad pixels calibration file */
    badpix = irplib_frameset_find_file(framelist, VISIR_CALIB_BPM);

    /* Flatfield calibration file */
    flat = irplib_frameset_find_file(framelist, VISIR_CALIB_FLAT);

    /* Get the resolution and central wavelength */
    resol = visir_spc_get_res_wl(rawframes, &wlen, &slitw, &temp, &fwhm, 0);

    skip_if (0);

    if (resol != VISIR_SPC_R_GHR) {
        if (config.orderoffset == 0) {
            cpl_msg_warning(cpl_func,"Reducing non-HR Grism data as main order");
        } else {
            cpl_msg_error(cpl_func, "This recipe cannot reduce non-HR Grism "
                          "data with an order-offset of %d",
                          config.orderoffset);
            visir_error_set(CPL_ERROR_TYPE_MISMATCH);
            skip_if(1);
        }
    }

    /* Combine the frames */
    combinedpair = visir_img_recombine(RECIPE_STRING, parlist, rawframes, badpix,
                                       flat, CPL_GEOM_FIRST, &drop_wcs,
                                       !config.do_fixcombi, wlen, resol);

    if (combinedpair == NULL) {
        cpl_msg_error(cpl_func, "Could not combine the input frames");
        skip_if (1);
    }

    cpl_image_delete(combinedpair[1]);
    combined = cpl_image_cast(combinedpair[0], CPL_TYPE_DOUBLE);
    cpl_image_delete(combinedpair[0]);

    skip_if (0);

    /* Compute here the sensitivity */
    cpl_msg_info(cpl_func, "Compute the sensitivity");
    config.phu = qclist;
    tab = visir_spc_phot_sensit_from_image(&combined, rawframes, &config,
                                           star_cat, spc_cal_lines,
                                           spc_cal_qeff, &weight2d, qclist,
                                           CPL_TRUE, wlen, slitw, temp, fwhm,
                                           resol, dit_key);

    if (tab == NULL) {
        cpl_msg_error(cpl_func, "Cannot compute sensitivity: '%s' in %s",
                        cpl_error_get_message(), cpl_error_get_where());
        skip_if(1);
    }

    bug_if (visir_spectro_qc(qclist, paflist, drop_wcs, rawframes, 
                             "^(" VISIR_PFITS_SPC_PHOT_COPY ")$",
                             "^(" VISIR_PFITS_REGEXP_SPC_PHOT_PAF ")$"));
    irplib_framelist_empty(rawframes);
   
    /* Save the results */
    cpl_msg_info(cpl_func, "Save the results");

    /* PRO.CATG */
    bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
                                           VISIR_SPC_PHOT_ECH_COMBINED_PROCATG));

    skip_if (visir_spc_phot_ech_save(framelist, parlist, qclist, paflist,
                                     combined, weight2d, tab));

    end_skip;

    cpl_propertylist_delete(qclist);
    cpl_propertylist_delete(paflist);
    irplib_framelist_delete(allframes);
    irplib_framelist_delete(rawframes);
    cpl_image_delete(combined);
    cpl_table_delete(tab);
    cpl_image_delete(weight2d);

    cpl_free(combinedpair);

    return cpl_error_get_code();
}
 
/*----------------------------------------------------------------------------*/
/**
  @brief    Save the visir_spc_phot_ech recipe products on disk
  @param    set         The input frame set
  @param    parlist     The input list of parameters
  @param    qclist      List of QC parameters
  @param    paflist     List of PAF parameters
  @param    combined    The combined image produced
  @param    weight2d    2D weights image
  @param    table       The spectral fields
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code visir_spc_phot_ech_save(cpl_frameset            * set,
                                              const cpl_parameterlist * parlist,
                                              const cpl_propertylist  * qclist,
                                              const cpl_propertylist  * paflist,
                                              const cpl_image         *combined,
                                              const cpl_image         *weight2d,
                                              const cpl_table         * table)
{
    bug_if (0);

    /* THE TABLE */
    skip_if (irplib_dfs_save_table(set, parlist, set, table, NULL, RECIPE_STRING,
                               VISIR_SPC_PHOT_ECH_TAB_PROCATG,
                               qclist, NULL, visir_pipe_id,
                               RECIPE_STRING "_tab" CPL_DFS_FITS));

    /* THE COMBINED IMAGE */
    skip_if (irplib_dfs_save_image(set, parlist, set, combined, CPL_BPP_IEEE_FLOAT,
                               RECIPE_STRING, VISIR_SPC_PHOT_ECH_COMBINED_PROCATG,
                               qclist, NULL, visir_pipe_id,
                               RECIPE_STRING CPL_DFS_FITS));

    /* THE WEIGHT IMAGE */
    skip_if (irplib_dfs_save_image(set, parlist, set, weight2d, CPL_BPP_IEEE_FLOAT,
                               RECIPE_STRING, VISIR_SPC_PHOT_ECH_WEIGHT_PROCATG,
                               qclist, NULL, visir_pipe_id,
                               RECIPE_STRING "_weight" CPL_DFS_FITS));

#ifdef VISIR_SAVE_PAF
    /* THE PAF FILE FOR QC PARAMETERS */
    skip_if (cpl_dfs_save_paf("VISIR", RECIPE_STRING, paflist,
                             RECIPE_STRING CPL_DFS_PAF));
#else
    bug_if(paflist == NULL);
#endif

    end_skip;

    return cpl_error_get_code();

}
