
/*
 * This file is part of the ESO UVES 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
 */


/*---------------------------------------------------------------------------*/
/**
  @brief procedure to perform a cross correlation and calculate the velocity 
         shift between two spectra
  @return   0 if everything is ok

*/
/*---------------------------------------------------------------------------*/
#include <irplib_utils.h>
#include <uves_msg.h>
#include <uves_error.h>
#include <uves_qclog.h>
#include <uves_dfs.h>
#include <uves_utils_wrappers.h>
#include <flames_midas_def.h>
#include <flames_corvel.h>
#include <flames_reduce_vcorrel.h>


// Simultaneous corvel simcal data reduction
double DRS_CVEL_MIN = -6.;
double DRS_CVEL_MAX = +6.;
double DRS_CVEL_STEP = 0.5;


int
flames_reduce_vcorrel(const char* sci_pfx, 
                      const char* cvel_pfx, 
                      const char* ccd_id,
                      const int ord_max,
                      const cpl_frame* cvel_tab, 
                      const char* xxima_pfx, 
                      const char* xwcal_pfx,
                      const double drs_cvel_min,
                      const double drs_cvel_max,
                      double* zero_point,
                      double* avg_cnt,
                      double* sig_cnt,
		      cpl_table* qclog)
{

   int ord = 0;
   int ord_min=1;
   char cvel_tab_name[MAX_NAME_SIZE];
   char tim_ccf[80];
   char nim_ccf[80];
   char iim_pfx[80];
   char tab_pfx[80];
   char nim_pfx[80];
   char tim_pfx[80];
   char ref_frm[80];
   char otab[80];
   const int npix=(drs_cvel_max-drs_cvel_min)/DRS_CVEL_STEP+1;

   cpl_image* tim_ccf_ima=NULL;
   cpl_image* nim_ccf_ima=NULL;

   cpl_table* cvel_tbl=NULL;
   double ccfcnt[ord_max];
   int    num_ord=0;
   int status=0;
   int unit=0;
   int actvals=0;
   int null=0;
 
   int in_ima_id=0;
   int iim_pfx_id=0;

   char out_cvel_tab[80];
   char out_tot_ima[80];
   char out_nrm_ima[80];
   cpl_table* cvel_ord_tbl=NULL;
   int row_pos=0;

   cpl_image* tot_ima=NULL;
   cpl_image* nrm_ima=NULL;
   int nrow=0;

   double ccf_max=0;
   double wav_rng=0;
   double pix_tot=0;
   int lin_tot=0;
   cpl_propertylist* plist_ima_new=NULL;
   cpl_propertylist* plist_tbl_new=NULL;

   double corvel_max=0;


   char key_name[80];

   const char* command=NULL;



   //Fixme
   uves_msg_debug("sci_pfx=%s",sci_pfx);
   uves_msg_debug("ccd_id=%s",ccd_id);

   sprintf(otab,"%s%s%s",cvel_pfx,ccd_id,".fits");
   sprintf(tim_ccf,"%s%s%s%s","tot_",cvel_pfx,ccd_id,".fits");
   sprintf(nim_ccf,"%s%s%s%s","nrm_",cvel_pfx,ccd_id,".fits");
   sprintf(iim_pfx,"%s%s%s%s","mw",sci_pfx,xxima_pfx,".fits");
   sprintf(tab_pfx,"%s%s%s","tab_",ccd_id,"_");
   sprintf(nim_pfx,"%s%s%s","nrm_",ccd_id,"_");
   sprintf(tim_pfx,"%s%s%s","tot_",ccd_id,"_");
   sprintf(ref_frm,"%s%s%s","w",sci_pfx,xwcal_pfx);


   uves_msg_debug("pointer=%p",cvel_tab);

   uves_msg("name=%s",cpl_frame_get_filename(cvel_tab));
   sprintf(cvel_tab_name,"%s",cpl_frame_get_filename(cvel_tab));

   uves_msg_debug("npix=%d",npix);
   tim_ccf_ima=cpl_image_new(npix,ord_max,CPL_TYPE_FLOAT);
   nim_ccf_ima=cpl_image_new(npix,ord_max,CPL_TYPE_FLOAT);


   //AMO:Fixme
   row_pos=0;
   uves_msg_debug("ord_max=%d nlines=%d",ord_max,npix*ord_max);
   //cvel_tbl=cpl_table_new(npix*ord_max);
   cvel_tbl=cpl_table_new(0);
   check_nomsg(cpl_table_new_column(cvel_tbl,"Select",CPL_TYPE_INT));
   check_nomsg(cpl_table_new_column(cvel_tbl,"ccf_pos",CPL_TYPE_DOUBLE));
   check_nomsg(cpl_table_new_column(cvel_tbl,"ccf_nrm",CPL_TYPE_DOUBLE));
   check_nomsg(cpl_table_new_column(cvel_tbl,"ccf_out",CPL_TYPE_DOUBLE));
   check_nomsg(cpl_table_new_column(cvel_tbl,"ORDER",CPL_TYPE_INT));
   check_nomsg(plist_ima_new=cpl_propertylist_new());


  
   ck0_nomsg(uves_qclog_add_string(qclog,
				   "QC TEST2 ID",
				   "Fibre-Science-QC",
				   "Name of QC test",
				   "%s"));
   uves_check_rec_status(0);

   for (ord=ord_min;ord<=ord_max;ord++) {
      ccfcnt[ord]=0;
      //for (ord=2;ord<=2;ord++) {
 
      sprintf(out_cvel_tab,"%s%s%d%s","tab_",ccd_id,ord,".fits");
      sprintf(out_tot_ima,"%s%s%d%s","tot_",ccd_id,ord,".fits");
      sprintf(out_nrm_ima,"%s%s%d%s","nrm_",ccd_id,ord,".fits");

 
      uves_msg_debug("vc2 %s %s %s",out_cvel_tab,out_tot_ima,out_nrm_ima);
      uves_msg_debug("iim_pfx=%s cvel_tab_name=%s ord=%d",
                       iim_pfx,cvel_tab_name,ord);
 
      uves_msg_debug("out_cvel_tab=%s",out_cvel_tab);
      uves_msg_debug("out_tot_ima=%s",out_tot_ima);
      uves_msg_debug("out_nrm_ima=%s",out_nrm_ima);
      uves_msg_debug("ord=%d",ord);

 


      check_nomsg(flames_corvel(iim_pfx,
                                cvel_tab_name,
                                ord,
                                out_cvel_tab,
                                out_tot_ima,
                                out_nrm_ima,
                                drs_cvel_min,
                                drs_cvel_max,
                                DRS_CVEL_STEP));


      uves_msg_debug("CVEL MAX=%f MIN=%f STEP=%f",
		       drs_cvel_min,drs_cvel_max,DRS_CVEL_STEP);

      check_nomsg(tot_ima=cpl_image_load(out_tot_ima,CPL_TYPE_FLOAT,0,0));
      check_nomsg(nrm_ima=cpl_image_load(out_nrm_ima,CPL_TYPE_FLOAT,0,0));
      check_nomsg(cpl_image_copy(tim_ccf_ima,tot_ima,1,ord-ord_min+1));
      check_nomsg(cpl_image_copy(nim_ccf_ima,nrm_ima,1,ord-ord_min+1));
      check_nomsg(cvel_ord_tbl=cpl_table_load(out_cvel_tab,1,1));
 

      check_nomsg(cpl_table_new_column(cvel_ord_tbl,"ORDER",CPL_TYPE_INT));
      check_nomsg(nrow=cpl_table_get_nrow(cvel_ord_tbl));

      check_nomsg(cpl_table_fill_column_window_int(cvel_ord_tbl,"ORDER",0,nrow,ord));
      if(ord==ord_min) {
         const char* unit=cpl_table_get_column_unit(cvel_ord_tbl,"ccf_pos");
         cpl_table_set_column_unit(cvel_tbl,"ccf_pos",unit);
         unit=cpl_table_get_column_unit(cvel_ord_tbl,"ccf_nrm");
         cpl_table_set_column_unit(cvel_tbl,"ccf_nrm",unit);
         unit=cpl_table_get_column_unit(cvel_ord_tbl,"ccf_out");
         cpl_table_set_column_unit(cvel_tbl,"ccf_out",unit);
      }
      check_nomsg(cpl_table_insert(cvel_tbl,cvel_ord_tbl,row_pos));
      row_pos+=nrow;

      if((status=SCFOPN(out_tot_ima,D_R4_FORMAT,0,F_IMA_TYPE,&in_ima_id))!=0) {
         uves_msg_error("opening frame %s",out_tot_ima);
         return flames_midas_error(MAREMMA);
      }

      if((status=SCFOPN(iim_pfx,D_R4_FORMAT,0,F_IMA_TYPE,&iim_pfx_id))!=0) {
         uves_msg_error("opening frame %s",iim_pfx);
         return flames_midas_error(MAREMMA);
      }



      sprintf(key_name,"%s","CORVEL_MAX");
      if((status=SCDRDD(iim_pfx_id,key_name,1,1,&actvals,&corvel_max,&unit,&null)) 
         != 0) {
	uves_msg_error("Reading descriptor %s from frame %s",
		       key_name,out_tot_ima);
         return flames_midas_error(MAREMMA);
      }

 

      sprintf(key_name,"%s%d","CCF_PMX",ord);
      uves_msg_debug("corvel_max=%g",corvel_max);
      if(!irplib_isnan(corvel_max)) {
         ccfcnt[ord]=corvel_max;
	 check_nomsg(cpl_propertylist_append_double(plist_ima_new,key_name,
						    corvel_max));


	     
	 ck0_nomsg(uves_qclog_add_double(qclog,
					 cpl_sprintf("%s%d%s",
						     "QC CCF",ord," POSMAX"),
					 corvel_max,
					 "CCF pos Max",
					 "%f"));
	 

      } else {
         ccfcnt[ord]=999;
	 check_nomsg(cpl_propertylist_append_double(plist_ima_new,key_name,
						    999));


	 
     
	 ck0_nomsg(uves_qclog_add_double(qclog,
					 cpl_sprintf("%s%d%s",
						     "QC CCF",ord," POSMAX"),
					 999,
					 "CCF pos Max",
					 "%f"));
	 

      }


      sprintf(key_name,"%s","CCF_MAX");
      if((status=SCDRDD(in_ima_id,key_name,1,1,&actvals,&ccf_max,&unit,&null)) 
         != 0) {
	uves_msg_error("Reading descriptor %s from frame %s",
		       key_name,out_tot_ima);
         return flames_midas_error(MAREMMA);
      }


      sprintf(key_name,"%s%d","CCF_MAX",ord);
      uves_msg_debug("ccf_max=%g",ccf_max);
      check_nomsg(cpl_propertylist_append_double(plist_ima_new,key_name,ccf_max));

      
      ck0_nomsg(uves_qclog_add_double(qclog,
				    cpl_sprintf("%s%d%s",
						"QC CCF",ord," INTMAX"),
				      ccf_max,
				      "CCF Int Max",
				      "%f"));

      
 
      sprintf(key_name,"%s","WAV_RNG");
      if((status=SCDRDD(in_ima_id,key_name,1,1,&actvals,&wav_rng,&unit,&null)) 
         != 0) {
	uves_msg_error("Reading descriptor %s from frame %s",
		       key_name,out_tot_ima);
         return flames_midas_error(MAREMMA);
      }

      sprintf(key_name,"%s%d","WAV_RNG",ord);
      uves_msg_debug("wav_rng=%g",wav_rng);
      uves_msg_debug("key_name=%s",key_name);
      check_nomsg(cpl_propertylist_append_double(plist_ima_new,key_name,wav_rng));

      
      ck0_nomsg(uves_qclog_add_double(qclog,
				    cpl_sprintf("%s%d%s",
						"QC CCF",ord," WAVRNG"),
				      wav_rng,
				      "CCF Range",
				      "%f"));

      
     
      sprintf(key_name,"%s","PIX_TOT");
      if((status=SCDRDD(in_ima_id,key_name,1,1,&actvals,&pix_tot,&unit,&null)) 
         != 0) {
	uves_msg_error("Reading descriptor %s from frame %s",
		       key_name,out_tot_ima);
         return flames_midas_error(MAREMMA);
      }
 
     
      uves_msg_debug("pix_tot=%g",pix_tot);
      if(!irplib_isinf(pix_tot)) {

	sprintf(key_name,"%s%d","PIX_TOT",ord);
	check_nomsg(cpl_propertylist_append_double(plist_ima_new,key_name,pix_tot));

	ck0_nomsg(uves_qclog_add_double(qclog,
					cpl_sprintf("%s%d%s",
						    "QC CCF",ord," PIXTOT"),
					pix_tot,
					"CCF Pix",
					"%f"));

      } else {

	sprintf(key_name,"%s%d","PIX_TOT",ord);
	check_nomsg(cpl_propertylist_append_double(plist_ima_new,key_name,999.));

	ck0_nomsg(uves_qclog_add_double(qclog,
					cpl_sprintf("%s%d%s",
						    "QC CCF",ord," PIXTOT"),
					999,
					"CCF Pix",
					"%f"));


      }

      sprintf(key_name,"%s","LIN_TOT");
      if((status=SCDRDI(in_ima_id,key_name,1,1,&actvals,&lin_tot,&unit,&null)) 
         != 0) {
	uves_msg_error("Reading descriptor %s from frame %s",
		       key_name,out_tot_ima);
         return flames_midas_error(MAREMMA);
      }


      sprintf(key_name,"%s%d","LIN_TOT",ord);

      check_nomsg(cpl_propertylist_append_int(plist_ima_new,key_name,lin_tot));
      uves_msg_debug("lin_tot=%d",lin_tot);

           
      ck0_nomsg(uves_qclog_add_int(qclog,
				    cpl_sprintf("%s%d%s",
						"QC CCF",ord," LINTOT"),
				      pix_tot,
				      "CCF Lin",
				      "%d"));
     
     
      if((status = SCFCLO(in_ima_id))!=0) {
         uves_msg_error("Closing frame %d",in_ima_id);
         return flames_midas_error(MAREMMA);
      }
      if((status = SCFCLO(iim_pfx_id))!=0) {
         uves_msg_error("Closing frame %d",iim_pfx_id);
         return flames_midas_error(MAREMMA);
      }
 
     
      uves_free_table(&cvel_ord_tbl);
      uves_free_image(&tot_ima);
      uves_free_image(&nrm_ima);

      command=uves_sprintf("%s%s","rm -rf ",out_cvel_tab);
      system(command);
      command=uves_sprintf("%s%s","rm -rf ",out_tot_ima);
      system(command);
      command=uves_sprintf("%s%s","rm -rf ",out_nrm_ima);
      system(command);


   } //end loop over orders


   check_nomsg(uves_sanitise_propertylist(plist_ima_new));
   check_nomsg(cpl_image_save(tim_ccf_ima, "tot_ima.fits",CPL_BPP_IEEE_FLOAT,
			      plist_ima_new,CPL_IO_DEFAULT));
   check_nomsg(cpl_image_save(nim_ccf_ima, "nrm_ima.fits",CPL_BPP_IEEE_FLOAT,
			      plist_ima_new,CPL_IO_DEFAULT));
 
   check_nomsg(uves_sanitise_propertylist(plist_tbl_new));
   check_nomsg(cpl_table_save(cvel_tbl, plist_tbl_new, NULL, otab, 
			      CPL_IO_DEFAULT));
 
   uves_free_image(&tim_ccf_ima);
   uves_free_image(&nim_ccf_ima);
   uves_free_table(&cvel_tbl);

   ord = ord_max-ord_min+1;
   //flames_cveltab(cpfx_ccd_id_tbl,ord);



   num_ord = 0;
   *avg_cnt=0;
   for (ord=ord_min; ord<= ord_max; ord++) {
      if (ccfcnt[ord] != 999) {
         *avg_cnt +=ccfcnt[ord];
         uves_msg_debug("POSMAX avg=%g cnt=%g ord=%d",*avg_cnt,ccfcnt[ord],ord);
         num_ord += 1;
      }
   }
 
   *avg_cnt /= num_ord;
   *sig_cnt=0;
   for (ord = ord_min; ord <= ord_max; ord++) {
      if (ccfcnt[ord] != 999) {
         *sig_cnt += (ccfcnt[ord]-*avg_cnt)*(ccfcnt[ord]-*avg_cnt);
         uves_msg_debug("sig=%g cnt=%g ord=%d",*sig_cnt,ccfcnt[ord],ord);
      }
   }
   *sig_cnt = sqrt(*sig_cnt/(num_ord-1));

   *zero_point+=(*avg_cnt);


   /*
   uves_msg("POSMAX avg=%g sig=%g zp=%g",*avg_cnt,*sig_cnt,*zero_point);
   */

   ck0_nomsg(uves_qclog_add_double(qclog,
				   "QC CCF POSAVG",
				   *avg_cnt,
				   "CCF pos avg",
				   "%f"));


   ck0_nomsg(uves_qclog_add_double(qclog,
				   "QC CCF POSRMS",
				   *sig_cnt,
				   "CCF pos rms",
				   "%f"));
   /* commented out to match FUVES-MIDAS results

  ck0_nomsg(uves_qclog_add_double(qclog,
				   "QC CCF POSOFF",
				   *zero_point,
				   "CCF pos avg from ThAr calibration",
				   "%f"));

   */
 


   uves_msg_debug("POSAVG=%f POSRMS=%f",*avg_cnt,*sig_cnt);
 

   /*
     do ord = ord_min ord_max

     CORVEL/FLAMES {iim_pfx}{ord}.bdf {cvel_tab} {ord} -
     {tab_pfx}{ord}.tbl {tim_pfx}{ord}.bdf {nim_pfx}{ord}.bdf
    
 

     insert/ima {tim_pfx}{ord}.bdf {tim_ccf} @1,@{ord}
     insert/ima {nim_pfx}{ord}.bdf {nim_ccf} @1,@{ord}
     
     create/column {tab_pfx}{ord}.tbl :ORDER
     compute/table {tab_pfx}{ord}.tbl :ORDER = {ord}
     if counter .eq. 0 then
     merge/table {tab_pfx}{ord}.tbl  {cpfx}_{ccd_id}.tbl
     counter = counter + 1
     else
     -rename {cpfx}_{ccd_id}.tbl tmp.tbl
     merge/table tmp.tbl {tab_pfx}{ord}.tbl  {cpfx}_{ccd_id}.tbl  
     endif
     copy/dd {iim_pfx}{ord}.bdf CORVEL_MAX {cpfx}_{ccd_id}.tbl CCF_PMX{ord}
     qc1log/out 1 {otab}  "QC.CCF{ord}.POSMAX" {{iim_pfx}{ord}.bdf,CORVEL_MAX} "CCF pos Max"
     qc1log/out 1 {otab}  "QC.CCF{ord}.INTMAX" {{tab_pfx}{ord}.tbl,CCF_MAX} "CCF Int Max"
     qc1log/out 1 {otab}  "QC.CCF{ord}.WAVRNG" {{tab_pfx}{ord}.tbl,WAV_RNG} "CCF Range"
     qc1log/out 1 {otab}  "QC.CCF{ord}.PIXTOT" {{tab_pfx}{ord}.tbl,PIX_TOT} "CCF Pix"
     qc1log/out 1 {otab}  "QC.CCF{ord}.LINTOT" {{tab_pfx}{ord}.tbl,LIN_TOT} "CCF Lin"
     if "{{iim_pfx}{ord}.bdf,CORVEL_MAX}" .ne. "NAN" then
     ccfcnt({ord}) = {{iim_pfx}{ord}.bdf,CORVEL_MAX}
     else
     mess/out 2 {pid} "Pos Max Nan for order {ord}. Skip it"
     ccfcnt({ord}) = 999
     endif

     copy/dd {tab_pfx}{ord}.tbl CCF_MAX {cpfx}_{ccd_id}.tbl CCF_MAX{ord}
     copy/dd {tab_pfx}{ord}.tbl WAV_RNG {cpfx}_{ccd_id}.tbl WAV_RNG{ord}
     copy/dd {tab_pfx}{ord}.tbl PIX_TOT {cpfx}_{ccd_id}.tbl PIX_TOT{ord}
     copy/dd {tab_pfx}{ord}.tbl LIN_TOT {cpfx}_{ccd_id}.tbl LIN_TOT{ord}



     copy/dd {iim_pfx}{ord}.bdf CORVEL_MAX {tim_ccf} CCF_PMX{ord}
     copy/dd {tim_pfx}{ord}.bdf CCF_MAX    {tim_ccf} CCF_MAX{ord}
     copy/dd {tim_pfx}{ord}.bdf WAV_RNG    {tim_ccf} WAV_RNG{ord}
     copy/dd {tim_pfx}{ord}.bdf PIX_TOT    {tim_ccf} PIX_TOT{ord}
     copy/dd {tim_pfx}{ord}.bdf LIN_TOT    {tim_ccf} LIN_TOT{ord}

     copy/dd {iim_pfx}{ord}.bdf CORVEL_MAX {nim_ccf} CCF_PMX{ord}
     copy/dd {nim_pfx}{ord}.bdf CCF_MAX    {nim_ccf} CCF_MAX{ord}
     copy/dd {nim_pfx}{ord}.bdf WAV_RNG    {nim_ccf} WAV_RNG{ord}
     copy/dd {nim_pfx}{ord}.bdf PIX_TOT    {nim_ccf} PIX_TOT{ord}
     copy/dd {nim_pfx}{ord}.bdf LIN_TOT    {nim_ccf} LIN_TOT{ord}

     enddo
     ord = {ord_max}-{ord_min}+1
     CVELTAB/FLAMES {cpfx}_{ccd_id}.tbl {ord}



     nord = 0
     do ord = ord_min ord_max
     if ccfcnt({ord}) .ne. 999 then
     avgcnt = avgcnt+ccfcnt({ord})
     nord = nord+1
     endif
     enddo
     avgcnt = avgcnt/(nord)
     do ord = ord_min ord_max
     if ccfcnt({ord}) .ne. 999 then
     sigcnt = sigcnt+(ccfcnt({ord})-avgcnt)*(ccfcnt({ord})-avgcnt)
     endif
     enddo
     sigcnt = m$sqrt(sigcnt/(nord-1))


     mess/out {DRS_MES_LEV} {pid} "POSAVG={avgcnt} POSRMS={sigcnt}"
     qc1log/out 1 {otab}  "QC.CCF.POSAVG" {avgcnt} "CCF pos avg"
     qc1log/out 1 {otab}  "QC.CCF.POSRMS" {sigcnt} "CCF pos rms"
     qc1log/out 1 {otab}  "QC.CCF.POSOFF" {p8}  "CCF pos avg from ThAr calibration"

     qc1log/out 3
     return {avgcnt}
     !set/format {cpfx}_{ccd_id}.tbl


   */
  cleanup:

   if(plist_ima_new!=NULL) {
     uves_msg_warning("free");
      cpl_propertylist_delete(plist_ima_new);
      plist_ima_new=NULL;
   }
   uves_free_table(&cvel_tbl);
   uves_free_image(&tim_ccf_ima);
   uves_free_image(&nim_ccf_ima);
   uves_free_image(&tot_ima);
   uves_free_image(&nrm_ima);
   uves_free_table(&cvel_ord_tbl);
 


   if (cpl_error_get_code() != CPL_ERROR_NONE) {
      uves_check_rec_status(9);
      //uves_free_imagelist(&obj_cor);
      return -1;
   } else {
      return 0;
   }

}

