/*
 * 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
 */



/*---------------------------------------------------------------------------*/
/**
   @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 ;
    }

    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 ;
    }

    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 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 ;
    }

    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_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;

}




/**@}*/
