/* $Id: sinfo_utl_cube2spectrum.c,v 1.11 2012-03-03 10:17:31 amodigli Exp $
 *
 * This file is part of the IIINSTRUMENT Pipeline
 * Copyright (C) 2002,2003 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * $Author: amodigli $
 * $Date: 2012-03-03 10:17:31 $
 * $Revision: 1.11 $
 * $Name: not supported by cvs2svn $
 */

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

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


#include "sinfo_utl_cube2spectrum.h"
#include "sinfo_functions.h"
#include "sinfo_spectrum_ops.h"
#include "sinfo_key_names.h"
#include "sinfo_pro_save.h"
#include "sinfo_utilities_scired.h"
#include "sinfo_globals.h"
#include "sinfo_error.h"
#include "sinfo_utils_wrappers.h"
/*----------------------------------------------------------------------------
                            Functions prototypes
 ----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                            Static variables
 ----------------------------------------------------------------------------*/

static int
sinfo_change_header(const char * name);
/**@{*/
/**
 * @addtogroup sinfo_utl_cube2spectrum Cube to spectrum trasformation
 *
 * TBD
 */

/*-----------------------------------------------------------------------------
                            Function implementation
 ----------------------------------------------------------------------------*/

static int
sinfo_change_header(const char * name) {
    int cenpix=0;
    double cenLambda=0;
    double dispersion=0;
    cpl_propertylist* plist=NULL;

    plist=cpl_propertylist_load(name,0);
    cenpix = sinfo_pfits_get_crpix3(plist);
    cenLambda = sinfo_pfits_get_crval3(plist);
    dispersion = sinfo_pfits_get_cdelt3(plist);


    check(cpl_propertylist_set_string(plist,"CTYPE2","WAVE"),"Setting CTYPE2");
    check_nomsg(cpl_propertylist_set_comment(plist,"CTYPE2",
                    "wavelength axis in microns"));

    check(cpl_propertylist_set_double(plist,"CRPIX2",(double)cenpix),
          "Setting CRPIX2");
    check_nomsg(cpl_propertylist_set_comment(plist,"CRPIX2","Reference pixel"));

    check(cpl_propertylist_set_double(plist,"CRVAL2",cenLambda),
          "Setting CRVAL2");
    check_nomsg(cpl_propertylist_set_comment(plist,"CRVAL2",
                    "central wavelength"));

    check(cpl_propertylist_set_double(plist,"CDELT2",dispersion),
          "Setting CDELT2");
    check_nomsg(cpl_propertylist_set_comment(plist,"CDELT2",
                    "microns per pixel"));

    check(cpl_propertylist_set_string(plist,"CUNIT2","um"),"Setting CUNIT2");
    check_nomsg(cpl_propertylist_set_comment(plist,"CUNIT2","spectral unit"));

    check(cpl_propertylist_set_string(plist,"CTYPE1","ONESPEC"),
          "Setting CTYPE1");
    check_nomsg(cpl_propertylist_set_comment(plist,"CTYPE1",
                    "one spectrum in y-direction"));

    if(cpl_propertylist_has(plist,"CRPIX1")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CRPIX1",0),"Erasing CRPIX1");
    }

    if(cpl_propertylist_has(plist,"CRVAL1")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CRVAL1",0),"Erasing CRVAL1");
    }

    if(cpl_propertylist_has(plist,"CDELT1")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CDELT1",0),"Erasing CDELT1");
    }


    if(cpl_propertylist_has(plist,"CUNIT1")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CUNIT1",0),"Erasing CUNIT1");
    }


    if(cpl_propertylist_has(plist,"CTYPE3")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CTYPE3",0),"Erasing CTYPE3");
    }


    if(cpl_propertylist_has(plist,"CRPIX3")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CRPIX3",0),"Erasing CRPIX3");
    }

    if(cpl_propertylist_has(plist,"CRVAL3")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CRVAL3",0),"Erasing CRVAL3");
    }

    if(cpl_propertylist_has(plist,"CDELT3")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CDELT3",0),"Erasing CDELT3");
    }

    if(cpl_propertylist_has(plist,"CUNIT3")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CUNIT3",0),"Erasing CUNIT3");
    }


    if(cpl_propertylist_has(plist,"CD1_1")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CD1_1",0),"Erasing CD1_1");
    }


    if(cpl_propertylist_has(plist,"CD1_2")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CD1_2",0),"Erasing CD1_2");
    }

    if(cpl_propertylist_has(plist,"CD2_1")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CD2_1",0),"Erasing CD2_1");
    }

    if(cpl_propertylist_has(plist,"CD2_2")==1) {
        check(cpl_propertylist_erase_regexp(plist, "CD2_2",0),"Erasing CD2_2");
    }

    cleanup:
    sinfo_free_propertylist(&plist);

    /* Return */
    if (cpl_error_get_code()) 
        return -1 ;
    else 
        return 0 ;

}

/*---------------------------------------------------------------------------*/
/**
  @brief    Get the command line options and execute the data reduction
  @param    parlist     the parameters list
  @param    framelist   the frames list
  @param    tag         frame tag
  @return   0 if everything is ok
 */
/*---------------------------------------------------------------------------*/
int sinfo_utl_cube2spectrum(
                cpl_parameterlist   *   parlist,
                cpl_frameset        *   framelist,
                const char* tag)
{
    cpl_parameter       *   param =NULL;
    const char          *   operation =NULL;
    const char          *   aperture =NULL;
    char  name_i [MAX_NAME_SIZE];
    int                    llx=0;
    int                    urx=0;
    int                    lly=0;
    int                    ury=0;
    int                    lo_rej=0;
    int                    hi_rej=0;
    int                    centerx=0;
    int                    centery=0;
    int                    radius=0;
    int                    clx=0;
    int                    cly=0;

    double                 disp=0;
    double                 cpix=0;
    double                 clam=0;

    cpl_frame           *   frm_cub=NULL;

    char ima_o[MAX_NAME_SIZE];
    char tbl_o[MAX_NAME_SIZE];
    char tag_i[MAX_NAME_SIZE];
    char tag_o[MAX_NAME_SIZE];
    cpl_propertylist    *   plist =NULL;
    cpl_image           *   image =NULL;
    cpl_frame           *   product_frame=NULL;

    cpl_image * im_spec=NULL;
    cpl_table * tbl_spec=NULL;
    cpl_image * img=NULL;
    cpl_imagelist  * cube=NULL;
    Vector * spec=NULL;
    /*fits_header* head=NULL; */

    /* HOW TO RETRIEVE INPUT PARAMETERS */
    /* --stropt */
    check_nomsg(param=cpl_parameterlist_find(parlist, 
                    "sinfoni.sinfo_utl_cube2spectrum.op"));
    check_nomsg(operation=cpl_parameter_get_string(param));

    /* --stropt */
    check_nomsg(param=cpl_parameterlist_find(parlist, 
                    "sinfoni.sinfo_utl_cube2spectrum.ap"));
    check_nomsg(aperture=cpl_parameter_get_string(param));
    /* --stropt */


    if (tag == NULL) {
        strcpy(ima_o,"out_spec_ima.fits");
        strcpy(tbl_o,"out_spec_tbl.fits");
        strcpy(tag_i,SI_UTL_CUBE2SPECTRUM_CUBE);
        strcpy(tag_o,SI_UTL_CUBE2SPECTRUM_PROIMA);
    } else {
        snprintf(ima_o,MAX_NAME_SIZE-1,"%s%s",tag,"_spec_ima.fits");
        snprintf(tbl_o,MAX_NAME_SIZE-1,"%s%s",tag,"_spec_tbl.fits");
        snprintf(tag_o,MAX_NAME_SIZE-1,"%s%s",tag,"_SPCT");
        strcpy(tag_i,  tag);
    }


    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.llx"));
    check_nomsg(llx=cpl_parameter_get_int(param));

    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.lly"));
    check_nomsg(lly=cpl_parameter_get_int(param));

    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.urx"));
    check_nomsg(urx=cpl_parameter_get_int(param));

    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.ury"));
    check_nomsg(ury=cpl_parameter_get_int(param));

    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.lo_rej"));
    check_nomsg(lo_rej=cpl_parameter_get_int(param));

    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.hi_rej"));
    check_nomsg(hi_rej=cpl_parameter_get_int(param));

    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.centerx"));
    check_nomsg(centerx=cpl_parameter_get_int(param));

    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.centery"));
    check_nomsg(centery=cpl_parameter_get_int(param));

    /* --intopt */
    check_nomsg(param=cpl_parameterlist_find(parlist,
                    "sinfoni.sinfo_utl_cube2spectrum.radius"));
    check_nomsg(radius=cpl_parameter_get_int(param));

    /* Identify the RAW and CALIB frames in the input frameset */
    if (sinfo_dfs_set_groups(framelist)) {
        sinfo_msg_error( "Cannot identify RAW and CALIB frames") ;
        goto cleanup;
    }

    /* HOW TO ACCESS INPUT DATA */
    cknull(frm_cub=cpl_frameset_find(framelist,tag_i),
           "SOF does not have a file tagged as %s",tag_i);

    /* Now performing the data reduction */
    /* Let's generate one image for the example */
    check_nomsg(strcpy(name_i,cpl_frame_get_filename(frm_cub)));
    check_nomsg(cube = cpl_imagelist_load((char*)name_i,CPL_TYPE_FLOAT,0));

    check_nomsg(img=cpl_imagelist_get(cube,0));
    check_nomsg(clx=cpl_image_get_size_x(img));
    check_nomsg(cly=cpl_image_get_size_y(img));
    check(plist=cpl_propertylist_load(name_i,0),
          "Cannot read the FITS header") ;

    cpix = (double) sinfo_pfits_get_crpix3(plist);
    clam = (double) sinfo_pfits_get_crval3(plist);
    disp = (double) sinfo_pfits_get_cdelt3(plist);
    sinfo_free_propertylist(&plist);
    if(strcmp(aperture,"rectangle") ==0) {
        if (llx<0) {
            sinfo_msg_warning("llx=%d too low set it to 0",llx);
            llx=0;
        }
        if (lly<0) {
            sinfo_msg_warning("lly=%d too low set it to 0",lly);
            lly=0;
        }
        if (urx>clx-1) {
            sinfo_msg_warning("urx=%d too large set it to %d",urx,clx-1);
            urx=clx-1;
        }
        if (ury>cly-1) {
            sinfo_msg_warning("ury=%d too large set it to %d",ury,cly-1);
            ury=cly-1;
        }
        if(llx>=urx) {
            sinfo_msg_error("llx>=urx!");
            goto cleanup;
        }
        if(lly>=ury) {
            sinfo_msg_error("lly>=ury!");
            goto cleanup;
        }

    } 

    if(strcmp(aperture,"circle") ==0) {
        if((centerx-radius) < 0) {
            sinfo_msg_error("It is not possible to set centerx-radius<0.");
            goto cleanup;
        }

        if((centery-radius) < 0) {
            sinfo_msg_error("It is not possible to set centery-radius<0.");
            goto cleanup;
        }

        if((centerx+radius) >= clx) {
            sinfo_msg_error("It is not possible to set centerx+radius >= cube x sixe");
            goto cleanup;
        }

        if((centery+radius) >= cly) {
            sinfo_msg_error("It is not possible to set centery+radius >= cube y size.");
            goto cleanup;
        }

        if((radius) < 0) {
            sinfo_msg_error("It is not possible to set radius<0.");
            goto cleanup;
        }

    }

    if(strcmp(operation,"average") ==0) {
        if (strcmp(aperture,"rectangle") ==0) {
            spec = sinfo_new_mean_rectangle_of_cube_spectra(cube,llx,lly,urx,ury);
        } else if (strcmp(aperture,"circle")==0) {
            spec = sinfo_new_mean_circle_of_cube_spectra(cube,centerx,
                            centery,radius);
        } else {
            sinfo_msg_error("Aperture not supported");
            sinfo_msg("Supported apertures are only:");
            sinfo_msg("rectangle, circle:");
            goto cleanup;
        }
    } else if (strcmp(operation,"clean_mean") ==0) {
        if (strcmp(aperture,"rectangle") == 0) {
            spec = sinfo_new_clean_mean_rectangle_of_cube_spectra(cube,llx,lly,
                            urx,ury,
                            lo_rej,hi_rej);
        } else if (strcmp(aperture,"circle")==0) {
            spec = sinfo_new_clean_mean_circle_of_cube_spectra(cube,centerx,
                            centery,radius,
                            lo_rej,hi_rej);
        } else {
            sinfo_msg_error("Aperture not supported");
            sinfo_msg("Supported apertures are only:");
            sinfo_msg("rectangle, circle:");
            goto cleanup;
        }
    } else if (strcmp(operation,"median") ==0) {
        if (strcmp(aperture,"rectangle")==0) {
            spec = sinfo_new_median_rectangle_of_cube_spectra(cube,llx,lly,
                            urx,ury);
        } else if (strcmp(aperture,"circle")==0) {
            spec = sinfo_new_median_circle_of_cube_spectra(cube,centerx,
                            centery,radius);
        } else {
            sinfo_msg_error("Aperture not supported");
            sinfo_msg("Supported apertures are only:");
            sinfo_msg("rectangle, circle:");
            goto cleanup;
        }
    } else if (strcmp(operation,"sum") ==0) {
        if (strcmp(aperture,"rectangle")==0) {
            spec = sinfo_new_sum_rectangle_of_cube_spectra(cube,llx,lly,urx,ury);
        } else if (strcmp(aperture,"circle")==0) {
            spec = sinfo_new_sum_circle_of_cube_spectra(cube,centerx,
                            centery,radius);
        } else {
            sinfo_msg_error("Aperture not supported");
            sinfo_msg("Supported apertures are only:");
            sinfo_msg("rectangle, circle:");
            goto cleanup;
        }
    } else if (strcmp(operation,"extract") == 0) {
        if (strcmp(aperture,"rectangle")==0) {
            spec = sinfo_new_median_rectangle_of_cube_spectra(cube,llx,lly,
                            urx,ury);
        } else if (strcmp(aperture,"circle")==0) {
            spec = sinfo_new_median_circle_of_cube_spectra(cube,centerx,
                            centery,radius);
        } else {
            sinfo_msg_error("Aperture not supported");
            sinfo_msg("Supported apertures are only:");
            sinfo_msg("rectangle, circle:");
            goto cleanup;
        }
    } else {
        sinfo_msg_error("Operation not supported");
        sinfo_msg("Supported operations are only:");
        sinfo_msg("average, clean_mean, median, sum, extract :");
        goto cleanup;
    }
    im_spec = sinfo_new_vector_to_image(spec);
    /* head = sinfo_fits_read_header((char*)name_i); */
    sinfo_msg("name_i=%s",name_i);
    ck0_nomsg(sinfo_change_header(name_i));

    /* HOW TO SAVE A PRODUCT ON DISK  */
    /* Set the file name */

    /* Create product frame */
    ck0(sinfo_pro_save_ima(im_spec,framelist,framelist,ima_o,
                    tag_o,NULL,cpl_func,parlist),"failed to save ima");


    sinfo_new_set_wcs_spectrum (im_spec,ima_o,clam, disp, cpix);

    sinfo_stectrum_ima2table(im_spec,ima_o,&tbl_spec);
    ck0(sinfo_pro_save_tbl(tbl_spec,framelist,framelist,tbl_o,
                    tag_o,NULL,cpl_func,parlist),
        "failed to save spectrum");

    cleanup:
    sinfo_free_propertylist(&plist) ;
    sinfo_free_frame(&product_frame) ;
    sinfo_free_image(&image) ;
    sinfo_free_imagelist(&cube);
    sinfo_free_image(&im_spec);
    /* This generate seg fault
    if(spec != NULL) sinfo_free_svector(&spec);
     */
    sinfo_free_table(&tbl_spec);
    /*if(head != NULL) sinfo_fits_header_destroy(head); */

    /* Return */
    if (cpl_error_get_code()) 
        return -1 ;
    else 
        return 0 ;


}
/**@}*/
