/*
 * This file is part of the UVES Pipeline
 * Copyright (C) 2002, 2003, 2004, 2005 Europpean 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, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */

/*
 * $Author: amodigli $
 * $Date: 2013-04-16 15:46:38 $
 * $Revision: 1.110 $
 * $Name: not supported by cvs2svn $
 */

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

/*----------------------------------------------------------------------------*/
/**
 * @defgroup uves_pfits     FITS header protected access
 *
 *   Interface for reading/writing FITS keywords. 
 */
/*----------------------------------------------------------------------------*/
/**@{*/

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

/*-----------------------------------------------------------------------------
                Includes
 -----------------------------------------------------------------------------*/
#include <stdio.h>
#include <uves_pfits.h>

#include <uves_utils.h>
#include <uves_utils_wrappers.h>
#include <uves_dump.h>
#include <uves_error.h>

#include <irplib_utils.h>

#include <cpl.h>

#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
/*-----------------------------------------------------------------------------
                Forward declarations
 -----------------------------------------------------------------------------*/

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


/*--------------------------------------------------------------------------- */
/**
 *   @brief    Write the CD1 value
 *   @param    plist      Property list to write to
 *   @param    value      The value to write
 */
/*--------------------------------------------------------------------------- */
void uves_pfits_set_cd1(uves_propertylist * plist, double value)
{
  check(uves_propertylist_update_double (plist, UVES_CD1, value),
             "Error writing keyword '%s'", UVES_CD1);
  cleanup:
    return;
}


/*--------------------------------------------------------------------------- */
/**
 *   @brief    Write the CD1_1 value
 *   @param    plist      Property list to write to
 *   @param    value      The value to write
 */
/*--------------------------------------------------------------------------- */
void uves_pfits_set_cd11(uves_propertylist * plist, double value)
{
  check(uves_propertylist_update_double (plist, UVES_CD11, value),
             "Error writing keyword '%s'", UVES_CD11);
  cleanup:
    return;
}

/*--------------------------------------------------------------------------- */
/**
 *   @brief    Write the CD1_2 value
 *   @param    plist      Property list to write to
 *   @param    value      The value to write
 */
/*--------------------------------------------------------------------------- */
void uves_pfits_set_cd12(uves_propertylist * plist, double value)
{
  check(uves_propertylist_update_double (plist, UVES_CD12, value),
             "Error writing keyword '%s'", UVES_CD12);
  cleanup:
    return;
}

/*--------------------------------------------------------------------------- */
/**
 *   @brief    Write the CD2_1 value
 *   @param    plist      Property list to write to
 *   @param    value      The value to write
 */
/*--------------------------------------------------------------------------- */
void uves_pfits_set_cd21(uves_propertylist * plist, double value)
{
  check(uves_propertylist_update_double (plist, UVES_CD21, value),
             "Error writing keyword '%s'", UVES_CD21);
  cleanup:
    return;
}

/*--------------------------------------------------------------------------- */
/**
 *   @brief    Write the CD2_2 value
 *   @param    plist      Property list to write to
 *   @param    value      The value to write
 */
/*--------------------------------------------------------------------------- */
void uves_pfits_set_cd22(uves_propertylist * plist, double value)
{
  check(uves_propertylist_update_double (plist, UVES_CD22, value),
             "Error writing keyword '%s'", UVES_CD22);
  cleanup:
    return;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    find out the value of   UVES_ENCODER_REF1
  @param    plist   FITS header
  @return   keyword value
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_slit3_x1encoder(const uves_propertylist * plist)
{
  int result=0;
  check(result=uves_propertylist_get_int(plist,UVES_ENCODER_REF1),
        "Error getting %s", UVES_ENCODER_REF1);

 cleanup:
    return result; 

}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the value of   UVES_ENCODER_REF2
  @param    plist   FITS header
  @return   keyword value
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_slit3_x2encoder(const uves_propertylist * plist)
{
  int result=0;
  check(result=uves_propertylist_get_int(plist,UVES_ENCODER_REF2),
        "Error getting %s",UVES_ENCODER_REF2);


 cleanup:
    return result; 

}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the frame
  @param    plist   FITS header
  @return   number max of fibres
 */
/*----------------------------------------------------------------------------*/
int  uves_pfits_get_maxfibres(const uves_propertylist * plist)
{
  int result=0;
   check(uves_get_property_value(plist, "MAXFIBRES", 
                 CPL_TYPE_INT, &result),
    "Error reading MAXFIBRES");

 cleanup:
    return result; 

}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the frame
  @param    plist   FITS header
  @return   pointer to statically allocated character string
 */
/*----------------------------------------------------------------------------*/
char  uves_pfits_get_chipchoice(const uves_propertylist * plist)
{
  char result=0;
  check(result=uves_propertylist_get_char(plist,"CHIPCHOICE"),
    "Error getting CHIPCHOICE");

 cleanup:
    return result; 

}
/*----------------------------------------------------------------------------*/
/**
  @brief    find out the frame
  @param    plist   FITS header
  @return   pointer to statically allocated character string
 */
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_badpxframe(const uves_propertylist * plist)
{

  const char* result=NULL;

  check(uves_get_property_value(plist, "BADPXFRAME", 
                 CPL_TYPE_STRING, &result),
    "Error reading BADPXFRAME");

 cleanup:
    return result; 

}


/*----------------------------------------------------------------------------*/
/**
  @brief    find out the arcfile   
  @param    plist   FITS header
  @return   keyword value
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_ambipress(const uves_propertylist * plist)
{
  double result=0;

  check(uves_get_property_value(plist, "ESO INS SENS26 MEAN", 
                 CPL_TYPE_DOUBLE, &result),
    "Error reading ESO INS SENS26 MEAN");

 cleanup:
    return result; 

}


/*---------------------------------------------------------------------------*/
/**
  @brief    find out the arcfile   
  @param    plist   FITS header
  @return   pointer to statically allocated character string
 */
/*---------------------------------------------------------------------------*/
const char * uves_pfits_get_arcfile(const uves_propertylist * plist)
{

  const char* result=NULL;


  check(uves_get_property_value(plist, "ARCFILE", 
                 CPL_TYPE_STRING, &result),
    "Error reading ARCFILE");

 cleanup:
    return result; 

}

/*---------------------------------------------------------------------------*/
/**
  @brief    find out the ident   
  @param    plist   FITS header
  @return   pointer to statically allocated character string
 */
/*---------------------------------------------------------------------------*/
const char * uves_flames_pfits_get_ident(const uves_propertylist * plist)
{

  const char* result=NULL;

  check(result=uves_propertylist_get_string(plist,"IDENT"),
    "Error getting IDENT");

 cleanup:
    return result; 

}

/*---------------------------------------------------------------------------*/
/**
  @brief    find out the OBJECT   
  @param    plist   FITS header
  @return   pointer to statically allocated character string
 */
/*---------------------------------------------------------------------------*/
const char * uves_flames_pfits_get_object(const uves_propertylist * plist)
{

  const char* result=NULL;

  check(result=uves_propertylist_get_string(plist,UVES_OBJECT),
    "Error getting OBJECT");

 cleanup:
    return result; 

}

/*---------------------------------------------------------------------------*/
/**
  @brief    find out the origfile   
  @param    plist   FITS header
  @return   pointer to statically allocated character string
 */
/*---------------------------------------------------------------------------*/
const char * uves_pfits_get_origfile(const uves_propertylist * plist)
{

  const char* result=NULL;

  check(uves_get_property_value(plist, "ORIGFILE", 
                 CPL_TYPE_STRING, &result),
    "Error reading ORIGFILE");

 cleanup:
    return result; 

}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the pipefile   
  @param    plist   FITS header
  @return   pointer to statically allocated character string
 */
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_pipefile(const uves_propertylist * plist)
{

  const char* result=NULL;


  check(uves_get_property_value(plist, "PIPEFILE", 
                 CPL_TYPE_STRING, &result),
    "Error reading PIPEFILE");

 cleanup:
    return result; 

}




/*----------------------------------------------------------------------------*/
/**
  @brief    find out the arcfile   
  @param    plist   FITS header
  @return   pointer to statically allocated character string
 */
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_rec1raw1name(const uves_propertylist * plist)
{
  const char* result=NULL;

  check(uves_get_property_value(plist, "ESO PRO REC1 RAW1 NAME", 
                 CPL_TYPE_STRING, &result),
    "Error reading ESO PRO REC1 RAW1 NAME");


 cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    find out the template id    
  @param    plist   FITS header
  @return   pointer to statically allocated character string
*/
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_templateid(const uves_propertylist * plist)
{
  const char* result=NULL;

  check(uves_get_property_value(plist, "ESO TPL ID", 
                 CPL_TYPE_STRING, &result),
    "Error reading ESO TPL ID");


 cleanup:

    return result; 
}


/*----------------------------------------------------------------------------*/
/**     
  @brief    find out the date of observation  
  @param    plist    FITS file name
  @return   pointer to statically allocated character string
 */ 
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_date_obs(const uves_propertylist * plist)
{

  const char* result=NULL;
  check(uves_get_property_value(plist, "DATE-OBS", 
                 CPL_TYPE_STRING, &result),
    "Error reading DATE-OBS");

 cleanup:
    return result;

}
/*----------------------------------------------------------------------------*/
/**
  @brief    find out the data category as defined by the DataFlow
  @param    plist    source FITS header
  @return   statically allocated char string, no need to free() it
 */
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_dpr_catg(const uves_propertylist * plist)
{
  const char* result=NULL;

  check(uves_get_property_value(plist, UVES_DPR_CATG, 
                 CPL_TYPE_STRING, &result),
    "Error reading %s", UVES_DPR_CATG);

 cleanup:
    return result;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Read the SIMCAL flag
  @param    plist    source FITS header
  @return   SIMCAL flag as integer
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_ocs_simcal(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_OCS_SIMCAL, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_OCS_SIMCAL);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Set the SIMCAL flag
  @param    plist    FITS header
  @param    simcal   value to write
 */
/*----------------------------------------------------------------------------*/
void uves_pfits_set_ocs_simcal(uves_propertylist * plist, int simcal)
{
    check( uves_propertylist_update_int(plist, UVES_OCS_SIMCAL, simcal),
           "Error writing keyword '%s'", UVES_OCS_SIMCAL);

  cleanup:
    return;
    
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the product category as defined by the DataFlow
  @param    plist    source FITS header
  @return   statically allocated char string, no need to free() it
 */
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_pro_catg(const uves_propertylist * plist)
{
  const char* result=NULL;

  check(uves_get_property_value(plist, "ESO PRO CATG", 
                 CPL_TYPE_STRING, &result),
    "Error reading ESO PRO CATG");

 cleanup:
    return result;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the data tech as defined by the DataFlow
  @param    plist    source FITS header
  @return   statically allocated char string, no need to free() it
 */
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_dpr_tech(const uves_propertylist * plist)
{
  const char* result=NULL;

  check( uves_get_property_value(plist, UVES_DPR_TECH, 
                 CPL_TYPE_STRING, &result),
     "Error reading %s", UVES_DPR_TECH);

 cleanup:
    return result;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the data type as defined by the DataFlow
  @param    plist    source FITS header
  @return   statically allocated char string, no need to free() it
 */
/*----------------------------------------------------------------------------*/
const char * uves_pfits_get_dpr_type(const uves_propertylist * plist)
{
  const char* result=NULL;


  check( uves_get_property_value(plist, UVES_DPR_TYPE, 
                 CPL_TYPE_STRING, &result),
     "Error reading %s", UVES_DPR_TYPE);

 cleanup:
    return result;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out if CCD header is new
  @param    plist       Header to read from

  @return   true iff the observation date is later than July 6th, 2009
 */
/*----------------------------------------------------------------------------*/
bool uves_ccd_is_new(const uves_propertylist * plist)
{    
    double mjd_obs = 0.0; /* Observation date */

    check( mjd_obs = uves_pfits_get_mjdobs(plist),
       "Could not read observation date");

  cleanup:
    /* New format iff modified julian date is after April 1st, 2004 = 53096 mjd */
    return (mjd_obs > 55018.0);  
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out FITS header format
  @param    plist       Header to read from

  @return   true iff the observation date is later than April 1st, 2004
 */
/*----------------------------------------------------------------------------*/
bool uves_format_is_new(const uves_propertylist * plist)
{    
    double mjd_obs = 0.0; /* Observation date */

    check( mjd_obs = uves_pfits_get_mjdobs(plist),
       "Could not read observation date");

  cleanup:
    /* New format iff modified julian date is after April 1st, 2004 = 53096 mjd */
    return (mjd_obs > 53096.0);  
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the x-prescan
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_prescanx(const uves_propertylist * plist, enum uves_chip chip)
{
    int returnvalue = 0;
    bool new_format;
    
    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_PRESCANX(new_format, chip), 
                   CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword %s", UVES_PRESCANX(new_format, chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the chip ID
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error
**/
/*----------------------------------------------------------------------------*/
const char* uves_pfits_get_chipid(const uves_propertylist * plist, enum uves_chip chip)
{
    const char* returnvalue = "";

    check( uves_get_property_value(plist, UVES_CHIP_ID(chip), CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword %s", UVES_CHIP_ID(chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the chip name
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error
**/
/*----------------------------------------------------------------------------*/
const char* uves_pfits_get_chip_name(const uves_propertylist * plist, enum uves_chip chip)
{
    const char* returnvalue = "";

    check( uves_get_property_value(plist, UVES_CHIP_NAME(chip), CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword %s", UVES_CHIP_NAME(chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the x-overscan
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error
**/
/*----------------------------------------------------------------------------*/
int uves_pfits_get_ovrscanx(const uves_propertylist * plist, enum uves_chip chip)
{
    int returnvalue = 0;
    bool new_format;

    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_OVRSCANX(new_format, chip), 
                   CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword %s", UVES_OVRSCANX(new_format, chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the y-prescan
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_prescany(const uves_propertylist * plist, enum uves_chip chip)
{
    int returnvalue = 0;
    bool new_format;
    

    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_PRESCANY(new_format, chip), 
                   CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword %s", UVES_PRESCANY(new_format, chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the y-overscan
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error
**/
/*----------------------------------------------------------------------------*/
int uves_pfits_get_ovrscany(const uves_propertylist * plist, enum uves_chip chip)
{
    int returnvalue = 0;
    bool new_format;

    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_OVRSCANY(new_format, chip), 
                   CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword %s", UVES_OVRSCANY(new_format, chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the readout noise in ADU
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error

  The function reads the readout noise in electrons and multiplies
  by the gain (conversion factor from electrons to ADU).

  An error is set if the readout noise is not positive.
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_ron_adu(const uves_propertylist * plist, enum uves_chip chip)
{
    double ron_el = 0;          /* Read-out noise in electron units  */
    double default_ron_el = 5.0;/* Number converted from MIDAS       */
    double gain = 0;            /* Conversion from electrons to ADUs */
    bool new_format;

    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_RON(new_format, chip), CPL_TYPE_DOUBLE, &ron_el),
       "Error reading keyword '%s'", UVES_RON(new_format, chip));

    if (ron_el <= 0)
    {
        uves_msg_warning("Read-out-noise is "
                 "non-positive (%e electrons). Using default value %e",
                 ron_el, default_ron_el);
        ron_el = default_ron_el;
    }
    
    check( gain = uves_pfits_get_gain(plist, chip),
       "Error reading gain");
    
    assure( ron_el * gain > 0, CPL_ERROR_ILLEGAL_INPUT,
        "Non-positive read-out noise: %f ADU", ron_el * gain);
    
  cleanup:
    return ron_el * gain;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the start telescope altitude
  @param    plist       Header to read from

  @return   The requested value, or undefined on error

*/
/*----------------------------------------------------------------------------*/
double uves_pfits_get_tel_alt_start(const uves_propertylist * plist)
{
    double result = 0;

    check( uves_get_property_value(plist, UVES_TEL_ALT, CPL_TYPE_DOUBLE, &result),
       "Error reading keyword '%s'", UVES_TEL_ALT);

  cleanup:
    return result;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the start airmass
  @param    plist       Header to read from

  @return   The requested value, or undefined on error
  
*/
/*----------------------------------------------------------------------------*/
double uves_pfits_get_airmass_start(const uves_propertylist * plist)
{
    double result = 0;
    
    check( uves_get_property_value(plist, UVES_AIRMASS_START, CPL_TYPE_DOUBLE, &result),
       "Error reading keyword '%s'", UVES_AIRMASS_START);
    
  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the end airmass
  @param    plist       Header to read from

  @return   The requested value, or undefined on error
  
*/
/*----------------------------------------------------------------------------*/
double uves_pfits_get_airmass_end(const uves_propertylist * plist)
{
    double result = 0;
    
    check( uves_get_property_value(plist, UVES_AIRMASS_END, CPL_TYPE_DOUBLE, &result),
       "Error reading keyword '%s'", UVES_AIRMASS_END);
    
  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the conad
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error
  
*/
/*----------------------------------------------------------------------------*/
double uves_pfits_get_conad(const uves_propertylist * plist, enum uves_chip chip)
{
    double result = 0;
    
    bool new_format;

    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_CONAD(new_format, chip),
                   CPL_TYPE_DOUBLE, &result),
       "Error reading keyword '%s'", UVES_CONAD(new_format, chip));
    
  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    Get target name
  @param    plist       Header to read from

  @return   The requested value, or undefined on error
  
*/
/*----------------------------------------------------------------------------*/
const char *uves_pfits_get_targ_name(const uves_propertylist * plist)
{
    const char* returnvalue = "";

    check( uves_get_property_value(plist, UVES_TARG_NAME, CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword %s", UVES_TARG_NAME);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the gain
  @param    plist       Header to read from
  @param    chip        CCD chip

  @return   The requested value, or undefined on error
  
  The gain is in units of (ADU / el-).
*/
/*----------------------------------------------------------------------------*/
double uves_pfits_get_gain(const uves_propertylist * plist, enum uves_chip chip)
{
    double result = 0;
    double default_gain = 2.1;        /* Adopted from MIDAS */
    bool new_format;

    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_GAIN(new_format, chip),
                   CPL_TYPE_DOUBLE, &result),
       "Error reading keyword '%s'", UVES_GAIN(new_format, chip));
    
    if (result <= 0)
    {
        uves_msg_warning("Gain factor from header is "
                 "non-positive (%e). Using default value %e",
                 result, default_gain);
        result = default_gain;
    }

  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the exposure time in seconds
  @param    plist       Header to read from

  @return   The requested value, or undefined on error

  An error is set if the exposure time is negative. In that case this negative
  value is returned.
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_exptime(const uves_propertylist * plist)
{
    double result = 0;            /* Conversion from electrons to ADUs */
    
    check( uves_get_property_value(plist, UVES_EXPTIME, CPL_TYPE_DOUBLE, &result), 
       "Error reading keyword '%s'", UVES_EXPTIME);
    assure( result >= 0, CPL_ERROR_ILLEGAL_OUTPUT, "Exposure time is negative: %f", result);
    
  cleanup:
    return result;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Write the exposure time
  @param    plist        Property list to write to
  @param    exptime      The value to write

  @return   CPL_ERROR_NONE iff okay.
 */
/*----------------------------------------------------------------------------*/
cpl_error_code
uves_pfits_set_exptime(uves_propertylist *plist, double exptime)
{
    check(( uves_propertylist_update_double(plist, UVES_EXPTIME, exptime),
        uves_propertylist_set_comment(plist, UVES_EXPTIME, "Total integration time")),
       "Error writing keyword '%s'", UVES_EXPTIME);
  cleanup:
    return cpl_error_get_code();
}

/*--------------------------------------------------------------------------- */
/**
  @brief    find out the TEL AIRM END value
  @param    plist property list to read from
  @return   the requested value
*/
/*--------------------------------------------------------------------------- */
static double uves_pfits_get_airm_end (const cpl_propertylist * plist)
{

  return cpl_propertylist_get_double(plist,UVES_AIRMASS_END);
}

/*--------------------------------------------------------------------------- */
/**
  @brief    find out the TEL AIRM START value
  @param    plist property list to read from
  @return   the requested value
*/
/*--------------------------------------------------------------------------- */
static double uves_pfits_get_airm_start (const cpl_propertylist * plist)
{

  return cpl_propertylist_get_double(plist,UVES_AIRMASS_START);
}

/*--------------------------------------------------------------------------- */
/**
  @brief    find out the mean airmass value
  @param    plist property list to read from
  @return   the requested value
*/
/*--------------------------------------------------------------------------- */
double uves_pfits_get_airm_mean (const cpl_propertylist * plist)
{
  double airmass_start=0;
  double airmass_end=0;
 airmass_start = uves_pfits_get_airm_start(plist);
 airmass_end = uves_pfits_get_airm_end(plist);

 return 0.5*(airmass_start+airmass_end);
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Write the declination
  @param    plist        Property list to write to
  @param    dec          The value to write

  @return   CPL_ERROR_NONE iff okay.
 */
/*----------------------------------------------------------------------------*/
void
uves_pfits_set_dec(uves_propertylist *plist, double dec)
{
    check( uves_propertylist_update_double(plist, UVES_DEC, dec),
       "Error writing keyword '%s'", UVES_DEC);
  cleanup:
    return;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Write the right ascension
  @param    plist        Property list to write to
  @param    ra           The value to write

  @return   CPL_ERROR_NONE iff okay.
 */
/*----------------------------------------------------------------------------*/
void
uves_pfits_set_ra(uves_propertylist *plist, double ra)
{
    check( uves_propertylist_update_double(plist, UVES_RA, ra),
       "Error writing keyword '%s'", UVES_RA);
  cleanup:
    return;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Write the predicted number of order
  @param    plist        Property list to write to
  @param    nord         The value to write

  @return   CPL_ERROR_NONE iff okay.
 */
/*----------------------------------------------------------------------------*/
cpl_error_code
uves_pfits_set_ordpred(uves_propertylist *plist, int nord)
{
    check(( uves_propertylist_update_int(plist, UVES_ORD_PRED, nord),
        uves_propertylist_set_comment(plist, UVES_ORD_PRED, "Predicted no of orders")),
       "Error writing keyword '%s'", UVES_ORD_PRED);
  cleanup:
    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the drs id
  @param    plist       Header to read from
  @return   The requested value, or NULL on error
 */
/*----------------------------------------------------------------------------*/
const char *
uves_pfits_get_drs_id(const uves_propertylist * plist)
{
    const char *result = "";
    
    check( uves_get_property_value(plist, UVES_DRS_ID, CPL_TYPE_STRING, &result), 
       "Error reading keyword '%s'", UVES_DRS_ID);
    
  cleanup:
    if (cpl_error_get_code() != CPL_ERROR_NONE) 
    {
        result = NULL;
    }

    return result;
}



/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the tpl start
  @param    plist       Header to read from
  @return   The requested value, or NULL on error
 */
/*----------------------------------------------------------------------------*/
const char *
uves_pfits_get_tpl_start(const uves_propertylist * plist)
{
    const char *result = "";
    
    check( uves_get_property_value(plist, UVES_TPL_START, CPL_TYPE_STRING, &result),
       "Error reading keyword '%s'", UVES_TPL_START);
    
  cleanup:
    if (cpl_error_get_code() != CPL_ERROR_NONE) 
    {
        result = NULL;
    }

    return result;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the observation time
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_utc(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_UTC, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_UTC);
    
  cleanup:
    return returnvalue;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the modified julian observation date
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_mjdobs(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_MJDOBS, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_MJDOBS);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the telescope latitude
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_geolat(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_GEOLAT, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_GEOLAT);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the telescope longitude
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_geolon(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_GEOLON, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_GEOLON);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the right ascension
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_ra(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_RA, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_RA);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the declination
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_dec(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_DEC, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_DEC);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the x binning factor
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_binx(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_BINX, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_BINX);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the y binning factor 
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_biny(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_BINY, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_BINY);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Find out the number of input raw frames
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_datancom(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    /* This keyword changed name at some point. For support of older products, try to
       first new then old FITS card */

    assure( plist != NULL, CPL_ERROR_NULL_INPUT, "Null plist");

    if (uves_propertylist_contains(plist, UVES_DATANCOM))
    {
        check( uves_get_property_value(plist, UVES_DATANCOM, CPL_TYPE_INT, &returnvalue),
           "Error reading keyword '%s'", UVES_DATANCOM);
    }
    else if( uves_propertylist_contains(plist, UVES_DATANCOM_OLD)) 
    {
        
        check( uves_get_property_value(plist, UVES_DATANCOM_OLD, CPL_TYPE_INT, &returnvalue),
           "Error reading keyword '%s'", UVES_DATANCOM_OLD);
    } else {

      uves_msg_warning("Neither %s nor %s found! We assume a value of 5! This may affect noise/error propagation",
		       UVES_DATANCOM,UVES_DATANCOM_OLD);
      returnvalue=5;
    }
    
  cleanup:
    return returnvalue;
}



/*----------------------------------------------------------------------------*/
/**
  @brief    find out the ccd id  
  @param    plist       property list to read from
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
const char* uves_pfits_get_ccdid(const uves_propertylist * plist)
{
    const char* result="";
    
    check( uves_get_property_value(plist, UVES_CCDID, CPL_TYPE_STRING, &result), 
       "Error reading keyword '%s'", UVES_CCDID);
    
  cleanup:
    return result;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the pressure value  
  @param    plist       property list to read from
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_pressure(const uves_propertylist * plist)
{
    double returnvalue;
    
    check( uves_get_property_value(plist, UVES_PRESSURE, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_PRESSURE);
    
  cleanup:
    return returnvalue;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    chop the "ESO " prefix
  @param    key      keyword name
  @return   the requested value or NULL on error

  The function fails if the provided keyword does not start with "ESO "
 */
/*----------------------------------------------------------------------------*/
const char * uves_chop_eso_prefix(const char* key)
{
    const char *result = NULL;
    const char *prefix = "ESO ";
    unsigned int pref_len = strlen(prefix);
    
    assure( strlen(key) >= pref_len && 
        strncmp(key, prefix, pref_len) == 0,
        CPL_ERROR_ILLEGAL_INPUT,
        "Keyword %s does not contain 'ESO ' prefix", key);

    result = key + pref_len;

  cleanup:
    return result;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the pressure value  
  @param    plist       property list to read from
  @param    chip        CCD chip
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_tempcam(const uves_propertylist * plist, enum uves_chip chip)
{
    double returnvalue;
    
    check( uves_get_property_value(plist, UVES_TEMPCAM(chip), CPL_TYPE_DOUBLE, &returnvalue),
       "Error reading keyword '%s'", UVES_TEMPCAM(chip));
    
  cleanup:
    return returnvalue;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    find out the humidity value  
  @param    plist       property list to read from
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_humidity(const uves_propertylist * plist)
{
    double returnvalue;
    
    check( uves_get_property_value(plist, UVES_HUMIDITY, CPL_TYPE_DOUBLE, &returnvalue),
       "Error reading keyword '%s'", UVES_HUMIDITY);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the WLEN1 wavelength value
  @param    plist       property list to read from
  @return   the requested value which is always positive on success
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_wlen1(const uves_propertylist * plist)
{
    double returnvalue;

    check( uves_get_property_value(plist, "WLEN1", CPL_TYPE_DOUBLE, &returnvalue),
       "Error reading keyword '%s'", "WLEN1");

    assure(returnvalue > 0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive wavelength: %e", returnvalue);

  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the central wavelength
  @param    plist       property list to read from
  @param    chip        CCD chip
  @return   the requested value which is always positive on success
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_gratwlen(const uves_propertylist * plist, enum uves_chip chip)
{
    double returnvalue;
    
    check( uves_get_property_value(plist, UVES_GRATWLEN(chip), CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_GRATWLEN(chip));

    assure(returnvalue > 0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive wavelength: %e", returnvalue);
       
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the chip name value  
  @param    plist       property list to read from
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
const char* uves_pfits_get_insmode(const uves_propertylist * plist)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_INSMODE, CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword '%s'", UVES_INSMODE);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the chip name value  
  @param    plist       property list to read from
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
const char* uves_pfits_get_inspath(const uves_propertylist * plist)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_INSPATH, CPL_TYPE_STRING, &returnvalue),
       "Error reading keyword '%s'", UVES_INSPATH);
    
  cleanup:
    return returnvalue;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    find out the grating name value  
  @param    plist       property list to read from
  @param    chip        CCD chip
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
const char* uves_pfits_get_gratname(const uves_propertylist * plist, enum uves_chip chip)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_GRATNAME(chip), CPL_TYPE_STRING, &returnvalue),
       "Error reading keyword '%s'", UVES_GRATNAME(chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the readout speed
  @param    plist       property list to read from
  @param    chip        CCD chip
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
const char* uves_pfits_get_readspeed(const uves_propertylist * plist)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_READ_SPEED, CPL_TYPE_STRING, &returnvalue),
       "Error reading keyword '%s'", UVES_READ_SPEED);
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the grating ID value  
  @param    plist       property list to read from
  @param    chip        CCD chip
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
const char* uves_pfits_get_gratid(const uves_propertylist * plist, enum uves_chip chip)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_GRATID(chip), CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword '%s'", UVES_GRATID(chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    find out the slit length  
  @param    plist       property list to read from
  @param    chip        CCD chip
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_slitlength(const uves_propertylist * plist, enum uves_chip chip)
{
    double returnvalue;
    
    check( uves_get_property_value(plist, UVES_SLITLENGTH(chip), CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_SLITLENGTH(chip));
    
  cleanup:
    return returnvalue;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    find out the slit width
  @param    plist       property list to read from
  @param    chip        CCD chip
  @return   the requested value
 */
/*----------------------------------------------------------------------------*/
double uves_pfits_get_slitwidth(const uves_propertylist * plist, enum uves_chip chip)
{
    double returnvalue;
    
    check( uves_get_property_value(plist, UVES_SLITWIDTH(chip), CPL_TYPE_DOUBLE, &returnvalue),
       "Error reading keyword '%s'", UVES_SLITWIDTH(chip));
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Read the predicted number of orders
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
int uves_pfits_get_ordpred(const uves_propertylist * plist)
{
    cpl_type type;
    int returnvalue;

    assure( plist != NULL, CPL_ERROR_NULL_INPUT, "Null plist");
    
    /* In the UVES calibration data base this keyword
       is sometimes integer (e.g. '33'), sometimes a floating 
       point value (e.g. '33.'), so support both types */
    
    assure( uves_propertylist_contains(plist, UVES_ORD_PRED), 
        CPL_ERROR_DATA_NOT_FOUND,
        "Keyword %s does not exist", UVES_ORD_PRED);
    check ( type = uves_propertylist_get_type(plist, UVES_ORD_PRED), 
        "Error reading type of property '%s'", UVES_ORD_PRED);
    
    if (type == CPL_TYPE_INT)
    {
        check( uves_get_property_value(
               plist, UVES_ORD_PRED, CPL_TYPE_INT, &returnvalue), 
           "Error reading keyword '%s'", UVES_ORD_PRED);
    }
    else if (type == CPL_TYPE_DOUBLE)
    {
        double dvalue;
        check( uves_get_property_value(
               plist, UVES_ORD_PRED, CPL_TYPE_DOUBLE, &dvalue), 
           "Error reading keyword '%s'", UVES_ORD_PRED);
        returnvalue = uves_round_double(dvalue);
    }
    else
    {
        assure( false, CPL_ERROR_TYPE_MISMATCH,
            "Keyword '%s' has wrong type '%s'",
            UVES_ORD_PRED, uves_tostring_cpl_type(type));
    }
    
  cleanup:
    return returnvalue;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Write integer value to HISTORY keyword
  @param    plist        property list to write to
  @param    name         name
  @param    format       printf-style argument, value to write

  This function adds a HISTORY keyword with value "[name] [value]".
  If a HISTORY entry with value prefix "[name] " already exists,
  the value will be changed (first match is used).

  See also @c parse_history().
 */
/*----------------------------------------------------------------------------*/
void
uves_pfits_set_history_val(uves_propertylist *plist, const char *name, const char *format, ...)
{
    char *val_str = NULL;
    char *number_str = NULL;
    cpl_property *existing = NULL;
    va_list arglist;
    const long int plist_size = uves_propertylist_get_size(plist);
    int i;

    for (i = 0;
     existing == NULL && i < plist_size; i++)
    {
        cpl_property *p = uves_propertylist_get(plist, i);
        const char *pname = cpl_property_get_name(p);
        
        if (strcmp(pname, "HISTORY") == 0)
        {
            const char *pval;
            check( pval = cpl_property_get_string(p),
               "Error reading property value");
            
            /* match the string  "<name> " */
            
            if (strlen(pval) > strlen(name) + strlen(" ") &&
            strncmp(pval, name, strlen(name)) == 0 &&
            pval[strlen(name)] == ' ')
            {
                /* Remember this one and stop searching */
                existing = p;
            }
        }
    }

    va_start(arglist, format);
    number_str = cpl_vsprintf(format, arglist);
    va_end(arglist);

    val_str = uves_sprintf("%s %s", name, number_str);

    if (existing != NULL)
    {
        check( cpl_property_set_string(existing, val_str),
           "Error updating HISTORY keyword with value '%s'", val_str);
    }
    else
    {
        check( uves_propertylist_append_string(plist, "HISTORY", val_str),
           "Error writing HISTORY keyword with value '%s'", val_str);
    }

  cleanup:
    cpl_free(val_str);
    cpl_free(number_str);
    return;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    Parse the value of a HISTORY keyword
  @param    plist        property list to read from
  @param    name         name 
  @param    type         integer or double
  @return   The requested value, or undefined on error. An integer value is cast
            to double (i.e. the caller should round the returned value)

  This function will search for a HISTORY keyword containing the value
  "[name] [number]" where [name] is the specified name and @em number
  is an integer or double (the value to read).
  
  The first "HISTORY [name] ..." entry will be read and it is an error if
  this doesn't contain a valid number string (also if a valid entry exists
  at a later point in the propertylist).
 */
/*----------------------------------------------------------------------------*/
static double
parse_history(const uves_propertylist *plist, const char *name, cpl_type type)
{
    double returnvalue = 0;
    const long int plist_size = uves_propertylist_get_size(plist);
    int i;
    bool found;

    found = false;
    for (i = 0; !found && i < plist_size; i++) {
        const cpl_property *p = uves_propertylist_get_const(plist, i);
        const char *value = cpl_property_get_name(p);
        
        if (strcmp(value, "HISTORY") == 0) {
            check( value = cpl_property_get_string(p),
                   "Error reading property value");
            
            /* match the string  "<name> " */
            
            if (strlen(value) > strlen(name) + strlen(" ") &&
                strncmp(value, name, strlen(name)) == 0 &&
                value[strlen(name)] == ' ') {
                errno = 0;
                switch(type) {
                case CPL_TYPE_INT:
                    returnvalue = atoi(value + strlen(name) + strlen(" "));
                    assure(errno == 0, CPL_ERROR_ILLEGAL_INPUT, 
                           "Could not parse string '%s' as integer. "
                           "atoi() returned %d",
                           value + strlen(name) + strlen(" "), errno);
                    break;
                case CPL_TYPE_DOUBLE:
                    returnvalue = strtod(value + strlen(name) + strlen(" "), NULL);
                    assure(errno == 0, CPL_ERROR_ILLEGAL_INPUT, 
                           "Could not parse string '%s' as double. "
                           "strtod() returned %d",
                           value + strlen(name) + strlen(" "), errno);
                    break;
                default:
                    assure( false, CPL_ERROR_UNSUPPORTED_MODE,
                            "Type is %s", uves_tostring_cpl_type(type));
                    break;
                }
                found = true;
            }
        }
    }
    
    assure( found, CPL_ERROR_DATA_NOT_FOUND, "Missing record 'HISTORY %s '",
        name );

  cleanup:
    return returnvalue;
}
    
/*----------------------------------------------------------------------------*/
/**
  @brief    Write the first absolute order number
  @param    plist           Property list to write to
  @param    first_abs_order  The value to write

  @return   CPL_ERROR_NONE iff okay.
 */
/*----------------------------------------------------------------------------*/
void
uves_pfits_set_firstabsorder(uves_propertylist *plist, int first_abs_order)
{
    uves_pfits_set_history_val(plist, UVES_FIRSTABSORDER, "%d", first_abs_order);

    return;
}



/*----------------------------------------------------------------------------*/
/**
  @brief    Get first absolute order number
  @param    plist        Property list to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
int
uves_pfits_get_firstabsorder(const uves_propertylist * plist)
{
    return uves_round_double(parse_history(plist, UVES_FIRSTABSORDER, CPL_TYPE_INT));
}


/*----------------------------------------------------------------------------*/
/**
  @brief    Write the last absolute order number
  @param    plist           Property list to write to
  @param    last_abs_order  The value to write

  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
void
uves_pfits_set_lastabsorder(uves_propertylist *plist, int last_abs_order)
{
    uves_pfits_set_history_val(plist, UVES_LASTABSORDER, "%d", last_abs_order);

    return;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    Get last absolute order number
  @param    plist        Property list to read from
  @return   The requested value, or undefined on error
 */
/*----------------------------------------------------------------------------*/
int
uves_pfits_get_lastabsorder(const uves_propertylist * plist)
{
    return uves_round_double(parse_history(plist, UVES_LASTABSORDER, CPL_TYPE_INT));
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the average pixel value
  @param    plist       Property list to write to
  @param    average     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_data_average(uves_propertylist * plist, double average)
{
    check(( uves_propertylist_update_double(plist, UVES_PRO_DATAAVG, average),
        uves_propertylist_set_comment  (plist, UVES_PRO_DATAAVG, "Mean of pixel values")),
       "Error writing keyword '%s'", UVES_PRO_DATAAVG);
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the RMS error of pixel values
  @param    plist       Property list to write to
  @param    stddev      The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_data_stddev(uves_propertylist * plist, double stddev)
{
    check(( uves_propertylist_update_double(plist, UVES_PRO_DATARMS, stddev),
        uves_propertylist_set_comment  (plist, UVES_PRO_DATARMS, 
                       "Standard deviation of pixel values")),
       "Error writing keyword '%s'", UVES_PRO_DATARMS);
  
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the median pixel value
  @param    plist       Property list to write to
  @param    median      The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_data_median(uves_propertylist * plist, double median)
{
    check(( uves_propertylist_update_double(plist, UVES_PRO_DATAMED, median),
        uves_propertylist_set_comment  (plist, UVES_PRO_DATAMED, "Median of pixel values")),
       "Error writing keyword '%s'", UVES_PRO_DATAMED);

  cleanup:
    return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the min pixel value
  @param    plist       Property list to write to
  @param    min         The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_data_min(uves_propertylist * plist, double min)
{
    check(( uves_propertylist_update_double(plist, UVES_DATAMIN, min),
        uves_propertylist_set_comment  (plist, UVES_DATAMIN, "Minimum of pixel values")),
        "Error writing keyword '%s'", UVES_DATAMIN);
  
  cleanup:
    return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the max pixel value
  @param    plist       Property list to write to
  @param    max         The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_data_max(uves_propertylist * plist, double max)
{
    check(( uves_propertylist_update_double(plist, UVES_DATAMAX, max),
        uves_propertylist_set_comment  (plist, UVES_DATAMAX, 
                                            "Maximum of pixel values")),
          "Error writing keyword '%s'", UVES_DATAMAX);
  
  cleanup:
    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Write the WLEN1 value
  @param    plist           Property list to write to
  @param    wlen1  The value to write

  @return   CPL_ERROR_NONE iff okay.
 */
/*----------------------------------------------------------------------------*/
cpl_error_code
uves_pfits_set_wlen1(uves_propertylist *plist, double wlen1)
{
    uves_propertylist_update_double(plist, "WLEN1", wlen1);

    return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the trace ID
  @param    plist        Property list to write to
  @param    trace_id     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
void
uves_pfits_set_traceid(uves_propertylist * plist, int trace_id)
{
    uves_pfits_set_history_val(plist, UVES_TRACEID, "%d", trace_id);    
    return;
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Get the trace offset
  @param    plist        Property list to read
  @return   offset
 */
/*---------------------------------------------------------------------------*/
double
uves_pfits_get_offset(const uves_propertylist *plist)
{
    double offset;
    if (uves_propertylist_contains(plist, UVES_TRACE_OFFSET)) 
        /* MIDAS format */
        {
            check( uves_get_property_value(plist, UVES_TRACE_OFFSET, CPL_TYPE_DOUBLE,
                                           &offset), 
                   "Error reading keyword %s", UVES_TRACE_OFFSET);
        }
    else
        {
            offset = parse_history(plist, UVES_TRACE_OFFSET, CPL_TYPE_DOUBLE);
        }

  cleanup:    
    return offset;
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the trace offset
  @param    plist        Property list to write to
  @param    trace_offset The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
void
uves_pfits_set_offset(uves_propertylist * plist, double trace_offset)
{
    uves_pfits_set_history_val(plist, UVES_TRACE_OFFSET, "%f", trace_offset);
    return;
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the window number
  @param    plist        Property list to write to
  @param    window_number The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
void
uves_pfits_set_windownumber(uves_propertylist * plist, int window_number)
{
    uves_pfits_set_history_val(plist, UVES_WINDOWNUMBER, "%d", window_number);
    return;
}


/*---------------------------------------------------------------------------*/
/**
  @brief    Get the trace ID number
  @param    plist        Property list to read from
  @return   The requested value, or undefined on error
 */
/*---------------------------------------------------------------------------*/
int
uves_pfits_get_traceid(const uves_propertylist * plist)
{
    return uves_round_double(parse_history(plist, UVES_TRACEID, CPL_TYPE_INT));
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Get the window number
  @param    plist          Property list to read from
  @return   The requested value, or undefined on error
 */
/*---------------------------------------------------------------------------*/
int
uves_pfits_get_windownumber(const uves_propertylist * plist)
{
    return uves_round_double(parse_history(plist, UVES_WINDOWNUMBER, CPL_TYPE_INT));
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the bunit
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
const char* 
uves_pfits_get_bunit(const uves_propertylist * plist)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_BUNIT, CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword '%s'", UVES_BUNIT);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the bscale
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_bscale(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_BSCALE, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_BSCALE);
    
  cleanup:
    return returnvalue;
}


/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the cunit1
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
const char* 
uves_pfits_get_cunit1(const uves_propertylist * plist)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_CUNIT1, CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword '%s'", UVES_CUNIT1);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the cunit2
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
const char* 
uves_pfits_get_cunit2(const uves_propertylist * plist)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_CUNIT2, CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword '%s'", UVES_CUNIT2);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the ctype1
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
const char* 
uves_pfits_get_ctype1(const uves_propertylist * plist)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_CTYPE1, CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword '%s'", UVES_CTYPE1);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the ctype2
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
const 
char* uves_pfits_get_ctype2(const uves_propertylist * plist)
{
    const char* returnvalue="";
    
    check( uves_get_property_value(plist, UVES_CTYPE2, CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword '%s'", UVES_CTYPE2);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the user integration time
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_uit(const uves_propertylist * plist)
{
    double returnvalue = 0;
    bool new_format;
    
    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_UIT(new_format), CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword %s", UVES_UIT(new_format));
    
  cleanup:
    return returnvalue;

}


/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the OUT1 NX or OUT4 NX
   @param    plist       Property list to read from
   @param    chip        CCD chip
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_nx(const uves_propertylist * plist,enum uves_chip chip)
{

    int returnvalue = 0;
    bool new_format;
    
    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_NX(new_format, chip), CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword %s", UVES_NX(new_format, chip));
    
  cleanup:
    return returnvalue;

}




/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the OUT1 NY or OUT4 NY
   @param    plist       Property list to read from
   @param    chip        CCD chip
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_ny(const uves_propertylist * plist,enum uves_chip chip)
{

    int returnvalue = 0;
    bool new_format;
    
    check( new_format = uves_format_is_new(plist),
       "Error determining FITS header format");
    
    check( uves_get_property_value(plist, UVES_NY(new_format, chip), CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword %s", UVES_NY(new_format, chip));
    
  cleanup:
    return returnvalue;

}



/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the OUT1 NX
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_out1nx(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_OUT1NX, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_OUT1NX);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the OUT1 NY
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_out1ny(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_OUT1NY, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_OUT1NY);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the OUT4 NX
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_out4nx(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_OUT4NX, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_OUT4NX);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the OUT4 NY
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_out4ny(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_OUT4NY, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_OUT4NY);
    
  cleanup:
    return returnvalue;
}


/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the NAXIS
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_naxis(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_NAXIS, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_NAXIS);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the NFLATS
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_flames_pfits_get_nflats(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, FLAMES_NFLATS, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", FLAMES_NFLATS);
    
  cleanup:
    return returnvalue;
}


/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the BITPIX
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_bitpix(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_BITPIX, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_BITPIX);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the NAXIS1
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int uves_pfits_get_naxis1(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_NAXIS1, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_NAXIS1);
    
  cleanup:
    return returnvalue;
}


/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the START1
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_startx(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_STARTX, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_STARTX);
    
  cleanup:
    return returnvalue;
}


/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the STARTY
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_starty(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_STARTY, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_STARTY);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the NAXIS2
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
int 
uves_pfits_get_naxis2(const uves_propertylist * plist)
{
    int returnvalue = 0;
    
    check( uves_get_property_value(plist, UVES_NAXIS2, CPL_TYPE_INT, &returnvalue), 
       "Error reading keyword '%s'", UVES_NAXIS2);
    
  cleanup:
    return returnvalue;
}
/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the crval1
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_crval1(const uves_propertylist * plist)
{
    double returnvalue = 0.0;
    
    check( uves_get_property_value(plist, UVES_CRVAL1, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_CRVAL1);
    
  cleanup:
    return returnvalue;
}
/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the crval2
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_crval2(const uves_propertylist * plist)
{
    double returnvalue = 0.0;
    
    check( uves_get_property_value(plist, UVES_CRVAL2, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_CRVAL2);
    
  cleanup:
    return returnvalue;
}
/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the crpix1
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_crpix1(const uves_propertylist * plist)
{
    double returnvalue = 0.0;
    
    check( uves_get_property_value(plist, UVES_CRPIX1, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_CRPIX1);
    
  cleanup:
    return returnvalue;
}
/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the crpix2
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_crpix2(const uves_propertylist * plist)
{
    double returnvalue = 0.0;
    
    check( uves_get_property_value(plist, UVES_CRPIX2, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_CRPIX2);
    
  cleanup:
    return returnvalue;
}
/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the cdelt1
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_cdelt1(const uves_propertylist * plist)
{
    double returnvalue = 0.0;
    
    check( uves_get_property_value(plist, UVES_CDELT1, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_CDELT1);
    
  cleanup:
    return returnvalue;
}
/*---------------------------------------------------------------------------*/
/**
   @brief    Find out the cdelt2
   @param    plist       Property list to read from
   @return   the requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_cdelt2(const uves_propertylist * plist)
{
    double returnvalue = 0.0;
    
    check( uves_get_property_value(plist, UVES_CDELT2, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", UVES_CDELT2);
    
  cleanup:
    return returnvalue;
}


/*---------------------------------------------------------------------------*/
/**
   @brief    Set DPR CATG value
   @param    plist       Property list to read from
   @param    catg        key value
   @return   void
 */
/*---------------------------------------------------------------------------*/
void 
uves_pfits_set_dpr_catg(uves_propertylist * plist, const char *catg)
{
    check( uves_propertylist_update_string(plist, UVES_DPR_CATG, catg),
           "Error writing %s", UVES_DPR_CATG);
  cleanup:
    return;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Set DPR TECH value
   @param    plist       Property list to read from
   @param    catg        key value
   @return   void
 */
/*---------------------------------------------------------------------------*/
void 
uves_pfits_set_dpr_tech(uves_propertylist * plist, const char *tech)
{
    check( uves_propertylist_update_string(plist, UVES_DPR_TECH, tech),
           "Error writing %s", UVES_DPR_TECH);
  cleanup:
    return;
}
/*---------------------------------------------------------------------------*/
/**
   @brief    Set DPR TYPE value
   @param    plist       Property list to read from
   @param    catg        key value
   @return   void
 */
/*---------------------------------------------------------------------------*/
void 
uves_pfits_set_dpr_type(uves_propertylist * plist, const char *type)
{
    check( uves_propertylist_update_string(plist, UVES_DPR_TYPE, type),
           "Error writing %s", UVES_DPR_TYPE);
  cleanup:
    return;
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the object keyword
  @param    plist       Property list to write to
  @param    object     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_object(uves_propertylist * plist, const char *object)
{
    check( uves_propertylist_update_string(plist, UVES_OBJECT, object),
       "Error writing keyword '%s'", UVES_OBJECT);
    
  cleanup:
    return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the object keyword
  @param    plist       Property list to write to
  @param    corr        The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_badpixcorr(uves_propertylist * plist, const char *corr)
{
    check( uves_propertylist_update_string(plist, UVES_QC_BADPIXCORR, corr),
       "Error writing keyword '%s'", UVES_QC_BADPIXCORR);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the reduction level
  @param    plist       Property list to write to
  @param    redlevel    The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_redlevel(uves_propertylist * plist, const char *redlevel)
{
    check( uves_propertylist_update_string(plist, UVES_REDLEVEL, redlevel),
       "Error writing keyword '%s'", UVES_REDLEVEL);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the status
  @param    plist       Property list to write to
  @param    status      The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_status(uves_propertylist * plist, const char *status)
{
    check( uves_propertylist_update_string(plist, UVES_STATUS, status),
       "Error writing keyword '%s'", UVES_STATUS);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the start time
  @param    plist       Property list to write to
  @param    start_time  The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_starttime(uves_propertylist * plist, const char *start_time)
{
    check( uves_propertylist_update_string(plist, UVES_START, start_time),
       "Error writing keyword '%s'", UVES_START);
    
  cleanup:
    return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the stop time
  @param    plist       Property list to write to
  @param    stop_time   The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_stoptime(uves_propertylist * plist, const char *stop_time)
{
    check( uves_propertylist_update_string(plist, UVES_STOP, stop_time),
       "Error writing keyword '%s'", UVES_STOP);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the bunit keyword
  @param    plist       Property list to write to
  @param    bunit     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_bunit(uves_propertylist * plist, const char *bunit)
{
    check( uves_propertylist_update_string(plist, UVES_BUNIT, bunit),
       "Error writing keyword '%s'", UVES_BUNIT);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the bscale keyword
  @param    plist       Property list to write to
  @param    bscale     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_bscale(uves_propertylist * plist, const double bscale)
{
    check( uves_propertylist_update_double(plist, UVES_BSCALE, bscale),
       "Error writing keyword '%s'", UVES_BSCALE);
    
  cleanup:
    return cpl_error_get_code();
}


/*---------------------------------------------------------------------------*/
/**
  @brief    Write the tunit keyword
  @param    plist       Property list to write to
  @param    bunit     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_tunit_no(uves_propertylist * plist, const int col_no, const char *tunit)
{
   char key_name[20];
   sprintf(key_name,"%s%d",UVES_TUNIT,col_no);
   uves_msg("Filling key %s with value %s",key_name,tunit);
    check( uves_propertylist_update_string(plist, key_name, tunit),
       "Error writing keyword '%s'", key_name);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the bunit keyword
  @param    plist       Property list to write to
  @param    bunit     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_bunit_no(uves_propertylist * plist, const int axis_no, const char *bunit)
{
    check( uves_propertylist_update_string(plist, UVES_BUNIT, bunit),
       "Error writing keyword '%s'", UVES_BUNIT);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the EXTNAME keyword
  @param    plist       Property list to write to
  @param    extname     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code
uves_pfits_set_extname(uves_propertylist * plist, const char *extname)
{

    check( uves_propertylist_append_string(plist, "EXTNAME", extname),
              "Error writing EXTNAME keyword with value '%s'", extname);

  cleanup:
    return cpl_error_get_code();
}


/*---------------------------------------------------------------------------*/
/**
  @brief    Write the ctype1 keyword
  @param    plist       Property list to write to
  @param    ctype1     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_ctype1(uves_propertylist * plist, const char *ctype1)
{
    check( uves_propertylist_update_string(plist, UVES_CTYPE1, ctype1),
       "Error writing keyword '%s'", UVES_CTYPE1);
    
  cleanup:
    return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the ctype2 keyword
  @param    plist       Property list to write to
  @param    ctype2     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_ctype2(uves_propertylist * plist, const char *ctype2)
{
    check( uves_propertylist_update_string(plist, UVES_CTYPE2, ctype2),
       "Error writing keyword '%s'", UVES_CTYPE2);
    
  cleanup:
    return cpl_error_get_code();
}



/*---------------------------------------------------------------------------*/
/**
  @brief    Write the cunit1 keyword
  @param    plist       Property list to write to
  @param    cunit1     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_cunit1(uves_propertylist * plist, const char *cunit1)
{
    check( uves_propertylist_update_string(plist, UVES_CUNIT1, cunit1),
       "Error writing keyword '%s'", UVES_CUNIT1);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the cunit2 keyword
  @param    plist       Property list to write to
  @param    cunit2     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_cunit2(uves_propertylist * plist, const char *cunit2)
{
    check( uves_propertylist_update_string(plist, UVES_CUNIT2, cunit2),
       "Error writing keyword '%s'", UVES_CUNIT2);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the crval1 keyword
  @param    plist       Property list to write to
  @param    crval1     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_crval1(uves_propertylist * plist, double crval1)
{
    check( uves_propertylist_update_double(plist, UVES_CRVAL1, crval1),
       "Error writing keyword '%s'", UVES_CRVAL1);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the crval2 keyword
  @param    plist       Property list to write to
  @param    crval2     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_crval2(uves_propertylist * plist, double crval2)
{
    check( uves_propertylist_update_double(plist, UVES_CRVAL2, crval2),
       "Error writing keyword '%s'", UVES_CRVAL2);
    
  cleanup:
    return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the crpix1 keyword
  @param    plist       Property list to write to
  @param    crpix1     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_crpix1(uves_propertylist * plist, double crpix1)
{
    check( uves_propertylist_update_double(plist, UVES_CRPIX1, crpix1),
       "Error writing keyword '%s'", UVES_CRPIX1);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the crpix2 keyword
  @param    plist       Property list to write to
  @param    crpix2     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_crpix2(uves_propertylist * plist, double crpix2)
{
    check( uves_propertylist_update_double(plist, UVES_CRPIX2, crpix2),
       "Error writing keyword '%s'", UVES_CRPIX2);
    
  cleanup:
    return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the cdelt1 keyword
  @param    plist       Property list to write to
  @param    cdelt1     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_cdelt1(uves_propertylist * plist, double cdelt1)
{
    check( uves_propertylist_update_double(plist, UVES_CDELT1, cdelt1),
       "Error writing keyword '%s'", UVES_CDELT1);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the ccfposmax keyword (what is it?)
  @param    plist       Property list to write to
  @param    ccfposmax   The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
void 
uves_flames_pfits_set_ccfposmax(uves_propertylist *plist, double ccfposmax)
{
    check( uves_propertylist_update_double(plist, FLAMES_CCFPOSMAX, ccfposmax),
       "Error writing keyword '%s'", FLAMES_CCFPOSMAX);

  cleanup:
    return;
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the cdelt2 keyword
  @param    plist       Property list to write to
  @param    cdelt2     The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_cdelt2(uves_propertylist * plist, double cdelt2)
{
    check( uves_propertylist_update_double(plist, UVES_CDELT2, cdelt2),
       "Error writing keyword '%s'", UVES_CDELT2);
    
  cleanup:
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the 2d extractino slit length
  @param    plist    Property list to write to
  @param    hs       The value to write
 */
/*---------------------------------------------------------------------------*/
void 
uves_pfits_set_hs(uves_propertylist * plist, int hs)
{
    check( uves_propertylist_update_int(plist, UVES_HS, hs),
       "Error writing keyword '%s'", UVES_HS);
    
  cleanup:
    return;
}


/*---------------------------------------------------------------------------*/
/**
  @brief    Write the wstart keyword
  @param    plist       Property list to write to
  @param    order       Write WSTART keyword for this order number
  @param    wstart      The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_wstart(uves_propertylist * plist, int order, double wstart)
{
    char *wstart_string = NULL;

    assure (1 <= order && order <= 99, CPL_ERROR_ILLEGAL_INPUT, 
        "Illegal order number: %d. Allowed range is 1 to 99", order);
    
    /* allocate room for two digits and '\0' */
    wstart_string = cpl_malloc( strlen(UVES_WSTART) + 2 + 1);  
    assure_mem( wstart_string );

    snprintf(wstart_string, strlen(UVES_WSTART)+2+1, UVES_WSTART "%d", order);
    
    check( uves_propertylist_update_double(plist, wstart_string, wstart ),
       "Error updating product header");
        
  cleanup:
    cpl_free(wstart_string);
    return cpl_error_get_code();
}


/*---------------------------------------------------------------------------*/
/**
  @brief    Read the wstart keyword
  @param    plist       Property list to read
  @param    order       Read WSTART keyword for this order number
  @return   The value read
 */
/*---------------------------------------------------------------------------*/

double 
uves_pfits_get_wstart(const uves_propertylist * plist, int order)
{
    double returnvalue;
    char *wstart = NULL;

    assure (1 <= order && order <= 99, CPL_ERROR_ILLEGAL_INPUT, 
        "Illegal order number: %d. Allowed range is 1 to 99", order);
    
    /* allocate room for two digits and '\0' */
    wstart = cpl_malloc( strlen(UVES_WSTART) + 2 + 1);  
    assure_mem( wstart );
    
    snprintf(wstart, strlen(UVES_WSTART)+2+1, UVES_WSTART "%d", order);
    
    check( uves_get_property_value(plist, wstart, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", wstart);
    
  cleanup:
    cpl_free(wstart);
    return returnvalue;
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Write the wend keyword
  @param    plist       Property list to write to
  @param    order       Write WEND keyword for this order number
  @param    wend      The value to write
  @return   CPL_ERROR_NONE iff okay
 */
/*---------------------------------------------------------------------------*/
cpl_error_code 
uves_pfits_set_wend(uves_propertylist * plist, int order, double wend)
{
    char *wend_string = NULL;

    assure (1 <= order && order <= 99, CPL_ERROR_ILLEGAL_INPUT, 
        "Illegal order number: %d. Allowed range is 1 to 99", order);
    
    /* allocate room for two digits and '\0' */
    wend_string = cpl_malloc( strlen(UVES_WEND) + 2 + 1);  
    assure_mem( wend_string );

    snprintf(wend_string, strlen(UVES_WEND)+2+1, UVES_WEND "%d", order);
    
    check( uves_propertylist_update_double(plist, wend_string, wend ),
       "Error updating product header");
        
  cleanup:
    cpl_free(wend_string);
    return cpl_error_get_code();
}


/*---------------------------------------------------------------------------*/
/**
  @brief    Read the wend keyword
  @param    plist       Property list to read
  @param    order       Read WEND keyword for this order number
  @return   The value read
 */
/*---------------------------------------------------------------------------*/

double 
uves_pfits_get_wend(const uves_propertylist * plist, int order)
{
    double returnvalue;
    char *wend = NULL;

    assure (1 <= order && order <= 99, CPL_ERROR_ILLEGAL_INPUT, 
        "Illegal order number: %d. Allowed range is 1 to 99", order);
    
    /* allocate room for two digits and '\0' */
    wend = cpl_malloc( strlen(UVES_WEND) + 2 + 1);  
    assure_mem( wend );
    
    snprintf(wend, strlen(UVES_WEND)+2+1, UVES_WEND "%d", order);
    
    check( uves_get_property_value(plist, wend, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", wend);
    
  cleanup:
    cpl_free(wend);
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Get pixel scale
   @param    plist       Property list to read from
   @return   The requested value
 */
/*---------------------------------------------------------------------------*/
double 
uves_pfits_get_pixelscale(const uves_propertylist *plist)
{
    double pixelscale = 0;
    
    check( uves_get_property_value(plist, UVES_PIXELSCALE, CPL_TYPE_DOUBLE, &pixelscale),
           "Error reading keyword '%s'", UVES_PIXELSCALE);
    
  cleanup:
    return pixelscale;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Get image slicer name
   @param    plist       Property list to read from
   @return   The requested value
 */
/*---------------------------------------------------------------------------*/
const char* 
uves_pfits_get_slit1_name(const uves_propertylist * plist)
{
    const char* returnvalue = "";
    
    check( uves_get_property_value(plist, UVES_SLIT1NAME, CPL_TYPE_STRING, &returnvalue), 
       "Error reading keyword '%s'", UVES_SLIT1NAME);
    
  cleanup:
    return returnvalue;
}


/*---------------------------------------------------------------------------*/
/**
  @brief    Read the slit length in pixels
  @param    plist       Property list to read
  @param    chip        CCD chip
  @return   The slit length in pixels

  The function returns the slit length in pixels taking into account
  the possible existence of an image slicer
 */
/*---------------------------------------------------------------------------*/

double 
uves_pfits_get_slitlength_pixels(const uves_propertylist * plist, 
                                 enum uves_chip chip)
{
    double slitlength_pixels = 0;         /* Result */
    
    const char *slicer_name = "";
    double slitlength_arcsecs = 0;        /* Slit length in arc-seconds */

    check( slicer_name = uves_pfits_get_slit1_name(plist),
       "Could not read slicer id");

    if ( strncmp(slicer_name, "FREE", 4) != 0)
    {
        /* Slicer inserted */
        if      (strncmp(slicer_name, "SLIC#1", 6) == 0) slitlength_arcsecs = 8.0;
        else if (strncmp(slicer_name, "SLIC#2", 6) == 0) slitlength_arcsecs = 8.0;
        else if (strncmp(slicer_name, "SLIC#3", 6) == 0) slitlength_arcsecs = 10.0;
        else
        {
            assure( false, CPL_ERROR_ILLEGAL_INPUT, "Unrecognized slicer name: '%s'. "
                "Recognized names are 'FREE', 'SLIC#1', 'SLIC#2', 'SLIC#3'.", 
                slicer_name);
        }
    }
    else
    {
        /*  slicer_name = 'FREE', no slicer */

        check( uves_get_property_value(
               plist, UVES_SLITLENGTH(chip), CPL_TYPE_DOUBLE, &slitlength_arcsecs),
           "Error reading keyword '%s'", UVES_SLITLENGTH(chip));
    }

    /* Convert from arcseconds to pixels */
    {
    double pixelscale;         /* Arcseconds per pixel */
    int binx;                  /* The x-binning of the raw image 
                      is the y-binning of the extracted/rotated image */
    
    check_nomsg( pixelscale = uves_pfits_get_pixelscale(plist) );

    check( binx = uves_pfits_get_binx(plist),
           "Could not get x-binning");

    slitlength_pixels = slitlength_arcsecs / (pixelscale * binx);
    }
    
  cleanup:
    return slitlength_pixels;
}


/*---------------------------------------------------------------------------*/
/**
  @brief    read the plate id
  @param    raw_header   FITS header
  @return   plate id
 */
/*---------------------------------------------------------------------------*/
int
uves_flames_pfits_get_plateid(const uves_propertylist *raw_header)
{
    int plate_no;
    
    if (uves_propertylist_contains(raw_header,
                  FLAMES_NEWPLATEID))
    {
        check( uves_get_property_value(raw_header, FLAMES_NEWPLATEID, 
                       CPL_TYPE_INT, &plate_no), 
           "Error reading keyword '%s'", FLAMES_NEWPLATEID);
    }
    else if(uves_propertylist_contains(raw_header, 
                      FLAMES_OBS_PLATE_ID))
    {
        check( uves_get_property_value(raw_header, FLAMES_OBS_PLATE_ID, 
                       CPL_TYPE_INT, &plate_no),
           "Error reading keyword '%s'", FLAMES_NEWPLATEID);
    }
    else if (uves_propertylist_contains(raw_header,
                       FLAMES_INS_SHUT09))
    {
        plate_no = 1;
    }
    else if (uves_propertylist_contains(raw_header,
                       FLAMES_INS_SHUT10))
    {
        plate_no = 2;
    }
    else
    {
        plate_no = 0;
        uves_msg_warning("Missing raw header keywords %s, %s, %s and %s, "
                 "setting plate number = %d",
                 FLAMES_NEWPLATEID, 
                 FLAMES_OBS_PLATE_ID,
                 FLAMES_INS_SHUT09,
                 FLAMES_INS_SHUT10,
                 plate_no);
    }
    
  cleanup:
    return plate_no;
}


/*---------------------------------------------------------------------------*/
/**
  @brief    Find out the integration time
  @param    plist       Header to read from
  @return   The requested value, or undefined on error
 */
/*---------------------------------------------------------------------------*/
double 
uves_flames_pfits_get_dit(const uves_propertylist * plist)
{
    double returnvalue = 0;
    
    check( uves_get_property_value(plist, FLAMES_DIT, CPL_TYPE_DOUBLE, &returnvalue), 
       "Error reading keyword '%s'", FLAMES_DIT);
    
  cleanup:
    return returnvalue;
}

/*---------------------------------------------------------------------------*/
/**
  @brief    Write the plate number
  @param    plist        Property list to write to
  @param    plate_no     The value to write
 */
/*---------------------------------------------------------------------------*/
void
uves_flames_pfits_set_newplateid(uves_propertylist * plist, int plate_no)
{
    check( uves_propertylist_update_int(plist, FLAMES_NEWPLATEID, plate_no),
       "Error writing keyword '%s'", FLAMES_NEWPLATEID);
  cleanup:
    return;
}

/**@}*/
