/* $Id: visir_spc_wcal_ech.c,v 1.70 2012/01/12 13:56:27 llundin 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: llundin $
 * $Date: 2012/01/12 13:56:27 $
 * $Revision: 1.70 $
 * $Name: visir-3_5_1 $
 */

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

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

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

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

#define RECIPE_STRING "visir_spc_wcal_ech"

/*-----------------------------------------------------------------------------
                            Private Functions prototypes
 -----------------------------------------------------------------------------*/
static cpl_error_code visir_spc_wcal_ech_save(cpl_frameset *,
                                              const cpl_parameterlist *,
                                              const cpl_propertylist *,
                                              const cpl_propertylist *,
                                              const cpl_table *);

VISIR_RECIPE_DEFINE(visir_spc_wcal_ech,
                    VISIR_PARAM_ZERODIST | VISIR_PARAM_ORDEROFF |
                    VISIR_PARAM_AUTOBPM  |
                    VISIR_PARAM_PLOT     | VISIR_PARAM_SLITSKEW |
                    VISIR_PARAM_SPECSKEW | VISIR_PARAM_VERTARC  |
                    VISIR_PARAM_REJLEFT | VISIR_PARAM_REJRIGHT |
                    VISIR_PARAM_HORIARC,
                    "Spectroscopic wavelength calibration recipe in Echelle",
                    "This recipe estimates the dispersion relation using the "
                    "atmospheric spectrum\n"
                    "in a grism spectroscopy half-cycle frame.\n"
                    "The files listed in the Set Of Frames (sof-file) "
                    "must be tagged:\n"
                    "VISIR-Echelle-Spectroscopy-file.fits "
                    VISIR_SPC_WCAL_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"
                    MAN_VISIR_CALIB_BPM_SPC);

/*-----------------------------------------------------------------------------
                            Static variables
 -----------------------------------------------------------------------------*/

static struct {
    /* Inputs */
    int         auto_bpm;
    int         plot;
    int         orderoffset;
    double      phi;
    double      ksi;
    double      eps;
    double      delta;

} visir_spc_wcal_ech_config;


/*----------------------------------------------------------------------------*/
/**
 * @defgroup visir_spc_wcal_ech   Echelle Spectroscopic Wavelength Calibration
 */
/*----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
                                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_spc_wcal_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      *   spc_cal_qeff;
    const char      *   spc_cal_lines;
    cpl_imagelist   *   hcycle = NULL;
    cpl_image       *   imhcycle = NULL;
    cpl_table       *   spc_table = NULL;
    cpl_image       *   order = NULL;
    double              wlen, slitw, temp, fwhm;
    int                 icol1, icol2;
    int                 jcol1, jcol2;
    visir_spc_resol     resol;


    visir_spc_wcal_ech_config.auto_bpm = 
        visir_parameterlist_get_bool(parlist, RECIPE_STRING, VISIR_PARAM_AUTOBPM);
    visir_spc_wcal_ech_config.plot =
        visir_parameterlist_get_int(parlist, RECIPE_STRING, VISIR_PARAM_PLOT);

    visir_spc_wcal_ech_config.phi = 
        visir_parameterlist_get_double(parlist,RECIPE_STRING,VISIR_PARAM_SLITSKEW);
    visir_spc_wcal_ech_config.ksi = 
        visir_parameterlist_get_double(parlist,RECIPE_STRING,VISIR_PARAM_SPECSKEW);
    visir_spc_wcal_ech_config.eps = 
        visir_parameterlist_get_double(parlist,RECIPE_STRING, VISIR_PARAM_VERTARC);
    visir_spc_wcal_ech_config.delta = 
        visir_parameterlist_get_double(parlist,RECIPE_STRING, VISIR_PARAM_HORIARC);

    visir_spc_wcal_ech_config.orderoffset = 
        visir_parameterlist_get_int(parlist, RECIPE_STRING, VISIR_PARAM_ORDEROFF);

    jcol1 = visir_parameterlist_get_int(parlist, RECIPE_STRING,
                                        VISIR_PARAM_REJLEFT);
    jcol2 = visir_parameterlist_get_int(parlist, RECIPE_STRING,
                                        VISIR_PARAM_REJRIGHT);

    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_WCAL_ECH_RAW);
    skip_if (rawframes == NULL);

    irplib_framelist_empty(allframes);

    skip_if(irplib_framelist_load_propertylist(rawframes, 0, 0, "^("
                                               VISIR_PFITS_REGEXP_LOAD_IMAGELIST
                                               "|"
                                               VISIR_PFITS_REGEXP_SPC_GET_RES_WL
                                               "|" VISIR_PFITS_REGEXP_CAPA "|"
                                               VISIR_PFITS_REGEXP_SPC_WCAL_PAF
                                               ")$", CPL_FALSE));

    skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
                                               VISIR_PFITS_REGEXP_LOAD_IMAGELIST
                                               "|"
                                               VISIR_PFITS_REGEXP_SPC_GET_RES_WL
                                               ")$", CPL_FALSE));

    skip_if(visir_dfs_check_framelist_tag(rawframes));
    
    /* 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);

    /* Get Resolution and Central Wavelength */
    resol = visir_spc_get_res_wl(rawframes, &wlen, &slitw, &temp, &fwhm);
   
    skip_if (0);

    if (resol != VISIR_SPC_R_GHR) {
        if (visir_spc_wcal_ech_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",
                          visir_spc_wcal_ech_config.orderoffset);
            visir_error_set(CPL_ERROR_TYPE_MISMATCH);
            skip_if(1);
        }
    }
   
    /* Get the hcycle image from the reference file */
    hcycle = visir_load_hcycle(rawframes, 0);
    skip_if (0);

    imhcycle = cpl_imagelist_get(hcycle, 0);

    skip_if (visir_spc_det_fix(&imhcycle, 1, CPL_FALSE,
                               wlen, resol,
                               visir_spc_wcal_ech_config.phi,
                               visir_spc_wcal_ech_config.ksi,
                               visir_spc_wcal_ech_config.eps,
                               visir_spc_wcal_ech_config.delta, 
                               visir_spc_wcal_ech_config.plot));

    skip_if (visir_spc_echelle_limit(&icol1, &icol2, wlen,
                                     visir_spc_wcal_ech_config.orderoffset, 1,
                           cpl_image_get_size_y(imhcycle)));

    skip_if(visir_qc_append_background(qclist, rawframes, icol1, icol2));

    if (jcol1 != 0) {
        cpl_msg_info(cpl_func, "Ignoring %d leftmost columns from %d to %d",
                     jcol1, icol1, icol1 + jcol1);
        icol1 += jcol1;
    }
    if (jcol2 != 0) {
        cpl_msg_info(cpl_func, "Ignoring %d rightmost columns from %d to %d",
                     jcol2, icol2 - jcol2, icol2);
        icol2 -= jcol2;
    }

    if (icol1 != 1 || icol2 != cpl_image_get_size_x(imhcycle)) {

        order = visir_spc_column_extract(imhcycle, icol1, icol2,
                                          visir_spc_wcal_ech_config.plot);
        skip_if (0);
    } else {
        /* Cannot really succeed from here... */
        order = imhcycle;
    }

    skip_if (visir_spc_wavecal(order, qclist, wlen, slitw, temp, fwhm, resol,
                               visir_spc_wcal_ech_config.orderoffset,
                               spc_cal_lines, spc_cal_qeff,
                               &spc_table, visir_spc_wcal_ech_config.plot));

    /* This column is not part of the product */
    skip_if (cpl_table_erase_column(spc_table, "SPC_EMISSIVITY"));

    bug_if (visir_spectro_qc(qclist, paflist, CPL_FALSE, rawframes, NULL,
                             "^(" VISIR_PFITS_REGEXP_SPC_WCAL_PAF ")$"));
    irplib_framelist_empty(rawframes);
   
    /* Save the spectrum */
    cpl_msg_info(cpl_func, "Saving the produced spectrum");

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

    skip_if (visir_spc_wcal_ech_save(framelist, parlist, qclist, paflist,
                                     spc_table));

    end_skip;

    cpl_propertylist_delete(qclist);
    cpl_propertylist_delete(paflist);
    irplib_framelist_delete(allframes);
    irplib_framelist_delete(rawframes);
    cpl_table_delete(spc_table);
    if (order != imhcycle) cpl_image_delete(order);
    cpl_imagelist_delete(hcycle);

    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Save the visir_spc_wcal_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    table       The spectral fields
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code visir_spc_wcal_ech_save(cpl_frameset            * set, 
                                              const cpl_parameterlist * parlist,
                                              const cpl_propertylist  * qclist,
                                              const cpl_propertylist  * paflist,
                                              const cpl_table         * table)
{
    bug_if (0);

    /* THE TABLE */
    skip_if (irplib_dfs_save_table(set, parlist, set, table, NULL, RECIPE_STRING,
                               VISIR_SPC_WCAL_ECH_TAB_PROCATG,
                               qclist, NULL, visir_pipe_id,
                               RECIPE_STRING "_spectrum_tab" 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();
}
