/* $Id: visir_util_spc_txt2fits.c,v 1.49 2012-08-04 18:05:51 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-08-04 18:05:51 $
 * $Revision: 1.49 $
 * $Name: not supported by cvs2svn $
 */

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

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

#include "visir_recipe.h"

#include <string.h>

/*-----------------------------------------------------------------------------
                            Recipe defines
 -----------------------------------------------------------------------------*/

#define RECIPE_STRING "visir_util_spc_txt2fits"

#ifndef FLEN_VALUE
    /* Copied from CFITSIO */
#define FLEN_VALUE 71
#endif

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

static cpl_error_code visir_propertylist_fill_comments(cpl_propertylist *,
                                                       FILE *);

VISIR_RECIPE_DEFINE(visir_util_spc_txt2fits, VISIR_PARAM_QEFF,
                    "Generate spectrum calibration FITS tables",
                    "This recipe shall be used to generate spectrum "
                    "calibration tables.\n"
                    "The sof file shall consist of 1 line with the name of an "
                    "ASCII-file\n"
                    "currently tagged with either " VISIR_SPC_LINES_ASCII " or "
                    VISIR_SPC_QEFF_ASCII ".\n"
                    "The file must comprise two columns:\n"
                    "1st: Must be wavelengths in increasing order in units "
                    "of meter\n"
                    "2nd: For " VISIR_SPC_LINES_ASCII "-files must be the "
                    "atmospheric emission, "
                    "while\n"
                    "     for " VISIR_SPC_QEFF_ASCII "-files must be the "
                    "quantum efficiency of "
                    "the detector.\n"
                    "A " VISIR_SPC_LINES_ASCII "-file will generate a "
                    VISIR_CALIB_LINES_SPC
                    "-file, and \n"
                    "a " VISIR_SPC_QEFF_ASCII "-file will generate a "
                    VISIR_CALIB_QEFF_SPC
                    "-file.\n"
                    "The current " VISIR_CALIB_LINES_SPC "- and "
                    VISIR_CALIB_QEFF_SPC
                    "-files are\n"
                    "generated using the ASCII-files in the catalogs/ "
                    "directory of the VISIR\n"
                    "source-code distribution.");

/*----------------------------------------------------------------------------*/
/**
 * @defgroup visir_util_spc_txt2fits   Generate spectrum calibration FITS tables
 */
/*----------------------------------------------------------------------------*/

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

/*----------------------------------------------------------------------------*/
/**
  @brief    The FITS file creation occurs here 
  @param    framelist   the frames list
  @return   0 iff everything is ok

  The recipe expects a text file with two columns, and will create a FITS file
  out of it. The default column labels and the PRO CATG may be modified on the
  command line. 
 */
/*----------------------------------------------------------------------------*/
static int visir_util_spc_txt2fits(cpl_frameset            * framelist,
                                   const cpl_parameterlist * parlist)
{
    const char       * label2 = NULL; /* Avoid uninit warning */
    const char       * procat;
    cpl_propertylist * qclist = cpl_propertylist_new();
    irplib_framelist * allframes = NULL;
    irplib_framelist * rawframes = NULL;
    cpl_bivector     * spectrum = NULL;
    cpl_table        * tab = NULL;
    FILE             * stream = NULL;
    int                nframes;
    int                i, nvals;
    
    /* Identify the RAW 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_regexp(allframes, "^("
                                                VISIR_SPC_LINES_ASCII "|"
                                                VISIR_SPC_QEFF_ASCII ")$",
                                                CPL_FALSE);
    skip_if (rawframes == NULL);

    nframes = irplib_framelist_get_size(rawframes);

    /* Loop on all input frames */
    for (i = 0; i < nframes; i++) {
        const cpl_frame * frame = irplib_framelist_get_const(rawframes, i);
        const char * filename = cpl_frame_get_filename(frame);
        const char * basepos;
        const char * dotpos;
        char extname[FLEN_VALUE];
        size_t baselen;

        skip_if(filename == NULL);
        cpl_propertylist_empty(qclist);

        basepos = strrchr(filename, '/');
        basepos = basepos == NULL ? filename : basepos + 1;
        dotpos = strrchr(basepos, '.');
        baselen = dotpos == NULL ? strlen(basepos) : (size_t)(dotpos - basepos);
        if (baselen > 0) {
            strncpy(extname, basepos, CX_MIN(FLEN_VALUE, baselen));
            extname[CX_MIN(FLEN_VALUE - 1, baselen)] = '\0';

            skip_if(cpl_propertylist_append_string(qclist, "EXTNAME", extname));
        }

        if (stream != NULL) fclose(stream);
        stream = fopen(filename, "r");

        skip_if (stream == NULL);

        cpl_bivector_delete(spectrum);
        spectrum = cpl_bivector_new(2481); /* Some 1st guess at actual length */
        skip_if( visir_bivector_load(spectrum, stream));

        if (strcmp(cpl_frame_get_tag(frame), VISIR_SPC_LINES_ASCII)) {
            /* The file is a quantum efficiency file */

            procat = VISIR_SPEC_CAL_QEFF_PROCATG;
            label2 = "Efficiency";

            skip_if(cpl_propertylist_set_comment(qclist, "EXTNAME", "Match "
                                                 "with HIERARCH.ESO."
                                                 "DET.CHIP.NAME"));


        } else {
            /* The file is a sky lines file */
            procat = VISIR_SPEC_CAL_LINES_PROCATG;
            label2 = "Emission";
        }

        /* Get the number of values in the model */
        nvals = cpl_bivector_get_size(spectrum);

        /* Allocate the data container */
        if (tab != NULL) {
            cpl_table_unwrap(tab, "Wavelength");
            cpl_table_unwrap(tab, label2);
            cpl_table_delete(tab);
        }
        tab = cpl_table_new(nvals);

        skip_if( tab == NULL );

        skip_if (cpl_table_wrap_double(tab, cpl_bivector_get_x_data(spectrum),
                                       "Wavelength"));
        skip_if (cpl_table_set_column_unit(tab, "Wavelength", "m"));

        skip_if (cpl_table_wrap_double(tab, cpl_bivector_get_y_data(spectrum),
                                       label2));

        skip_if (cpl_table_set_column_unit(tab, label2, "[0;1] (Unitless)"));

        skip_if(visir_propertylist_fill_comments(qclist, stream));

        /* Save the table */
        cpl_msg_info(cpl_func, "Saving the table with %d rows", nvals);
        if (i == 0) {

            skip_if (visir_util_spc_txt2fits_save(framelist, parlist, qclist,
                                                  procat, tab));
        } else {
            skip_if (cpl_table_save(tab, NULL, qclist, RECIPE_STRING
                                    CPL_DFS_FITS, CPL_IO_EXTEND));
        }
    }

    end_skip;

    if (stream != NULL) fclose(stream);
    cpl_bivector_delete(spectrum);
    if (tab) {
        cpl_table_unwrap(tab, "Wavelength");
        cpl_table_unwrap(tab, label2);
        cpl_table_delete(tab);
    }
    irplib_framelist_delete(allframes);
    irplib_framelist_delete(rawframes);
    cpl_propertylist_delete(qclist);

    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Save the visir_util_spc_txt2fits recipe products on disk
  @param    set      the input frame set
  @param    parlist  the input list of parameters
  @param    qclist   the list of properties
  @param    procat   the value of the PROCATG card
  @param    tab      the table to save
  @return   0 iff everything is ok
 
  The table contains 2 columns.
 */
/*----------------------------------------------------------------------------*/
static
cpl_error_code visir_util_spc_txt2fits_save(cpl_frameset            * set,
                                            const cpl_parameterlist * parlist,
                                            const cpl_propertylist  * qclist,
                                            const char              * procat,
                                            const cpl_table         * tab)
{

    cpl_propertylist * applist = cpl_propertylist_new();


    bug_if(cpl_propertylist_append_string(applist, "INSTRUME", "VISIR"));

    skip_if (irplib_dfs_save_table(set, parlist, set, tab, qclist, RECIPE_STRING,
                                   procat, applist, NULL, visir_pipe_id,
                                   RECIPE_STRING CPL_DFS_FITS));

    end_skip;

    cpl_propertylist_delete(applist);

    return cpl_error_get_code();
}


/*----------------------------------------------------------------------------*/
/**
  @brief    Attempt to rewind file and put comments into propertylist comments
  @param    self   the list of properties to fill
  @param    stream the stream to rewind and parse for comments
  @return   0 iff everything is ok
  @note Comments are assumed to start with '#', this character is skipped in
        the COMMENT card
 
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code visir_propertylist_fill_comments(cpl_propertylist * self,
                                                       FILE * stream)
{

    bug_if(self == NULL);
    bug_if(stream == NULL);

    if (!fseek(stream, 0, SEEK_SET)) {

        char line[1024];

        while (fgets(line, 1024, stream) != NULL) {

            if (line[0] == '#') {
                char value[FLEN_VALUE];
                strncpy(value, line+1, FLEN_VALUE);
                value[FLEN_VALUE - 1] = '\0';
                cpl_propertylist_append_string(self, "COMMENT", value);
            }
        }
    }

    end_skip;

    return cpl_error_get_code();
}
