/* $Id: uves_qclog.c,v 1.53 2012-11-19 09:12:54 jtaylor Exp $
 *
 * This file is part of the UVES 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * $Author: jtaylor $
 * $Date: 2012-11-19 09:12:54 $
 * $Revision: 1.53 $
 * $Name: not supported by cvs2svn $
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <uves_time.h>
#include <uves_globals.h>
/*----------------------------------------------------------------------------*/
/**
 * @defgroup uves_qclog   Interface for reading/writing QC LOG keywords. 
 */
/*----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
                Defines
 -----------------------------------------------------------------------------*/
#define FILE_NAME_SZ 1024  /* fixme: should not use fixed size buffers */

/**@{*/

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

#include "uves_qclog.h"

#include <uves_baryvel.h>
#include <uves_utils_wrappers.h>
#include <uves_pfits.h>
#include <uves_error.h>
#include <uves_msg.h>

#include <irplib_utils.h>
#include <string.h>
/*-----------------------------------------------------------------------------
                Forward declarations
 -----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
                Function codes
 -----------------------------------------------------------------------------*/

static FILE * uves_paf_print_header(
        const char    *   filename,
        const char    *   paf_id,
        const char    *   paf_desc,
        const char    *   login_name,
        const char    *   datetime) ;

/*----------------------------------------------------------------------------*/
/**
  @brief    Open a new PAF file, output a default header.
  @param    filename    Name of the file to create.
  @param    paf_id        PAF identificator.
  @param    paf_desc    PAF description.
  @param    login_name  Login name
  @param    datetime    Date
  @return    Opened file pointer.

  This function creates a new PAF file with the requested file name.
  If another file already exists with the same name, it will be
  overwritten (if the file access rights allow it).

  A default header is produced according to the VLT DICB standard. You
  need to provide an identificator (paf_id) of the producer of the
  file. Typically, something like "ISAAC/zero_point".

  The PAF description (paf_desc) is meant for humans. Typically,
  something like "Zero point computation results".

  This function returns an opened file pointer, ready to receive more
  data through fprintf's. The caller is responsible for fclose()ing
  the file.
 */
/*----------------------------------------------------------------------------*/
static FILE * uves_paf_print_header(
    const char    *   filename,
    const char    *      paf_id,
    const char    *    paf_desc,
    const char    *   login_name,
    const char    *   datetime)
{
    FILE * paf ;
    
    if ((paf=fopen(filename, "w"))==NULL) {
        uves_msg_error("cannot create PAF file [%s]", filename);
        return NULL ;
    }
    fprintf(paf, "PAF.HDR.START         ; # start of header\n");
    fprintf(paf, "PAF.TYPE              \"pipeline product\" ;\n");
    fprintf(paf, "PAF.ID                \"%s\"\n", paf_id);
    fprintf(paf, "PAF.NAME              \"%s\"\n", filename);
    fprintf(paf, "PAF.DESC              \"%s\"\n", paf_desc);
    fprintf(paf, "PAF.CRTE.NAME         \"%s\"\n", login_name) ;
    fprintf(paf, "PAF.CRTE.DAYTIM       \"%s\"\n", datetime) ;
    fprintf(paf, "PAF.LCHG.NAME         \"%s\"\n", login_name) ;
    fprintf(paf, "PAF.LCHG.DAYTIM       \"%s\"\n", datetime) ;
    fprintf(paf, "PAF.CHCK.CHECKSUM     \"\"\n");
    fprintf(paf, "PAF.HDR.END           ; # end of header\n");
    fprintf(paf, "\n");
    return paf ;
}


/**
@brief computes rootname
@param filename name of file
@return rootname of filename
*/

char *
uves_get_rootname(const char * filename)
{
    static char path[MAX_NAME_SIZE+1];
    char * lastdot ;

    if (strlen(filename)>MAX_NAME_SIZE) return NULL ;
    memset(path, 0, MAX_NAME_SIZE);
    strcpy(path, filename);
    lastdot = strrchr(path, '.');
    if (lastdot == NULL) return path ;
    if ((!strcmp(lastdot, ".fits")) || (!strcmp(lastdot, ".FITS")) ||
        (!strcmp(lastdot, ".paf")) || (!strcmp(lastdot, ".PAF")) ||
        (!strcmp(lastdot, ".dat")) || (!strcmp(lastdot, ".DAT")) ||
        (!strcmp(lastdot, ".tfits")) || (!strcmp(lastdot, ".TFITS")) ||
        (!strcmp(lastdot, ".ascii")) || (!strcmp(lastdot, ".ASCII")))
    {
        lastdot[0] = (char)0;
    }
    return path ;
}
/**
@brief get paf file name
@param in      product name
@param paf_no  paf file number
@param paf     output paf file name
*/

void
uves_get_paf_name(const char* in, int paf_no, char** paf) 
{
    char* tmp=NULL;
    char  name_b[512] ;
    
    if (strstr(in, "." ) != NULL ) 
    {
        tmp = uves_get_rootname(in);
        strcpy(name_b, tmp);
    } 
    else
    {
        sprintf(name_b, "%s", in) ;
    }
    
    sprintf(*paf, "%s-%d.paf", name_b, paf_no);
    
    return;
}
/**
@brief replace a blank to a dot
@param in input string 
@param ou output string
*/
int uves_blank2dot(const char * in, char* ou) 
{
  int len=0;
  int i=0;

  strcpy(ou,in);
  len = strlen(in);
  for (i=0;i<len;i++)
    {
      if (in[i] == ' ') {
          ou[i] =  '.';
      }
    }
  return 0;
}


/*----------------------------------------------------------------------------*/


/**
  @brief    Init QC-LOG table
  @param filename        input filename. This is the filename of the
                         associated recipe product
  @param paf_no          paf file number, counting from zero. The paf
                         filename is created from the 'filename' and
             from this number. (This is to support several
             paf files for one recipe product).
  @param rec_id          input recipe id
  @param qclog           QC parameters table
  @param plist           property list
  @param rhead           reference frame header
  @param pro_catg        product category
  @return   a cpl_table with 0 rows and proper structure to do hold QC-LOG keys
 */
/*----------------------------------------------------------------------------*/
int uves_save_paf(const char* filename, 
          int paf_no,
                  const char* rec_id,  
                  const cpl_table* qclog,
                  uves_propertylist*   plist,
                  const uves_propertylist*   rhead,
                  const char*      pro_catg)
{


    FILE            *   paf ;
    const char      *   sval ;
    char            key_name[FILE_NAME_SZ] ;
    char            key_paf[FILE_NAME_SZ] ;
    char            key_dpaf[FILE_NAME_SZ] ;
    char            key_type[FILE_NAME_SZ] ;
    char            key_value[FILE_NAME_SZ] ;
    char            key_help[FILE_NAME_SZ] ;
    char* name_p=NULL;

    int i =0;
    int n=0;

    name_p = cpl_malloc(FILE_NAME_SZ * sizeof(char));
    uves_get_paf_name(filename, paf_no, &name_p);


    uves_msg( "Writing %s" , name_p) ;
    /* Create the default PAF header */
    if ((paf = uves_paf_print_header(
         name_p,
         rec_id,
         "QC file",
         "login-name",
         uves_get_datetime_iso8601())) == NULL) {
        uves_msg_error( "cannot open file [%s] for output", name_p) ;
        return -1 ;
    }
    cpl_free(name_p);


    strcpy(key_name,KEY_NAME_QC_DID);        
    strcpy(key_paf,PAF_NAME_QC_DID);
    uves_blank2dot(key_paf,key_dpaf);
    fprintf(paf,"%-21s \"%s\" ; # %s \n",key_dpaf,
        uves_propertylist_get_string(plist,key_name),KEY_HELP_QC_DID);


    uves_blank2dot(PAF_NAME_PIPE_ID,key_dpaf);
    fprintf(paf,"%-21s \"%s/%s\" ; # %s \n", key_dpaf,
                 PACKAGE, PACKAGE_VERSION,KEY_HELP_PIPE_ID);

    strcpy(key_name, KEY_NAME_PIPEFILE);        
    strcpy(key_paf, KEY_NAME_PIPEFILE);        
    uves_blank2dot(key_paf, key_dpaf);
    if (uves_propertylist_contains(plist, key_name)) {
       fprintf(paf,"%-21s \"%s\" ; # %s \n", key_dpaf,
       uves_propertylist_get_string(plist,key_name),KEY_HELP_PIPEFILE);
    }

    /* Value: "TEMPORARY", "PREPROCESSED", "REDUCED" or "QCPARAM". */
    strcpy(key_name,KEY_NAME_PRO_TYPE);
    strcpy(key_paf,PAF_NAME_PRO_TYPE);    
    uves_blank2dot(key_paf,key_dpaf);
    if (uves_propertylist_contains(plist, key_name)) {
       fprintf(paf,"%-21s \"%s\" ; # %s \n", key_dpaf,
       uves_propertylist_get_string(plist,key_name),KEY_HELP_PRO_TYPE);
    }

    strcpy(key_name,KEY_NAME_PRO_RECID);  
    strcpy(key_paf,PAF_NAME_PRO_RECID);  
    uves_blank2dot(key_paf,key_dpaf);        
    if (uves_propertylist_contains(plist, key_name)) {
      fprintf(paf,"%-21s \"%s\" ; # %s \n", key_dpaf,
          uves_propertylist_get_string(plist,key_name),KEY_HELP_PRO_RECID);
    }

    /* sprintf(cval, "CPL-%s", get_cpl_version()); */
    strcpy(key_name,KEY_NAME_PRO_DRSID); 
    strcpy(key_paf,PAF_NAME_PRO_DRSID); 
    uves_blank2dot(key_paf,key_dpaf);        
    if (uves_propertylist_contains(plist, key_name)) {
      fprintf(paf,"%-21s \"%s\" ; # %s \n",key_dpaf, 
          uves_propertylist_get_string(plist,key_name),KEY_HELP_PRO_DRSID);
    }
    /*
    if (uves_propertylist_contains(plist,KEY_NAME_DATE_OBS)) {
      sval = uves_pfits_get_date_obs(plist);
      strcpy(key_paf,KEY_NAME_DATE_OBS); 
      uves_blank2dot(key_paf,key_dpaf);        
      fprintf(paf, "%-21s \"%s\" ; # %s\n",key_dpaf, 
                sval,KEY_HELP_DATE_OBS) ;
    }
    */

      if (uves_propertylist_contains(rhead,KEY_NAME_ARCFILE)) {
      sval = uves_pfits_get_arcfile(rhead);
      strcpy(key_paf,KEY_NAME_ARCFILE);
      uves_blank2dot(key_paf,key_dpaf);      
      fprintf(paf, "%-21s \"%s\" ; # %s \n", key_dpaf,sval,KEY_HELP_ARCFILE) ;
    } else if (uves_propertylist_contains(rhead,KEY_NAME_PRO_REC1_RAW1_NAME)) {
      sval = uves_pfits_get_rec1raw1name(rhead);
      strcpy(key_paf,KEY_NAME_ARCFILE);
      uves_blank2dot(key_paf,key_dpaf);        
   } else {
      uves_msg_error("%s is missing QC LOG will fail!",KEY_NAME_ARCFILE);
    }


    if (uves_propertylist_contains(plist,KEY_NAME_TPL_ID)) {
      sval = uves_pfits_get_templateid(plist);
      strcpy(key_paf,PAF_NAME_TPL_ID);
      uves_blank2dot(key_paf,key_dpaf);       
      fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
          sval,KEY_HELP_TPL_ID) ;
 
    }
    
    if (uves_propertylist_contains(plist,KEY_NAME_DPR_TYPE)) {
      sval = uves_pfits_get_dpr_type(plist);
      strcpy(key_paf,PAF_NAME_DPR_TYPE); 
      uves_blank2dot(key_paf,key_dpaf);        
      fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
                sval, KEY_HELP_DPR_TYPE) ;
    }
    
    if (uves_propertylist_contains(plist,KEY_NAME_DPR_TECH)) {
      sval = uves_pfits_get_dpr_tech(plist);
      strcpy(key_paf,PAF_NAME_DPR_TECH); 
      uves_blank2dot(key_paf,key_dpaf);   
      fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
                sval, KEY_HELP_DPR_TECH) ;
    }
    
    if (uves_propertylist_contains(plist,KEY_NAME_DPR_CATG)) {
      sval = uves_pfits_get_dpr_catg(plist);
      strcpy(key_paf,PAF_NAME_DPR_CATG); 
      uves_blank2dot(key_paf,key_dpaf); 
      fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
                sval, KEY_HELP_DPR_CATG) ;
    }
    
    strcpy(key_paf,PAF_NAME_PRO_CATG); 
    uves_blank2dot(key_paf,key_dpaf); 
    fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
                pro_catg, KEY_HELP_PRO_CATG) ;

    n=cpl_table_get_nrow(qclog);
    for(i=0;i<n;i++) 
    {
        strcpy(key_paf,cpl_table_get_string(qclog,"key_name",i));
        uves_blank2dot(key_paf,key_name);
        strcpy(key_type,  cpl_table_get_string(qclog, "key_type",i));
        strcpy(key_value, cpl_table_get_string(qclog, "key_value",i));
        strcpy(key_help,  cpl_table_get_string(qclog, "key_help" , i));
        
        if (strcmp(key_type, "CPL_TYPE_STRING") == 0)
        {
            fprintf(paf,"%s               \"%s\"\n",
                key_name, key_value);
        }
        else
        {
            fprintf(paf,"%s               %s\n",
                key_name, key_value);
        }
    }
    fprintf(paf, "\n");
    fclose(paf) ;

    return 0;

}


/*----------------------------------------------------------------------------*/
/**
  @brief    Init QC-LOG table
  @param    raw_header     input FITS header
  @param    chip           CCD chip
  @return   a cpl_table with proper structure to do hold QC-LOG keys
            and QC parameters common to all recipes
 */
/*----------------------------------------------------------------------------*/
cpl_table *
uves_qclog_init(const uves_propertylist *raw_header,
        enum uves_chip chip)
{
  cpl_table *qclog = NULL;

  qclog = cpl_table_new(0);
  cpl_table_new_column(qclog,"key_name", CPL_TYPE_STRING);
  cpl_table_new_column(qclog,"key_type", CPL_TYPE_STRING);
  cpl_table_new_column(qclog,"key_value", CPL_TYPE_STRING);
  cpl_table_new_column(qclog,"key_help", CPL_TYPE_STRING);

  check_nomsg(uves_qclog_add_string(qclog,
                    uves_remove_string_prefix(KEY_NAME_QC_DID,"ESO "),
                    "UVES-1.14",
                    KEY_NAME_QC_DID,
                    "%s"));

  /* Not present in bias/dark frames: */
  if (uves_propertylist_contains(raw_header, UVES_INSPATH))
      {
      check_nomsg(uves_qclog_add_string(qclog,
                        uves_remove_string_prefix(UVES_INSPATH,"ESO "),
                        uves_pfits_get_inspath(raw_header),
                        "Optical path used.",
                        "%s"));
      }
  else
      {
      uves_msg_debug("Missing descriptor %s", UVES_INSPATH);
      }

  if (uves_propertylist_contains(raw_header, UVES_INSMODE))
      {
      check_nomsg(uves_qclog_add_string(qclog,
                        uves_remove_string_prefix(UVES_INSMODE,"ESO "),
                        uves_pfits_get_insmode(raw_header),
                        "Instrument mode used.",
                        "%s"));
      }
  else
      {
      uves_msg_debug("Missing descriptor %s", UVES_INSMODE);
      }

    
  if (uves_propertylist_contains(raw_header, UVES_GRATNAME(chip)))
      {
      check_nomsg(uves_qclog_add_string(qclog,
                        uves_remove_string_prefix(UVES_GRATNAME(chip),"ESO "),
                        uves_pfits_get_gratname(raw_header,chip),
                        "Grating common name",
                        "%s"));
      }
  else
      {
      uves_msg_debug("Missing descriptor %s", UVES_GRATNAME(chip));
      }
  
  /* Always present: */
  check_nomsg(uves_qclog_add_string(qclog,
                    uves_remove_string_prefix(UVES_READ_SPEED,"ESO "),
                    uves_pfits_get_readspeed(raw_header),
                    "Readout speed",
                    "%s"));
  
  check_nomsg(uves_qclog_add_int(qclog,
                 uves_remove_string_prefix(UVES_BINX, "ESO "),
                 uves_pfits_get_binx(raw_header),
                 "Binning factor along X",
                 "%d"));
  
  check_nomsg(uves_qclog_add_int(qclog,
                 uves_remove_string_prefix(UVES_BINY, "ESO "),
                 uves_pfits_get_biny(raw_header),
                 "Binning factor along Y",
                 "%d"));
  
  if (uves_propertylist_contains(raw_header, UVES_CHIP_NAME(chip)))
      {
      check_nomsg(uves_qclog_add_string(qclog,
                        uves_remove_string_prefix(UVES_CHIP_NAME(chip),"ESO "),
                        /* UVES_QC_CHIP_VAL(chip), */
                        uves_pfits_get_chip_name(raw_header, chip),
                        "Detector chip name",
                        "%s"));
      }
  else
      {
      uves_msg_warning("Missing descriptor %s", UVES_CHIP_NAME(chip));
      }
  
  cleanup:
  return qclog;
}



/*----------------------------------------------------------------------------*/
/**
  @brief    Add integer key to QC-LOG table
  @param    table       QC-LOG table
  @param    key_name    QC-LOG key name
  @param    value       QC-LOG key value
  @param    key_help    QC-LOG key help
  @param    format      QC-LOG key format

  @return   0 after successfull keyword addition
 */
/*----------------------------------------------------------------------------*/

int
uves_qclog_add_int(cpl_table* table,
                  const char*  key_name,  
                  const int    value,
                  const char*  key_help,
                  const char*  format)
{
  int sz = cpl_table_get_nrow(table);
  int raw = sz;
  char key_value[FILE_NAME_SZ];
  char key_type[FILE_NAME_SZ];

  sprintf(key_value,format,value);
  strcpy(key_type,"CPL_TYPE_INT"); 
 
  cpl_table_set_size(table,sz+1);

  cpl_table_set_string(table,"key_name" ,raw,key_name);
  cpl_table_set_string(table,"key_type" ,raw,key_type);
  cpl_table_set_string(table,"key_value",raw,key_value);
  cpl_table_set_string(table,"key_help" ,raw,key_help);

  return 0;

}



/**
  @brief    Add boolean key to QC-LOG table
  @param    table       QC-LOG table
  @param    key_name    QC-LOG key name
  @param    value       QC-LOG key value
  @param    key_help    QC-LOG key help
  @param    format      QC-LOG key format

  @return   0 after successfull keyword addition
 */
/*----------------------------------------------------------------------------*/

int
uves_qclog_add_bool(cpl_table* table,
                  const char*  key_name,  
                  const char   value,
                  const char*  key_help,
                  const char*  format)
{
  int sz = cpl_table_get_nrow(table);
  int raw = sz;
  char key_value[FILE_NAME_SZ];
  char key_type[FILE_NAME_SZ];

  sprintf(key_value,format,value);
  strcpy(key_type,"CPL_TYPE_BOOL"); 

  cpl_table_set_size(table,sz+1);

  cpl_table_set_string(table,"key_name" ,raw,key_name);
  cpl_table_set_string(table,"key_type" ,raw,key_type);
  cpl_table_set_string(table,"key_value",raw,key_value);
  cpl_table_set_string(table,"key_help" ,raw,key_help);

  return 0;

}

/**
  @brief    Add float key to QC-LOG table
  @param    table       QC-LOG table
  @param    key_name    QC-LOG key name
  @param    value       QC-LOG key value
  @param    key_help    QC-LOG key help
  @param    format      QC-LOG key format

  @return   0 after successfull keyword addition
 */
/*----------------------------------------------------------------------------*/


int
uves_qclog_add_float(cpl_table* table,
                  const char*  key_name,  
                  const float  value,
                  const char*  key_help,
                  const char*  format)
{
  int sz = cpl_table_get_nrow(table);
  int raw = sz;
  char key_value[FILE_NAME_SZ];
  char key_type[FILE_NAME_SZ];

  sprintf(key_value,format,value);
  strcpy(key_type,"CPL_TYPE_FLOAT"); 
 
  cpl_table_set_size(table,sz+1);

  cpl_table_set_string(table,"key_name" ,raw,key_name);
  cpl_table_set_string(table,"key_type" ,raw,key_type);
  cpl_table_set_string(table,"key_value",raw,key_value);
  cpl_table_set_string(table,"key_help" ,raw,key_help);

  return 0;

}



/**
  @brief    Add double key to QC-LOG table
  @param    table       QC-LOG table
  @param    key_name    QC-LOG key name
  @param    value       QC-LOG key value
  @param    key_help    QC-LOG key help
  @param    format      QC-LOG key format

  @return   0 after successfull keyword addition
 */
/*----------------------------------------------------------------------------*/


int
uves_qclog_add_double(cpl_table* table,
                  const char*  key_name,  
                  const double value,
                  const char*  key_help,
                  const char*  format)
{
  int sz = cpl_table_get_nrow(table);
  int raw = sz;
  char key_value[FILE_NAME_SZ];
  char key_type[FILE_NAME_SZ];

  sprintf(key_value,format,value);
  strcpy(key_type,"CPL_TYPE_DOUBLE"); 

  cpl_table_set_size(table,sz+1);

  cpl_table_set_string(table,"key_name" ,raw,key_name);
  cpl_table_set_string(table,"key_type" ,raw,key_type);
  cpl_table_set_string(table,"key_value",raw,key_value);
  cpl_table_set_string(table,"key_help" ,raw,key_help);

  return 0;

}


/**
  @brief    Add string key to QC-LOG table
  @param    table       QC-LOG table
  @param    key_name    QC-LOG key name
  @param    value       QC-LOG key value
  @param    key_help    QC-LOG key help
  @param    format      QC-LOG key format

  @return   0 after successfull keyword addition
 */
/*----------------------------------------------------------------------------*/




int
uves_qclog_add_string(cpl_table* table,
                  const char*  key_name,  
                  const char*  value,
                  const char*  key_help,
                  const char*  format)
{
  int sz = cpl_table_get_nrow(table);
  int raw = sz;
  char key_value[FILE_NAME_SZ];
  char key_type[FILE_NAME_SZ];

  sprintf(key_value,format,value);
  strcpy(key_type,"CPL_TYPE_STRING"); 
 
  cpl_table_set_size(table,sz+1);

  cpl_table_set_string(table,"key_name" ,raw,key_name);
  cpl_table_set_string(table,"key_type" ,raw,key_type);
  cpl_table_set_string(table,"key_value",raw,key_value);
  cpl_table_set_string(table,"key_help" ,raw,key_help);

  return 0;

}

/**
  @brief    delete QC-LOG table
  @param    table       QC-LOG table
  @return   0 after successfull delete
 */
/*----------------------------------------------------------------------------*/

int
uves_qclog_delete(cpl_table** table)
{
  if (table != NULL) { 
    cpl_table_delete(*table);
    *table = NULL;
  }
  return 0;
}


/**
  @brief    Add QC-LOG to FITS header
  @param    plist       propertylist (FITS header)
  @param    qclog       QC-LOG table
  @return   0 after successfull keywords addition, -1 if not
 */
/*----------------------------------------------------------------------------*/


int uves_pfits_put_qc(
        uves_propertylist       *   plist,
        const cpl_table          *   qclog)
{
  char            key_name[FILE_NAME_SZ];
  char            key_value[FILE_NAME_SZ];
  char            key_type[FILE_NAME_SZ];
  char            key_help[FILE_NAME_SZ] ;

  int             i =0;
  int n =0;
  /* Test entries */
  if (plist == NULL) {
    uves_msg_error("plist=NULL, something strange");
    return -1 ;
  }
  /* Parameter Name:    PIPEFILE */

  n=cpl_table_get_nrow(qclog);
  for(i=0;i<n;i++) {
    strcpy(key_name,"ESO ");
    strcat(key_name,cpl_table_get_string(qclog,"key_name",i));
    strcpy(key_type,cpl_table_get_string(qclog,"key_type",i));
    strcpy(key_value,cpl_table_get_string(qclog,"key_value",i));
    strcpy(key_help,cpl_table_get_string(qclog,"key_help",i));

    /* uves_msg("name=%s type=%s value=%s\n",key_name,key_type,key_value); */
    if(!uves_propertylist_contains(plist,key_name)) {
      if(strcmp(key_type,"CPL_TYPE_STRING") == 0) {
    uves_propertylist_append_string(plist, key_name,key_value) ;
    uves_propertylist_set_comment(plist, key_name,key_help) ;
      } else if(strcmp(key_type,"CPL_TYPE_BOOL") == 0) {
      /* printf("key_value=%s\n",key_value); */
    uves_propertylist_append_bool(plist, key_name,atoi(key_value)) ;
    uves_propertylist_set_comment(plist, key_name,key_help) ;
      } else if(strcmp(key_type,"CPL_TYPE_INT") == 0) {
    uves_propertylist_append_int(plist,key_name,atoi(key_value)) ;
    uves_propertylist_set_comment(plist, key_name,key_help) ;
      } else if(strcmp(key_type,"CPL_TYPE_FLOAT") == 0) {
        uves_propertylist_append_float(plist, key_name,(float)atof(key_value)) ;
        uves_propertylist_set_comment(plist, key_name,key_help) ;
      } else if(strcmp(key_type,"CPL_TYPE_DOUBLE") == 0) {
        uves_propertylist_append_double(plist, key_name,atof(key_value)) ;
        uves_propertylist_set_comment(plist, key_name,key_help) ;
      }
      else
      {
          uves_msg_error("Unrecognized type: %s", key_type);
          return -1;
      }
    }

  }

  return 0 ;
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Write QC parameters related to science reduction
   @param    qclog         QC table to write to
   @param    raw_header    input frame FITS header
   @param    raw_image     input science image
   @param    slit          extraction slit length (pixels)
   @param    info_tbl      containing the previously computed parameters
*/
/*----------------------------------------------------------------------------*/
void
uves_qclog_add_sci(cpl_table *qclog,
           const uves_propertylist *raw_header,
           const cpl_image *raw_image,
           double slit,
           const cpl_table *info_tbl)
{
    char key_name[80];
    
    /* These QC parameters are computed only in optimal extraction.
       Update: After request from DFO, these are also calculated for
       average+linear extraction.
    */

    if (info_tbl != NULL) {
    int minorder = cpl_table_get_int(info_tbl, "Order", 0, NULL);
    int maxorder = minorder;
    int norder;          /* Number of orders extracted */
    int i;

    for(i = 0; i < cpl_table_get_nrow(info_tbl); i++) {
        int order = cpl_table_get_int(info_tbl,"Order", i, NULL);

        minorder = uves_min_int(minorder, order);
        maxorder = uves_max_int(maxorder, order);

        /*
          sprintf(key_name, "QC ORDER NUM%d", i);
          check_nomsg(uves_qclog_add_int(qclog,
          key_name,
          cpl_table_get_int(info_tbl,"Order",i, NULL),
          "Order Number",
          "%d"));
        */
        
        uves_msg_debug("QC-LOG: Order = %d, S/N = %g, Pos = %g, FHWM = %g, RI = %g", 
               order,
               cpl_table_get_double(info_tbl, "ObjSnBlzCentre"  ,i ,NULL),
               cpl_table_get_double(info_tbl, "ObjPosOnSlit"  ,i ,NULL),
               cpl_table_get_double(info_tbl, "ObjFwhmAvg" ,i ,NULL),
                           cpl_table_get_double(info_tbl, "Ripple" ,i ,NULL));
        
        
        sprintf(key_name, "QC ORD%d OBJ SN", order);
        check_nomsg(uves_qclog_add_double(qclog,
                          key_name,
                          cpl_table_get_double(info_tbl,"ObjSnBlzCentre",i, NULL),
                          "Av. S/N at order center",
                          "%8.4f"));
        
        sprintf(key_name, "QC ORD%d OBJ POS", order);
        check_nomsg(uves_qclog_add_double(qclog,
                          key_name,
                          cpl_table_get_double(info_tbl,"ObjPosOnSlit",i, NULL),
                          "Av. OBJ POS at order center",
                          "%8.4f"));
        
        sprintf(key_name, "QC ORD%d OBJ FWHM", order);
        check_nomsg(uves_qclog_add_double(qclog,
                          key_name,
                          cpl_table_get_double(info_tbl,"ObjFwhmAvg",i, NULL),
                          "Av. FWHM on order",
                          "%8.4f"));

        sprintf(key_name, "QC ORD%d OBJ RPLPAR", order);
        check_nomsg(uves_qclog_add_double(qclog,
                          key_name,
                          cpl_table_get_double(info_tbl,"Ripple",i, NULL),
                          "Av. relative ripple amplitude",
                          "%8.4f"));
    } /* for i */

       /* !WARNING!: Duplicate code follows. If changed, please
        * synchronize with the place where ORDER_TRACE_xxxx
        * is saved.
        *
        * These parameters used to (MIDAS),
        * be added only to ORDER_TRACE_xxxx.
        * Now add them to the same products as other
        * QC parameters
        */

    norder = maxorder - minorder + 1;
    check_nomsg(uves_qclog_add_int(qclog,
                       "QC EX NORD",
                       norder,
                       "No. of orders extracted",
                       "%d"));
    
    check_nomsg(uves_qclog_add_int(qclog,
                       "QC EX XSIZE",
                       cpl_image_get_size_x(raw_image),
                       "Input image width (pixels)",
                       "%d"));
    
    check_nomsg(uves_qclog_add_int(qclog,
                       "QC EX YSIZE",
                       uves_round_double(slit),
                       "Extraction slit (pixels)",
                       "%d"));
    } /* if info_tbl != NULL */
    
    {
    double barycor, helicor;

    check( uves_baryvel(raw_header, 
                &barycor,
                &helicor),
           "Could not compute velocity corrections");
    
    check_nomsg(uves_qclog_add_double(qclog,
                      "QC VRAD BARYCOR",
                      barycor,
                      "Barycentric radial velocity correction ",
                      "%13.6f"));
    
    check_nomsg(uves_qclog_add_double(qclog,
                      "QC VRAD HELICOR",
                      helicor,
                      "Heliocentric radial velocity correction ",
                      "%13.6f"));
    }
           
  cleanup:
  return;
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Write common QC parameters
   @param    raw_header    raw frame FITS header
   @param    chip          CCD chip
   @param    qclog         QC table to write to

   This function writes some QC parameters which are common
   for several recipes/QC-tests.
*/
/*----------------------------------------------------------------------------*/

void 
uves_qclog_add_common_wave(const uves_propertylist *raw_header,
               enum uves_chip chip,
               cpl_table *qclog)
{

    check_nomsg(uves_qclog_add_double(qclog,
                                      uves_remove_string_prefix(UVES_SLITWIDTH(chip),"ESO "),
                                      uves_pfits_get_slitwidth(raw_header,chip),
                                      "Slit width (arcsec) [arcsec] (hs).",
                                      "%.1f"));

    check_nomsg(uves_qclog_add_double(qclog,
                      uves_remove_string_prefix(UVES_GRATWLEN(chip),"ESO "),
                      uves_pfits_get_gratwlen(raw_header,chip),
                      "Grating central wavelength [nm] (hs).",
                      "%.1f"));
    



    check_nomsg(uves_qclog_add_double(qclog,
                      uves_remove_string_prefix(UVES_TEMPCAM(chip),"ESO "),
                      uves_pfits_get_tempcam(raw_header,chip),
                      "Average temperature [C] (ho).",
                      "%.1f"));



  cleanup:
    return;
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Create QC parameter name
   @param    name          last part of QC name
   @param    flames        FLAMES?
   @param    trace_number  for FLAMES only
   @return   newly allocated QC name string
*/
/*----------------------------------------------------------------------------*/

const char *
uves_qclog_get_qc_name(const char *name,
               bool flames, int trace_number)
{
    if (flames)
    {
        return uves_sprintf("QC FIB%d %s", trace_number + 1, name);
    }
    else
    {
        return uves_sprintf("QC %s", name);
    }
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Create common QC log 
   @param    name          last part of QC name
   @param    flames        FLAMES?
   @param    trace_number  for FLAMES only
   @return   newly allocated QC name string
*/
/*----------------------------------------------------------------------------*/

int
uves_qclog_dump_common(const uves_propertylist *plist,
               enum uves_chip chip, 
                       cpl_table* qclog)

{


  int binx=0;
  int biny=0;
  const char* read_speed=NULL;
  const char* dpr_type=NULL;
  const char* tpl_id=NULL;
  const char* arcfile=NULL;
  const char* pro_catg=NULL;
  const char* pipefile=NULL;
  const char* ins_path=NULL;
  const char* ins_mode=NULL;
  const char* name_cross=NULL;
  const char* name_ccd=NULL;
  

  check_nomsg(binx=uves_pfits_get_binx(plist));
  check_nomsg(biny=uves_pfits_get_biny(plist));
  check_nomsg(read_speed=uves_pfits_get_readspeed(plist));
  check_nomsg(dpr_type=uves_pfits_get_dpr_catg(plist));
  check_nomsg(tpl_id=uves_pfits_get_templateid(plist));    
  check_nomsg(arcfile=uves_pfits_get_arcfile(plist));
  check_nomsg(pro_catg=uves_pfits_get_pro_catg(plist));
  check_nomsg(pipefile=uves_pfits_get_pipefile(plist)); 
  check_nomsg(ins_path=uves_pfits_get_inspath(plist)); 
  check_nomsg(ins_mode=uves_pfits_get_insmode(plist)); 
  check_nomsg(name_cross=uves_pfits_get_gratname(plist,chip)); 
  check_nomsg(name_ccd=uves_pfits_get_chipid(plist,chip)); 

  ck0_nomsg(uves_qclog_add_string(qclog,
                  "PRO REC1 PIPE ID",
                  PACKAGE_VERSION,
                  "Pipeline (unique) identifier",
                  "%s"));

  ck0_nomsg(uves_qclog_add_string(qclog,
                  "DPR TYPE",
                  dpr_type,
                  "Data Processing Type",
                  "%s"));

  ck0_nomsg(uves_qclog_add_string(qclog,
                  "TPL ID",
                  tpl_id,
                  "Template Id",
                  "%s"));

  ck0_nomsg(uves_qclog_add_string(qclog,
                  "ARCFILE",
                  arcfile,
                  "Archive file name",
                  "%s"));

  ck0_nomsg(uves_qclog_add_string(qclog,
                  "PRO CATG",
                  pro_catg,
                  "Product Category",
                  "%s"));


  ck0_nomsg(uves_qclog_add_string(qclog,
                  "PIPEFILE",
                  pipefile,
                  "Pipeline file name",
                  "%s"));


  ck0_nomsg(uves_qclog_add_string(qclog,
                  "INS PATH",
                  ins_path,
                  "Instrument Path",
                  "%s"));


  ck0_nomsg(uves_qclog_add_string(qclog,
                  "INS MODE",
                  ins_mode,
                  "Instrument mode",
                  "%s"));

  ck0_nomsg(uves_qclog_add_string(qclog,
                  "NAME CROSS",
                  name_cross,
                  "Grating common name",
                  "%s"));

  ck0_nomsg(uves_qclog_add_string(qclog,
                  "NAME CCD",
                  name_ccd,
                  "Detector chip name",
                  "%s"));


  /*
  qc1log/out 1 {p2} "PRO.REC1.PIPE.ID" "{p_version}" "Pipeline (unique) identifier" PRO
  qc1log/out 1 {p1} {h_dprtype} "{dpr_type}" + DPR
  qc1log/out 1 {p2} {h_tpid} "{tpl_id}" + TPL
  qc1log/out 1 {p2} {h_arcfile} {arcfile} + PRIMARY-FITS
  qc1log/out 1 {p2} {h_procatg} {pro_catg} + PRO
  qc1log/out 1 {p2} {h_pipefile} {p2} + PRO
  set/format i1 f8.4,f8.4
   qc1log/out 1 {p2} {h_inspath} {{p1},{h_inspath}}                 "Optical path used."         UVES_ICS
   qc1log/out 1 {p2} {h_insmode} {{p1},{h_insmode}}                 "Instrument mode used."      UVES_ICS  
qc1log/out 1 {p2} "{h_namecros({PATHID})(5:18)}" {{p1},{h_namecros({PATHID})}}         "Grating common name"            UVES_ICS
nameccd =  "{{p1},{h_fits_nameccd({PATHID})}}"
qc1log/out 1 {p2} "{h_fits_nameccd({PATHID})(5:)}" "{nameccd}" "Detector chip name"              CCDDCS
qc1log/out 1 {p2} "{h_speed}"   {speed} "Readout speed"     CCDDCS
qc1log/out 1 {p2} "{h_xwinbin}" {binx}  "Binning factor along X"  CCDDCS
qc1log/out 1 {p2} "{h_ywinbin}" {biny}  "Binning factor along Y"  CCDDCS
set/format
  */

  ck0_nomsg(uves_qclog_add_string(qclog,
                  "DET READ SPEED",
                  read_speed,
                  "Readout speed",
                  "%8.4f"));


  ck0_nomsg(uves_qclog_add_double(qclog,
                  "DET BINX",
                  binx,
                  "Binning factor along X",
                  "%8.4f"));


  ck0_nomsg(uves_qclog_add_double(qclog,
                  "DET BINY",
                  biny,
                  "Binning factor along Y",
                  "%8.4f"));



  return 0;
 cleanup:
  return -1;

}


/*----------------------------------------------------------------------------*/
/**
   @brief    Create common QC log 
   @param    name          last part of QC name
   @param    flames        FLAMES?
   @param    trace_number  for FLAMES only
   @return   newly allocated QC name string
*/
/*----------------------------------------------------------------------------*/

int
uves_qclog_dump_common_wave(const uves_propertylist *plist,
                    enum uves_chip chip, 
                            cpl_table* qclog)
  {
    double slit_width=0;
    double temp_cam=0;
    double wave_len=0;
    check_nomsg(wave_len=uves_pfits_get_gratwlen(plist,chip));
    check_nomsg(temp_cam=uves_pfits_get_tempcam(plist,chip));
    check_nomsg(slit_width=uves_pfits_get_slitwidth(plist,chip));


 ck0_nomsg(uves_qclog_add_double(qclog,
                  "DET SLIT WIDTH",
                  slit_width,
                  "Slit width (arcsec) [arcsec] (hs).",
                  "%8.4f"));


 ck0_nomsg(uves_qclog_add_double(qclog,
                  "DET WCENT",
                  wave_len,
                  "Grating central wavelength [nm] (hs).",
                  "%8.4f"));


 ck0_nomsg(uves_qclog_add_double(qclog,
                  "TEMP CAM",
                  temp_cam,
                  "Average temperature [c] (ho).",
                  "%8.4f"));


    /*
    set/format i1 f8.4,f8.4
   qc1log/out 1 {p2} "{h_slwidth({PATHID})}"         {swid}     "Slit width (arcsec) [arcsec] (hs)."    UVES_ICS
qc1log/out 1 {p2} "{h_cwlen({PATHID})(5:)}"       {wlen}     "Grating central wavelength [nm] (hs)." UVES_ICS
qc1log/out 1 {p2} "{h_tempcam({PATHID})(5:)}"      {temp}    "Average temperature [c] (ho)."         UVES_ICS
set/format

    */
    return 0;

  cleanup:
    return -1;

}

/**@}*/
