/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004,2005 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <cpl.h>
#include "sinfo_pro_save.h"
#include "sinfo_key_names.h"
#include "sinfo_functions.h"
#include "sinfo_utilities.h" 
#include "sinfo_globals.h" 

static int 
sinfo_pfits_put_qc(
                cpl_propertylist       *   plist,
                cpl_table          *   qclog);

static void
sinfo_log_pro(char* name_o,
              const char* pro_catg, 
              int frm_type, 
              cpl_frameset* ref_set,
              cpl_frameset** out_set, 
              cpl_propertylist** plist,
              cpl_parameterlist* parlist, 
              const char* recid);


static void
sinfo_check_name(const char* in, char** ou, int type, char** paf);

static void
sinfo_clean_header(cpl_propertylist** header);
static void
sinfo_clean_cube_header(cpl_propertylist** header);

/**@{*/
/**
 * @defgroup sinfo_pro_save Functions to save a product
 *
 * TBD
 */

/**
   @name sinfo_update_fits_card_int
   @brief update an integer card in the header of a FITS file
   @param file file name
   @param card card name
   @param value card value
   @return if success 0 ; else -1
 */

int 
sinfo_update_fits_card_int(const char* file,const char* card,int value)
{
    cpl_propertylist *   plist =NULL;
    if ((plist = cpl_propertylist_load(file, 0)) == NULL) {
        sinfo_msg_error( "getting header from file %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }

    if (CPL_ERROR_NONE!=cpl_propertylist_set_int(plist,card,value)){
        sinfo_msg_error( "setting header of file %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }
    cpl_propertylist_delete(plist) ;
    return 0;
}

/**
   @name sinfo_update_fits_card_float
   @brief update a float card in the header of a FITS file
   @param file file name
   @param card card name
   @param value card value
   @return if success 0 ; else -1
 */

int 
sinfo_update_fits_card_float(const char* file,const char* card,float value)
{
    cpl_propertylist *   plist =NULL;
    if ((plist = cpl_propertylist_load(file, 0)) == NULL) {
        sinfo_msg_error( "getting header from file %s",file);
        sinfo_msg_error("%s", (char* ) cpl_error_get_message());
        sinfo_msg_error("%s", (char* ) cpl_error_get_where());
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }

    if (CPL_ERROR_NONE!=cpl_propertylist_set_float(plist,card,value)){
        sinfo_msg_error( "setting header of file %s",file);
        sinfo_msg_error("%s", (char* ) cpl_error_get_message());
        sinfo_msg_error("%s", (char* ) cpl_error_get_where());
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }
    cpl_propertylist_delete(plist) ;
    return 0;
}


/**
   @name sinfo_update_fits_card_double
   @brief update a double card in the header of a FITS file
   @param file file name
   @param card card name
   @param value card value
   @return if success 0 ; else -1
 */

int 
sinfo_update_fits_card_double(const char* file,const char* card,double value)
{
    cpl_propertylist *   plist =NULL;
    if ((plist = cpl_propertylist_load(file, 0)) == NULL) {
        sinfo_msg_error( "getting header from file %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }

    if (CPL_ERROR_NONE!=cpl_propertylist_set_double(plist,card,value)){
        sinfo_msg_error( "gsetting header of file %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }
    cpl_propertylist_delete(plist) ;
    return 0;
}

/**
   @name sinfo_update_fits_card_long
   @brief update a long card in the header of a FITS file
   @param file file name
   @param card card name
   @param value card value
   @return if success 0 ; else -1
 */

int 
sinfo_update_fits_card_long(const char* file,const char* card,long value)
{
    cpl_propertylist *   plist =NULL;
    if ((plist = cpl_propertylist_load(file, 0)) == NULL) {
        sinfo_msg_error( "getting header from file %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }
    if (CPL_ERROR_NONE!=cpl_propertylist_set_long(plist,card,value)){
        sinfo_msg_error( "setting header of file %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }
    cpl_propertylist_delete(plist) ;
    return 0;
}

/**
   @name sinfo_update_fits_card_string
   @brief update a string card in the header of a FITS file
   @param file file name
   @param card card name
   @param value card value
   @return if success 0 ; else -1
 */

int 
sinfo_update_ims_fits_card_string(cpl_imagelist* iml,
                                  const char* file, 
                                  const char* card,
                                  const char* value)
{

    cpl_propertylist *   plist =NULL;
    if ((plist = cpl_propertylist_load(file, 0)) == NULL) {
        sinfo_msg_error( "getting header from reference ima frame %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }


    if (CPL_ERROR_NONE!=cpl_propertylist_set_string(plist,card,value)){
        sinfo_msg_error( "getting header from reference ima frame %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }

    if (cpl_imagelist_save(iml,file,CPL_BPP_IEEE_FLOAT,
                    plist,CPL_IO_DEFAULT)!=CPL_ERROR_NONE) {
        sinfo_msg_error( "getting header from reference ima frame %s",file);
        cpl_propertylist_delete(plist) ;
        return -1 ;
    }
    cpl_propertylist_delete(plist) ;
    return 0;
}
/* Not used 
static int sinfo_save_paf(char* name_p, 
			  const char* rec_id, 
			  cpl_table* qclog,
			  cpl_propertylist*   plist,
			  const char*      pro_catg)
{



  FILE            *   paf ;
  const char            *   sval ;
  char            key_name[FILE_NAME_SZ] ;
  char            key_paf[FILE_NAME_SZ] ;
  char            key_dpaf[FILE_NAME_SZ] ;
  char            key_type[FILE_NAME_SZ] ;
  char            key_value[FILE_NAME_SZ] ;
  double dval=0;

  int i =0;
  int n=0;
  sinfo_msg( "Writing %s" , name_p) ;
  // Create the default PAF header
  if ((paf = sinfo_paf_print_header(name_p,rec_id,"QC file","login-name",
				    sinfo_get_datetime_iso8601())) == NULL) {
    sinfo_msg_error( "cannot open file [%s] for output", name_p) ;
    return -1 ;
  }
  if (sinfo_check_rec_status(0) == -1) {
    sinfo_msg_error( "Something was wrong") ;
    return -1 ;
  }

  // Test entries
  sinfo_blank2dot(PAF_NAME_PIPE_ID,key_dpaf);
  fprintf(paf,"%-21s \"%s\" ;# %s\" \n", key_dpaf,
	  VERSION,KEY_HELP_PIPE_ID);

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

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

  strcpy(key_name,KEY_NAME_PRO_DATANCOM); 
  strcpy(key_paf,PAF_NAME_PRO_DATANCOM); 
  sinfo_blank2dot(key_paf,key_dpaf);
  if (cpl_propertylist_has(plist,key_name)) {
    fprintf(paf,"%-21s %d ;# %s\" \n",key_dpaf,
	    cpl_propertylist_get_int(plist,key_name),KEY_HELP_PRO_DATANCOM);
  }

  strcpy(key_name,KEY_NAME_NCORRS_NAME);
  strcpy(key_paf,PAF_NAME_NCORRS_NAME);
  sinfo_blank2dot(key_paf,key_dpaf);
  if (cpl_propertylist_has(plist, key_name)) {
    fprintf(paf,"%-21s \"%s\" ;# %s \n", key_dpaf,
	    cpl_propertylist_get_string(plist,key_name),KEY_HELP_NCORRS_NAME);
  }

  strcpy(key_name,KEY_NAME_DET_NDSAMPLES);
  strcpy(key_paf,PAF_NAME_DET_NDSAMPLES);
  sinfo_blank2dot(key_paf,key_dpaf);        
  if (cpl_propertylist_has(plist, key_name)) {
    fprintf(paf,"%-21s %d ;# %s \n",key_dpaf, 
	    cpl_propertylist_get_int(plist,key_name),KEY_HELP_DET_NDSAMPLES);
  }

  strcpy(key_name,KEY_NAME_FILT_NAME);      
  strcpy(key_paf,PAF_NAME_FILT_NAME);      
  sinfo_blank2dot(key_paf,key_dpaf);        
  if (cpl_propertylist_has(plist, key_name)) {
    fprintf(paf,"%-21s \"%s\" ;# %s \n", key_dpaf,
	    cpl_propertylist_get_string(plist,key_name),KEY_HELP_FILT_NAME);
  }

  strcpy(key_name,KEY_NAME_FILT_ID);        
  strcpy(key_paf,PAF_NAME_FILT_ID);        
  sinfo_blank2dot(key_paf,key_dpaf);        
  if (cpl_propertylist_has(plist, key_name)) {
    fprintf(paf,"%-21s \"%s\" ;# %s \n",key_dpaf, 
	    cpl_propertylist_get_string(plist,key_name),KEY_HELP_FILT_ID);
  }

  strcpy(key_name,KEY_NAME_PREOPTICS);        
  strcpy(key_paf,PAF_NAME_PREOPTICS);        
  sinfo_blank2dot(key_paf,key_dpaf);        
  if (cpl_propertylist_has(plist, key_name)) {
    fprintf(paf,"%-21s \"%s\" ;# %s \n",key_dpaf, 
	    cpl_propertylist_get_string(plist,key_name),KEY_HELP_PREOPTICS);
  }

  strcpy(key_name,KEY_NAME_GRAT_NAME);        
  strcpy(key_paf,PAF_NAME_GRAT_NAME);        
  sinfo_blank2dot(key_paf,key_dpaf);        
  if (cpl_propertylist_has(plist, key_name)) {
    fprintf(paf, "%-21s \"%s\" ;# %s \n",key_dpaf, 
	    cpl_propertylist_get_string(plist,key_name),KEY_HELP_GRAT_NAME);
  }

  strcpy(key_name,KEY_NAME_GRAT_WLEN);        
  strcpy(key_paf,PAF_NAME_GRAT_WLEN);        
  sinfo_blank2dot(key_paf,key_dpaf);        
  if (cpl_propertylist_has(plist, key_name)) {
    fprintf(paf, "%-21s %f ;# %s \n", key_dpaf,
	    cpl_propertylist_get_double(plist,key_name),KEY_HELP_GRAT_WLEN);
  }

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


  // snprintf(cval, MAX_NAME_SIZE-1,"CPL-%s", get_cpl_version());
  strcpy(key_name,KEY_NAME_PRO_DRSID); 
  strcpy(key_paf,PAF_NAME_PRO_DRSID); 
  sinfo_blank2dot(key_paf,key_dpaf);        
  if (cpl_propertylist_has(plist, key_name)) {
    fprintf(paf,"%-21s \"%s\" ;# %s \n",key_dpaf, 
	    cpl_propertylist_get_string(plist,key_name),KEY_HELP_PRO_DRSID);
  }

  if (cpl_propertylist_has(plist,KEY_NAME_DATE_OBS)) {
    sval = sinfo_pfits_get_date_obs(plist);
    strcpy(key_paf,KEY_NAME_DATE_OBS); 
    sinfo_blank2dot(key_paf,key_dpaf);        
    fprintf(paf, "%-21s \"%s\" ;# %s\n",key_dpaf, 
	    sval,KEY_HELP_DATE_OBS) ;
  }


  if (cpl_propertylist_has(plist,KEY_NAME_TEL_AIRM_START)) {
    dval = sinfo_pfits_get_airmass_start(plist);
    strcpy(key_paf,PAF_NAME_TEL_AIRM_START); 
    sinfo_blank2dot(key_paf,key_dpaf);        
    fprintf(paf, "%-21s \"%f\" ;# %s \n",key_dpaf, 
	    dval,KEY_HELP_TEL_AIRM_START) ;
  }

  if (cpl_propertylist_has(plist,KEY_NAME_ARCFILE)) {
    sval = sinfo_pfits_get_arcfile(plist);
    strcpy(key_paf,KEY_NAME_ARCFILE);
    sinfo_blank2dot(key_paf,key_dpaf);      
    fprintf(paf, "%-21s \"%s\" ;# %s \n", key_dpaf,sval,KEY_HELP_ARCFILE) ;

  } else if (cpl_propertylist_has(plist,KEY_NAME_PRO_REC1_RAW1_NAME)) {
    sval = sinfo_pfits_get_rec1raw1name(plist);
    strcpy(key_paf,KEY_NAME_ARCFILE);
    sinfo_blank2dot(key_paf,key_dpaf);       
    fprintf(paf, "%-21s \"%s\" ;# %s \n", key_dpaf,sval,KEY_HELP_ARCFILE) ;
  } else {
    sinfo_msg_error("%s is missing QC LOG will fail!",KEY_NAME_ARCFILE);
  }

  if (cpl_propertylist_has(plist,KEY_NAME_TPL_ID)) {
    sval = sinfo_pfits_get_templateid(plist);
    strcpy(key_paf,PAF_NAME_TPL_ID);
    sinfo_blank2dot(key_paf,key_dpaf);       
    fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
	    sval,KEY_HELP_TPL_ID) ;

  }

  if (cpl_propertylist_has(plist,KEY_NAME_DET_DIT)) { 
    strcpy(key_paf,PAF_NAME_DET_DIT); 
    sinfo_blank2dot(key_paf,key_dpaf);        
    fprintf(paf,"%-21s %f ; # %s\n", key_dpaf,
	    sinfo_pfits_get_dit(plist),KEY_HELP_DET_DIT) ;
  }


  if (cpl_propertylist_has(plist,KEY_NAME_DET_NDIT)) {
    strcpy(key_paf,PAF_NAME_DET_NDIT); 
    sinfo_blank2dot(key_paf,key_dpaf); 
    fprintf(paf,"%-21s %d ; # %s\n", key_dpaf,
	    sinfo_pfits_get_ndit(plist),KEY_HELP_DET_NDIT) ;
  }

  if (cpl_propertylist_has(plist,KEY_NAME_NCORRS_NAME)) {
    sval = sinfo_pfits_get_ncorrs_name(plist);
    strcpy(key_paf,PAF_NAME_NCORRS_NAME); 
    sinfo_blank2dot(key_paf,key_dpaf);        

    fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
	    sval, KEY_HELP_NCORRS_NAME) ;
  }

  if (cpl_propertylist_has(plist,KEY_NAME_DPR_TYPE)) {
    sval = sinfo_pfits_get_dpr_type(plist);
    strcpy(key_paf,PAF_NAME_DPR_TYPE); 
    sinfo_blank2dot(key_paf,key_dpaf);        
    fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
	    sval, KEY_HELP_DPR_TYPE) ;
  }

  if (cpl_propertylist_has(plist,KEY_NAME_DPR_TECH)) {
    sval = sinfo_pfits_get_dpr_tech(plist);
    strcpy(key_paf,PAF_NAME_DPR_TECH); 
    sinfo_blank2dot(key_paf,key_dpaf);   
    fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
	    sval, KEY_HELP_DPR_TECH) ;
  }


  if (cpl_propertylist_has(plist,KEY_NAME_DPR_CATG)) {
    sval = sinfo_pfits_get_dpr_catg(plist);
    strcpy(key_paf,PAF_NAME_DPR_CATG); 
    sinfo_blank2dot(key_paf,key_dpaf); 
    fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
	    sval, KEY_HELP_DPR_CATG) ;
  }

  strcpy(key_paf,PAF_NAME_PRO_CATG); 
  sinfo_blank2dot(key_paf,key_dpaf); 
  fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
	  pro_catg, KEY_HELP_PRO_CATG) ;

  if (cpl_propertylist_has(plist,KEY_NAME_INS_SETUP)) {
    sval = sinfo_pfits_get_ins_setup(plist);
    strcpy(key_paf,PAF_NAME_INS_SETUP); 
    sinfo_blank2dot(key_paf,key_dpaf); 
    fprintf(paf, "%-21s \"%s\" ; # %s\n", key_dpaf,
	    sval, KEY_HELP_INS_SETUP) ;
  }

  n=cpl_table_get_nrow(qclog);
  for(i=0;i<n;i++) {
    strcpy(key_paf,cpl_table_get_string(qclog,"key_name",i));
    sinfo_blank2dot(key_paf,key_name);
    strcpy(key_type,cpl_table_get_string(qclog,"key_type",i));
    strcpy(key_value,cpl_table_get_string(qclog,"key_value",i));
    if(strcmp(key_type,"CPL_TYPE_STRING") == 0) {
      strcat(key_name,"               \"%s\"\n");
      fprintf(paf, key_name, key_value) ;
    } else if(strcmp(key_type,"CPL_TYPE_BOOL") == 0) {
      strcat(key_name,"               ");
      strcat(key_name,"%c\n");
      fprintf(paf, key_name, atoi(key_value)) ;
    } else if(strcmp(key_type,"CPL_TYPE_INT") == 0) {
      strcat(key_name,"               ");
      strcat(key_name,"%d\n");
      fprintf(paf, key_name, atoi(key_value)) ;
    } else if(strcmp(key_type,"CPL_TYPE_FLOAT") == 0) {
      strcat(key_name,"               ");
      strcat(key_name,"%g\n");
      fprintf(paf, key_name, (float) atof(key_value)) ;
    } else if(strcmp(key_type,"CPL_TYPE_DOUBLE") == 0) {
      strcat(key_name,"               ");
      strcat(key_name,"%g\n");
      fprintf(paf, key_name, atof(key_value)) ;
    }

  }
  fprintf(paf, "\n");
  fclose(paf) ;

  if (sinfo_check_rec_status(1) == -1) {
    sinfo_msg_error( "Something was wrong reading FITS keys") ;
    return -1 ;
  }
  return 0;

}

 */

/*---------------------------------------------------------------------------*/
/**
   @brief    Save the image product on disk
   @param    ima      the input imagelist 
   @param    ref      the reference frame set 
   @param    set      the output frame set
   @param    out_file the output file name
   @param    pro_catg the frame product category
   @param    qclog    the table to store quality control parameters
   @param    recid    the recipe id
   @param    parlist  the recipe parameter list
   @return   0 if everything is ok, -1 otherwise
 */
/*---------------------------------------------------------------------------*/


int sinfo_pro_save_ima(
                cpl_image       *   ima,
                cpl_frameset    *   ref,
                cpl_frameset    *   set,
                const char      *   out_file,
                const char      *   pro_catg,
                cpl_table       *   qclog,
                const char      *   recid,
                cpl_parameterlist* parlist)

{
    char      *         name_o ;
    char      *         name_p ;

    cpl_propertylist *   plist =NULL;
    //cpl_frame       *   first_frame=NULL;
    char            *   ref_file=NULL;

    /* Get the reference file  */
    cpl_frameset_iterator* it = cpl_frameset_iterator_new(ref);
    cpl_frame *first_frame = cpl_frameset_iterator_get(it);

    ref_file = (char*) cpl_strdup(cpl_frame_get_filename(first_frame)) ;

    name_o = cpl_malloc(FILE_NAME_SZ * sizeof(char));
    name_p = cpl_malloc(FILE_NAME_SZ * sizeof(char));
    sinfo_check_name(out_file, &name_o, CPL_FRAME_TYPE_IMAGE, &name_p);
    sinfo_msg( "Writing ima %s pro catg %s" , name_o, pro_catg) ;

    /* Get FITS header from reference file */
    if ((cpl_error_code)((plist=cpl_propertylist_load(ref_file, 0)) == NULL)) {
        sinfo_msg_error( "getting header from reference ima frame %s",ref_file);
        cpl_propertylist_delete(plist) ;
        cpl_free(ref_file);
        cpl_frameset_iterator_delete(it);
        return -1 ;
    }

    sinfo_clean_header(&plist);
    if ( ( strstr(pro_catg,"MASTER_PSF") != NULL ) ||
                    ( strstr(pro_catg,"STD_STAR_SPECTRUM") != NULL ) ||
                    ( strstr(pro_catg,"STD_STAR_SPECTRA") != NULL ) ) {
        sinfo_clean_cube_header(&plist);
    }

    /* Add DataFlow keywords and log the saved file in the input frameset */
    sinfo_log_pro(name_o, pro_catg, CPL_FRAME_TYPE_IMAGE,
                  ref,&set,&plist,parlist,recid);
    if(qclog != NULL) {
        sinfo_pfits_put_qc(plist, qclog) ;
    }

    /* Save the file */
    if (cpl_image_save(ima, name_o, CPL_BPP_IEEE_FLOAT,
                    plist,CPL_IO_DEFAULT)!=CPL_ERROR_NONE) {
        sinfo_msg_error( "Cannot save the product %s",name_o);
        cpl_propertylist_delete(plist) ;
        cpl_free(ref_file);
        cpl_free(name_o);
        cpl_free(name_p);
        cpl_frameset_iterator_delete(it);
        return -1 ;
    }

    /* THE PAF FILE FOR QC PARAMETERS
     if( qclog != NULL) {
     sinfo_save_paf(name_p,recid,qclog,plist,pro_catg);  
     }
     */

    cpl_propertylist_delete(plist) ;
    cpl_msg_indent_less() ;
    cpl_free(name_o);
    cpl_free(name_p);
    cpl_free(ref_file);
    cpl_frameset_iterator_delete(it);

    return 0 ;
}


/*---------------------------------------------------------------------------*/
/**
   @brief    Save the table products on disk
   @param    table    the input table 
   @param    ref      the reference frame set 
   @param    set      the output frame set
   @param    out_file the output file name
   @param    pro_catg the frame product category
   @param    qclog    the table to store quality control parameters
   @param    recid    the recipe id
   @param    parlist  the recipe parameter list
   @return   0 if everything is ok, -1 otherwise
 */
/*---------------------------------------------------------------------------*/



int sinfo_pro_save_tbl(
                cpl_table       *   table,
                cpl_frameset    *   ref,
                cpl_frameset    *   set,
                const char      *   out_file,
                const char      *   pro_catg,
                cpl_table       *   qclog,
                const char      *   recid,
                cpl_parameterlist* parlist)

{
    char *    name_o =NULL;
    char *    name_p =NULL;
    cpl_propertylist *   plist=NULL ;
    char* ref_file=NULL;
    /* Get the reference file  */

    cpl_frameset_iterator* it = cpl_frameset_iterator_new(ref);
    cpl_frame *first_frame = cpl_frameset_iterator_get(it);
    ref_file = cpl_strdup(cpl_frame_get_filename(first_frame)) ;

    name_o = cpl_malloc(FILE_NAME_SZ * sizeof(char));
    name_p = cpl_malloc(FILE_NAME_SZ * sizeof(char));
    sinfo_check_name(out_file, &name_o, CPL_FRAME_TYPE_TABLE, &name_p);
    sinfo_msg( "Writing tbl %s pro catg %s" , name_o, pro_catg) ;

    /* Get FITS header from reference file */
    if ((cpl_error_code)((plist = cpl_propertylist_load(ref_file,0)) == NULL))
    {
        sinfo_msg_error( "getting header from tbl frame %s",ref_file);
        cpl_propertylist_delete(plist) ;
        cpl_free(ref_file);
        cpl_free(name_o);
        cpl_free(name_p);
        cpl_frameset_iterator_delete(it);
        return -1 ;
    }
    sinfo_clean_header(&plist);

    /* Add DataFlow keywords and log the saved file in the input frameset */
    sinfo_log_pro(name_o, pro_catg, CPL_FRAME_TYPE_TABLE,
                  ref,&set,&plist,parlist,recid);
    if(qclog != NULL) {
        sinfo_pfits_put_qc(plist, qclog) ;
    }
    /* Save the file */
    if (cpl_table_save(table, plist, NULL, name_o, CPL_IO_DEFAULT)
                    != CPL_ERROR_NONE) {
        sinfo_msg_error( "Cannot save the product: %s", name_o);
        cpl_propertylist_delete(plist) ;
        cpl_free(ref_file);
        cpl_free(name_o);
        cpl_free(name_p);
        cpl_frameset_iterator_delete(it);
        return -1 ;
    }


    /* THE PAF FILE FOR QC PARAMETERS
     if (qclog != NULL) {
     sinfo_save_paf(name_p,recid,qclog,plist,pro_catg);
     }
     */
    cpl_propertylist_delete(plist) ;
    cpl_msg_indent_less() ;
    cpl_free(name_o);
    cpl_free(name_p);
    cpl_free(ref_file);
    cpl_frameset_iterator_delete(it);
    return 0 ;
}



/*---------------------------------------------------------------------------*/
/**
   @brief    Save the imagelist product on disk
   @param    ims      the input imagelist 
   @param    ref      the reference frame set 
   @param    set      the output frame set
   @param    out_file the output file name
   @param    pro_catg the frame product category
   @param    qclog    the table to store quality control parameters
   @param    recid    the recipe id
   @param    parlist  the recipe parameter list
   @return   0 if everything is ok, -1 otherwise
 */
/*---------------------------------------------------------------------------*/



int sinfo_pro_save_ims(
                cpl_imagelist   *   ims,
                cpl_frameset    *   ref,
                cpl_frameset    *   set,
                const char      *   out_file,
                const char      *   pro_catg,
                cpl_table       *   qclog,
                const char      *   recid,
                cpl_parameterlist* parlist)

{
    char *               name_o=NULL;
    char *               name_p=NULL;

    cpl_propertylist * plist=NULL ;
    char* ref_file=NULL;

    /* Get the reference file  */
    cpl_frameset_iterator* it = cpl_frameset_iterator_new(ref);
    cpl_frame *first_frame = cpl_frameset_iterator_get(it);

    ref_file = cpl_strdup(cpl_frame_get_filename(first_frame)) ;

    name_o = cpl_malloc(FILE_NAME_SZ * sizeof(char));
    name_p = cpl_malloc(FILE_NAME_SZ * sizeof(char));
    sinfo_check_name(out_file, &name_o, CPL_FRAME_TYPE_IMAGE, &name_p);
    sinfo_msg( "Writing ims %s pro catg %s" , name_o, pro_catg) ;
    /* Get FITS header from reference file */
    if ((cpl_error_code)((plist = cpl_propertylist_load(ref_file, 0)) == NULL))
    {
        sinfo_msg_error( "getting header from ims frame %s",ref_file);
        cpl_propertylist_delete(plist) ;
        cpl_free(ref_file);
        cpl_free(name_o);
        cpl_free(name_p);
        cpl_frameset_iterator_delete(it);
        return -1 ;
    }
    sinfo_clean_header(&plist);
    if ( ( strstr(pro_catg,"STD") != NULL ) ||
                    ( strstr(pro_catg,"PSF") != NULL ) ||
                    ( strstr(pro_catg,"OBJ") != NULL ) ) {
        sinfo_clean_cube_header(&plist);
    }

    /* Add DataFlow keywords and log the saved file in the input frameset */
    sinfo_log_pro(name_o, pro_catg, CPL_FRAME_TYPE_IMAGE,
                  ref,&set,&plist,parlist,recid);

    if(qclog != NULL) {
        sinfo_pfits_put_qc(plist, qclog) ;
    }


    /* Save the file */
    if (cpl_imagelist_save(ims, name_o, CPL_BPP_IEEE_FLOAT,
                    plist,CPL_IO_DEFAULT)!=CPL_ERROR_NONE) {
        sinfo_msg_error( "Cannot save the product %s",name_o);
        cpl_propertylist_delete(plist) ;
        cpl_free(ref_file);
        cpl_free(name_o);
        cpl_free(name_p);
        cpl_frameset_iterator_delete(it);
        return -1 ;
    }

    /* THE PAF FILE FOR QC PARAMETERS
     if (qclog != NULL) {
     sinfo_save_paf(name_p,recid,qclog,plist,pro_catg);
     }
     */
    cpl_propertylist_delete(plist) ;
    cpl_msg_indent_less() ;
    cpl_free(name_o);
    cpl_free(name_p);
    cpl_free(ref_file);
    cpl_frameset_iterator_delete(it);
    return 0 ;
}



static void
sinfo_log_pro(char* name_o, 
              const char* pro_catg, 
              int frm_type, 
              cpl_frameset* ref_set,
              cpl_frameset** out_set,
              cpl_propertylist** plist,
              cpl_parameterlist* parlist, 
              const char* recid)
{
    cpl_frame* product_frame = NULL ;
    char * pipe_id=NULL;
    cpl_errorstate initial_errorstate = cpl_errorstate_get();

    pipe_id = cpl_calloc(FILE_NAME_SZ,sizeof(char));
    snprintf(pipe_id,MAX_NAME_SIZE-1,"%s%s","sinfo/",PACKAGE_VERSION);
    product_frame = cpl_frame_new() ;
    cpl_frame_set_filename(product_frame, name_o) ;
    cpl_frame_set_tag(product_frame, pro_catg) ;
    cpl_frame_set_type(product_frame, frm_type);
    cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
    cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);

#if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0) 
    if(cpl_dfs_setup_product_header(*plist,product_frame,ref_set,parlist,recid,
                    pipe_id,KEY_VALUE_HPRO_DID,NULL) != CPL_ERROR_NONE) {
        sinfo_msg_warning("Problem in the product DFS-compliance");
        sinfo_msg_warning("%s", (char* ) cpl_error_get_message());
        cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
        cpl_error_reset();
    }
#else
    if(cpl_dfs_setup_product_header(*plist,product_frame,ref_set,parlist,recid,
                    pipe_id,KEY_VALUE_HPRO_DID) != CPL_ERROR_NONE) {
        sinfo_msg_warning("Problem in the product DFS-compliance");
        sinfo_msg_warning((char* ) cpl_error_get_message());
        cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
        cpl_error_reset();
    }
#endif
    cpl_frameset_insert(*out_set, product_frame);
    cpl_free(pipe_id);

}

static void
sinfo_check_name(const char* in, char** ou, int type, char** paf) {

    char  name_b[512] ;
    if (strstr(in, "." ) != NULL ) {
        char* tmp = sinfo_new_get_rootname(in);
        strcpy(name_b,tmp);
    } else {
        snprintf(name_b, MAX_NAME_SIZE-1,"%s", in) ;
    }
    strcpy(*ou,name_b);
    if (type == CPL_FRAME_TYPE_TABLE) {
        strcat(*ou,".fits");
    } else {
        strcat(*ou,".fits");
    }
    strcpy(*paf,name_b);
    strcat(*paf,".paf");

}


static void
sinfo_clean_header(cpl_propertylist** header)
{
    cpl_propertylist_erase_regexp(*header, "CHECKSUM",0);
    cpl_propertylist_erase_regexp(*header, "^ESO PRO .*",0);

}


static void
sinfo_clean_cube_header(cpl_propertylist** header)
{

    cpl_propertylist_erase_regexp(*header, "^CRVAL*",0);
    cpl_propertylist_erase_regexp(*header, "^CRPIX*",0);
    cpl_propertylist_erase_regexp(*header, "^CTYPE*",0);
    cpl_propertylist_erase_regexp(*header, "^CUNIT*",0);
    cpl_propertylist_erase_regexp(*header, "^CD1_1",0);
    cpl_propertylist_erase_regexp(*header, "^CD1_2",0);
    cpl_propertylist_erase_regexp(*header, "^CD2_1",0);
    cpl_propertylist_erase_regexp(*header, "^CD2_2",0);

}






static int 
sinfo_pfits_put_qc(
                cpl_propertylist       *   plist,
                cpl_table          *   qclog)
{
    char            key_name[FILE_NAME_SZ];
    char            key_value[FILE_NAME_SZ];
    char            key_type[FILE_NAME_SZ];
    char            key_help[FILE_NAME_SZ] ;

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

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

        /* sinfo_msg("name=%s type=%s value=%s\n",key_name,key_type,key_value); */
        if(!cpl_propertylist_has(plist,key_name)) {
            if(strcmp(key_type,"CPL_TYPE_STRING") == 0) {
                cpl_propertylist_append_string(plist, key_name,key_value) ;
                cpl_propertylist_set_comment(plist, key_name,key_help) ;
            } else if(strcmp(key_type,"CPL_TYPE_BOOL") == 0) {
                cpl_propertylist_append_bool(plist, key_name,atoi(key_value)) ;
                cpl_propertylist_set_comment(plist, key_name,key_help) ;
            } else if(strcmp(key_type,"CPL_TYPE_INT") == 0) {
                cpl_propertylist_append_int(plist,key_name,atoi(key_value)) ;
                cpl_propertylist_set_comment(plist, key_name,key_help) ;
            } else if(strcmp(key_type,"CPL_TYPE_FLOAT") == 0) {
                cpl_propertylist_append_float(plist, key_name,(float)atof(key_value)) ;
                cpl_propertylist_set_comment(plist, key_name,key_help) ;
            } else if(strcmp(key_type,"CPL_TYPE_DOUBLE") == 0) {
                cpl_propertylist_append_double(plist, key_name,atof(key_value)) ;
                cpl_propertylist_set_comment(plist, key_name,key_help) ;
            }
        }

    }

    return 0 ;
}







cpl_table *
sinfo_qclog_init(void)
{

    cpl_table *table;

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

    return table;
}





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

    snprintf(key_value,MAX_NAME_SIZE-1,format,value);
    strcpy(key_type,"CPL_TYPE_INT");

    cpl_table_set_size(table,sz+1);

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

    return 0;

}



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

    snprintf(key_value,MAX_NAME_SIZE-1,format,value);
    strcpy(key_type,"CPL_TYPE_BOOL");

    cpl_table_set_size(table,sz+1);

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

    return 0;

}



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

    snprintf(key_value,MAX_NAME_SIZE-1,format,value);
    strcpy(key_type,"CPL_TYPE_FLOAT");

    cpl_table_set_size(table,sz+1);

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

    return 0;

}



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

    snprintf(key_value,MAX_NAME_SIZE-1,format,value);
    strcpy(key_type,"CPL_TYPE_DOUBLE");

    cpl_table_set_size(table,sz+1);

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

    return 0;

}

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

    snprintf(key_value,MAX_NAME_SIZE-1,format,value);
    strcpy(key_type,"CPL_TYPE_STRING");

    cpl_table_set_size(table,sz+1);

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

    return 0;

}




/**@}*/
