/* $Id: visir_util_img_std_cat.c,v 1.58 2012/02/06 10:15:47 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/02/06 10:15:47 $
 * $Revision: 1.58 $
 * $Name: visir-3_5_1 $
 */

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

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

#include <stdio.h>
#include <string.h>

#include "visir_recipe.h"

/*-----------------------------------------------------------------------------
                                Defines
 -----------------------------------------------------------------------------*/
#define NFILTERS 37

#define RECIPE_STRING   "visir_util_img_std_cat"

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

static cpl_error_code visir_util_img_std_cat_save(cpl_frameset *,
                                                  const cpl_parameterlist *,
                                                  const cpl_table *);

static cpl_error_code visir_util_img_std_cat_parse(const char*, char *,
                                                   double *, double *, char *,
                                                   double *, int);

VISIR_RECIPE_DEFINE(visir_util_img_std_cat, 0,
                    "Convert ASCII-file(s) to a FITS standard star catalog",
                    "This recipe generates a FITS standard star catalog for "
                    "imaging from one or \n"
                    "more ASCII-files.\n"
                    "Each line in the text file must have 45 fields separated "
                    "by white-space.\n"
                    "The first field is the star name, e.g. 'HD108903' which "
                    "will be stored in a \n"
                    "table column labeled 'STARS'.\n"
                    "The 3 next fields are the RA (hh mm ss) which will be "
                    "stored in degrees in \n"
                    "a table column labeled 'RA' - all three are non-negative "
                    "and hh and mm are \n"
                    "integer.\n"
                    "The 3 next fields are the DEC (dd mm ss) which will be "
                    "stored in degrees in \n"
                    "a table column labeled 'DEC' - all three are non-negative, "
                    "dd and mm are \n"
                    "integer, while dd has either a '+' or a '-' prepended "
                    "(including -00).\n"
                    "The next field is the spectral type which will be "
                    "stored in a \n"
                    "table column labeled 'SP_TYPE'.\n"
                    "The 31 next fields are the JY values for the 31 supported "
                    "image filters.\n"
                    "The 6 next fields are the JY values for the 6 supported "
                    "spectral filters.\n"
                    "All JY values must be positive.\n"
                    "For each filter the JY value is stored in a table column "
                    "labeled with the \n"
                    "filter name.\n"
                    "The 37 filter names are hard-coded in the recipe.\n"
                    "\n"
                    "Lines beginning with a hash (#) are treated as comments.\n"
                    "\n"
                    "The ASCII-input should be tagged " VISIR_IMG_LINES_ASCII
                    ", but all input \n"
                    "files will currently be processed regardless.\n");

/*----------------------------------------------------------------------------*/
/**
 * @defgroup visir_util_img_std_cat   Convert ASCII star catalog(s) to FITS
 */
/*----------------------------------------------------------------------------*/

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

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

 */
/*----------------------------------------------------------------------------*/
static int visir_util_img_std_cat(cpl_frameset            * framelist,
                                  const cpl_parameterlist * parlist)
{
    const int    nfilters = NFILTERS;
    const cpl_frame *  frame;
    FILE       * in = NULL;

    char         line[1024];
    cpl_table  * tab = NULL;
    char         sname[512];
    char         stype[512];
    double       jys[NFILTERS];
    const char * filters[]
        = {"MV", "N_BAND", "SIC", "PAH1_1", "PAH1", "ARIII", "SIV_1", "SIV",
           "PAH2_1", "SIV_2", "PAH2", "PAH2_2", "NEII_1", "NEII", "NEII_2",
           "J7_9", "J8_9", "J9_8", "J12_2", "B9_7", "B10_7", "B11_7", "B12_4",
           "Q0", "QH2", "Q1", "Q2", "Q3", "Q4", "Q7", "Q8", "N_SW_spec",
           "H2S4_spec", "ARIII_spec", "NEII_2_spec", "H2S3_spec", "H2S1_spec"};
    const double max_radius = VISIR_STAR_MAX_RADIUS;
    double       mindist;
    int          iloc1, iloc2;
    int          nrows = 425; /* Some positive number */
    int          irow  = 0;
    int          i, j;


    if (cpl_error_get_code()) return cpl_error_get_code();

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

    bug_if(sizeof(filters) != NFILTERS * sizeof(char*));
 
    /* Create the table */
    tab = cpl_table_new(nrows);
    skip_if (cpl_table_new_column(tab, "STARS", CPL_TYPE_STRING));
    skip_if (cpl_table_new_column(tab, "SP_TYPE", CPL_TYPE_STRING));
    skip_if (cpl_table_new_column(tab, "RA", CPL_TYPE_DOUBLE));
    skip_if (cpl_table_new_column(tab, "DEC", CPL_TYPE_DOUBLE));

    for (j=0 ; j<nfilters ; j++)
        skip_if (cpl_table_new_column(tab, filters[j], CPL_TYPE_DOUBLE));
    
    /* Loop on all input frames */
    for (i=0, frame = cpl_frameset_get_first(framelist); frame != NULL ;
         i++, frame = cpl_frameset_get_next(framelist)) {

        /* Get file name */
        const char * filename = cpl_frame_get_filename(frame);
        int jrow = 0;


        /* Open the file */
        skip_if (filename == NULL);
        in = fopen(filename, "r");
        if (in == NULL) {
            cpl_msg_error(cpl_func, "Could not open the %d. file: %s", i+1,
                          filename);
            skip_if (1);
        }

        while (fgets(line, 1024, in) != NULL) {
            jrow++;
            if (line[0] != '#') {
                double ra, dec;

                if (visir_util_img_std_cat_parse(line, sname, &ra, &dec,
                                                 stype, jys, nfilters)) {
                    cpl_msg_error(cpl_func, "Unparsable line %d in %d. file "
                                  "%s", jrow, i+1, filename);
                    skip_if(1);
                }
                if (irow == nrows) {
                    /* Table needs more rows */
                    nrows *= 2;
                    skip_if (cpl_table_set_size(tab, nrows));
                }
                skip_if (cpl_table_set_string(tab, "STARS", irow, sname));
                skip_if (cpl_table_set_string(tab, "SP_TYPE", irow, stype));
                skip_if (cpl_table_set_double(tab, "RA", irow, ra));
                skip_if (cpl_table_set_double(tab, "DEC", irow, dec));
                for (j=0 ; j<nfilters ; j++) 
                    skip_if(cpl_table_set_double(tab, filters[j], irow,
                                                 jys[j]));
                irow++;

            }
        }
        fclose(in);
        in = NULL;
        if (jrow == 0) {
            cpl_msg_warning(cpl_func, "No usable lines in file %s", filename);
        }
    }

    skip_if( frame != NULL );

    skip_if (irow == 0);

    /* Resize the table to the actual number of rows read */
    nrows = irow;
    skip_if (cpl_table_set_size(tab, nrows));

    mindist = visir_star_dist_min(cpl_table_get_data_double(tab, "RA"),
                                  cpl_table_get_data_double(tab, "DEC"), nrows,
                                  &iloc1, &iloc2);

    if (mindist < max_radius)
        cpl_msg_warning(cpl_func, "The pair of closest stars is %s (%d) and %s "
                        "(%d) with the distance: %g",
                        cpl_table_get_string(tab, "STARS", iloc1), iloc1,
                        cpl_table_get_string(tab, "STARS", iloc2), iloc2,
                        mindist);
    else
        cpl_msg_info(cpl_func, "The pair of closest stars is %s (%d) and %s "
                     "(%d) with the distance: %g",
                     cpl_table_get_string(tab, "STARS", iloc1), iloc1,
                     cpl_table_get_string(tab, "STARS", iloc2), iloc2,
                     mindist);

    /* Save the table */
    cpl_msg_info(cpl_func, "Saving the table with %d rows and %d filters",
                 nrows, nfilters);

    skip_if (visir_util_img_std_cat_save(framelist, parlist, tab));

    end_skip;

    if (in) fclose(in);
    cpl_table_delete(tab);
    
    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Parse a line of ASCII input
  @param    line   The ASCII line
  @param    sname  The Star name
  @param    ra     The Right Ascension
  @param    dec    The Declination
  @param    stype  The Star type
  @param    jys    The array of Jansky values
  @param    njys   The number of Jansky values (Must be 29!)
  @return   CPL_ERROR_NONE iff the line was parsed OK
  @note The functions will assert() on NULL input or wrong njys
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code visir_util_img_std_cat_parse(const char * line,
                                                   char * sname, double * pra,
                                                   double * pdec, char *stype,
                                                   double * jys, int njys)
{

    const char * format = "%s %d %d %lg %c%d %d %lg %s %lg %lg %lg %lg %lg %lg "
        "%lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg "
        "%lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg %lg";

    int nvals;
    int ra1, ra2;
    int dec1, dec2;
    double ra3, dec3;
    char isign;

    assert( line );
    assert( sname );
    assert( stype );
    assert( jys );
    assert( njys == NFILTERS );


    nvals = sscanf(line, format,
                   sname, &ra1, &ra2, &ra3, &isign, &dec1, &dec2,
                   &dec3, stype, &(jys[0]), &(jys[1]), &(jys[2]),
                   &(jys[3]), &(jys[4]), &(jys[5]), &(jys[6]),
                   &(jys[7]), &(jys[8]), &(jys[9]), &(jys[10]),
                   &(jys[11]), &(jys[12]), &(jys[13]), &(jys[14]),
                   &(jys[15]), &(jys[16]), &(jys[17]), &(jys[18]),
                   &(jys[19]), &(jys[20]), &(jys[21]), &(jys[22]),
                   &(jys[23]), &(jys[24]), &(jys[25]), &(jys[26]),
                   &(jys[27]), &(jys[28]), &(jys[29]), &(jys[30]),
                   &(jys[31]), &(jys[32]), &(jys[33]), &(jys[34]),
                   &(jys[35]), &(jys[36]));

    if (nvals != njys+9) {
        cpl_msg_error(cpl_func, "Line with length=%u has %d not %d items "
                      "formatted: %s", (unsigned)strlen(line), nvals, njys+9,
                      format);
        cpl_ensure_code(0, CPL_ERROR_BAD_FILE_FORMAT);
    }

    return visir_star_convert(line, ra1, ra2, ra3, isign, dec1, dec2,
                              dec3, jys, njys, pra, pdec);
                                    
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Save the visir_util_img_std_cat recipe products on disk
  @param    set     the input frame set
  @param    parlist the input list of parameters
  @param    tab     table to save
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static
cpl_error_code visir_util_img_std_cat_save(cpl_frameset            * set,
                                           const cpl_parameterlist * parlist,
                                           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, NULL, RECIPE_STRING,
                              VISIR_IMA_STD_CAT_PROCATG,
                              applist, NULL, visir_pipe_id,
                              RECIPE_STRING CPL_DFS_FITS));

    end_skip;

    cpl_propertylist_delete(applist);

    return cpl_error_get_code();
}

