/* $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: sinfo-2_4_0 $
 */

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


}
/**@}*/
