
#include "amber_qc.h"
#include <string.h>

/*
static int amber_qc_calc(amdlibVIS *imdVis, amdlibVIS2 *imdVis2,
		amdlibVIS3 *imdVis3, cpl_propertylist * qclist, int channel_min,
		int channel_max, const char * base1name, const char * base2name,
		const char * base3name, const char * cpname);
 */
static int amber_qc_calc_new(amdlibVIS *imdVis, amdlibVIS2 *imdVis2,
		amdlibVIS3 *imdVis3, cpl_propertylist * qclist, int channel_min,
		int channel_max, const char * base1name, const char * base2name,
		const char * base3name, const char * cpname);
static int amber_qc_calc_snr(amdlibVIS *imdVis, cpl_propertylist * qclist,
		const char * base1name, const char * base2name, const char * base3name);
static int amber_qc_average_spectrum(amdlibSPECTRUM *spectrum,
		cpl_propertylist * qclist, int channel_min, int channel_max,
		const char * base1name, const char * base2name, const char * base3name);

/*----------------------------------------------------------------------------*/
/**
   @brief    Calculates QC parameters on the products
   @param    imdWave      pointer to the wave structure
   @param    imdVis       pointer to the visibility structure
   @param    imdVis2      pointer to the visibility2 structure
   @param    imdVis3      pointer to the closure phase structure
   @param    qclist       pointer to the propertylist


   @return   QC parameters appended to the  property list 

 */
/*----------------------------------------------------------------------------*/

int amber_qc(amdlibWAVELENGTH *imdWave, amdlibVIS *imdVis, amdlibVIS2 *imdVis2,
		amdlibVIS3 *imdVis3, amdlibSPECTRUM *spectrum,
		cpl_propertylist * qclist, const char * calib)
{

	int    QC_LAMBDA_CHAN=0;
	double QC_LAMBDA_MIN=0.;
	double QC_LAMBDA_MAX=0.;

	double QC_LAMBDA_CEN_MIN=0.;
	double QC_LAMBDA_CEN_MAX=0.;
	int    QC_LAMBDA_CEN_CHAN=0;

	double QC_LAMBDA_BIN1_MIN=0.;
	double QC_LAMBDA_BIN1_MAX=0.;
	int    QC_LAMBDA_BIN1_CHAN=0;

	double QC_LAMBDA_BIN2_MIN=0.;
	double QC_LAMBDA_BIN2_MAX=0.;
	int    QC_LAMBDA_BIN2_CHAN=0;

	double QC_LAMBDA_BIN3_MIN=0.;
	double QC_LAMBDA_BIN3_MAX=0.;
	int    QC_LAMBDA_BIN3_CHAN=0;

	//int cen_mean=0;
	int cen_min=0;
	int cen_max=0;
	//int bin1_mean=0;
	int bin1_min=0;
	int bin1_max=0;
	//int bin2_mean=0;
	int bin2_min=0;
	int bin2_max=0;
	//int bin3_mean=0;
	int bin3_min=0;
	int bin3_max=0;

	/* Check if at least 1 frame is present */
	if (imdVis->nbFrames<1)
	{
		cpl_msg_warning(cpl_func,"No frame found! Skipping QC calculation");
		return 0;
	}

	/* Calculate */

	/*  The three bins are centered at 1/6, 3/6 and 5/6 of the
	 *  full wavelength covered by the observation */


	//cen_mean=(int)(imdVis2->nbWlen/2.);
	cen_min =(int)((imdVis2->nbWlen/2.)-(imdVis2->nbWlen*USE_CEN/2.));
	cen_max =(int)((imdVis2->nbWlen/2.)+(imdVis2->nbWlen*USE_CEN/2.));
	if (cen_min<0) cen_min=0;
	if (cen_max>(imdVis2->nbWlen-1)) cen_max=(imdVis2->nbWlen-1);

	//bin1_mean= (int)(imdVis2->nbWlen*(1./6.));
	bin1_min =(int)((imdVis2->nbWlen*(1./6.))-(imdVis2->nbWlen*USE_BIN1/2.));
	bin1_max =(int)((imdVis2->nbWlen*(1./6.))+(imdVis2->nbWlen*USE_BIN1/2.));
	if (bin1_min<0) bin1_min=0;
	if (bin1_max>(imdVis2->nbWlen-1)) bin1_max=(imdVis2->nbWlen-1);


	//bin2_mean= (int)(imdVis2->nbWlen*(3./6.));
	bin2_min =(int)((imdVis2->nbWlen*(3./6.))-(imdVis2->nbWlen*USE_BIN2/2.));
	bin2_max =(int)((imdVis2->nbWlen*(3./6.))+(imdVis2->nbWlen*USE_BIN2/2.));
	if (bin2_min<0) bin2_min=0;
	if (bin2_max>(imdVis2->nbWlen-1)) bin2_max=(imdVis2->nbWlen-1);


	//bin3_mean= (int)(imdVis2->nbWlen*(5./6.));
	bin3_min =(int)((imdVis2->nbWlen*(5./6.))-(imdVis2->nbWlen*USE_BIN3/2.));
	bin3_max =(int)((imdVis2->nbWlen*(5./6.))+(imdVis2->nbWlen*USE_BIN3/2.));
	if (bin3_min<0) bin3_min=0;
	if (bin3_max>(imdVis2->nbWlen-1)) bin3_max=(imdVis2->nbWlen-1);


	/*  Divide through 1000 to get the result in micron ... */

	if(imdWave->wlen[0] > imdWave->wlen[imdWave->nbWlen-1]){

		/* lambda in descending order */
		QC_LAMBDA_MIN=imdWave->wlen[imdWave->nbWlen-1]/1000.;
		QC_LAMBDA_MAX=imdWave->wlen[0]/1000.;

		QC_LAMBDA_CEN_MIN=imdWave->wlen[cen_max]/1000.;
		QC_LAMBDA_CEN_MAX=imdWave->wlen[cen_min]/1000.;
		QC_LAMBDA_BIN1_MIN=imdWave->wlen[bin1_max]/1000.;
		QC_LAMBDA_BIN1_MAX=imdWave->wlen[bin1_min]/1000.;
		QC_LAMBDA_BIN2_MIN=imdWave->wlen[bin2_max]/1000.;
		QC_LAMBDA_BIN2_MAX=imdWave->wlen[bin2_min]/1000.;
		QC_LAMBDA_BIN3_MIN=imdWave->wlen[bin3_max]/1000.;
		QC_LAMBDA_BIN3_MAX=imdWave->wlen[bin3_min]/1000.;
	}
	else {
		/* lambda in ascending order */
		QC_LAMBDA_MAX=imdWave->wlen[imdWave->nbWlen-1]/1000.;
		QC_LAMBDA_MIN=imdWave->wlen[0]/1000.;

		QC_LAMBDA_CEN_MAX=imdWave->wlen[cen_max]/1000.;
		QC_LAMBDA_CEN_MIN=imdWave->wlen[cen_min]/1000.;
		QC_LAMBDA_BIN1_MAX=imdWave->wlen[bin1_max]/1000.;
		QC_LAMBDA_BIN1_MIN=imdWave->wlen[bin1_min]/1000.;
		QC_LAMBDA_BIN2_MAX=imdWave->wlen[bin2_max]/1000.;
		QC_LAMBDA_BIN2_MIN=imdWave->wlen[bin2_min]/1000.;
		QC_LAMBDA_BIN3_MAX=imdWave->wlen[bin3_max]/1000.;
		QC_LAMBDA_BIN3_MIN=imdWave->wlen[bin3_min]/1000.;
	}


	QC_LAMBDA_CHAN=imdWave->nbWlen;
	QC_LAMBDA_CEN_CHAN=cen_max-cen_min+1;
	QC_LAMBDA_BIN1_CHAN=bin1_max-bin1_min+1;
	QC_LAMBDA_BIN2_CHAN=bin2_max-bin2_min+1;
	QC_LAMBDA_BIN3_CHAN=bin3_max-bin3_min+1;


	/*Delete old QC parameters*/

	cpl_propertylist_erase_regexp(qclist, "^ESO QC LAMBDA *", 0);
	cpl_propertylist_erase_regexp(qclist, "^ESO QC CAL*", 0);
	cpl_propertylist_erase_regexp(qclist, "^ESO QC UNCAL*", 0);
	cpl_propertylist_erase_regexp(qclist, "^ESO QC TRF*", 0);

	cpl_propertylist_update_int(qclist,"ESO QC LAMBDA CHAN",
			QC_LAMBDA_CHAN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA MIN",
			QC_LAMBDA_MIN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA MAX",
			QC_LAMBDA_MAX);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA CEN MIN",
			QC_LAMBDA_CEN_MIN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA CEN MAX",
			QC_LAMBDA_CEN_MAX);
	cpl_propertylist_update_int(qclist,"ESO QC LAMBDA CEN CHAN",
			QC_LAMBDA_CEN_CHAN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA BIN1 MIN",
			QC_LAMBDA_BIN1_MIN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA BIN1 MAX",
			QC_LAMBDA_BIN1_MAX);
	cpl_propertylist_update_int(qclist,"ESO QC LAMBDA BIN1 CHAN",
			QC_LAMBDA_BIN1_CHAN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA BIN2 MIN",
			QC_LAMBDA_BIN2_MIN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA BIN2 MAX",
			QC_LAMBDA_BIN2_MAX);
	cpl_propertylist_update_int(qclist,"ESO QC LAMBDA BIN2 CHAN",
			QC_LAMBDA_BIN2_CHAN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA BIN3 MIN",
			QC_LAMBDA_BIN3_MIN);
	cpl_propertylist_update_double(qclist,"ESO QC LAMBDA BIN3 MAX",
			QC_LAMBDA_BIN3_MAX);
	cpl_propertylist_update_int(qclist,"ESO QC LAMBDA BIN3 CHAN",
			QC_LAMBDA_BIN3_CHAN);

	/*    Averages the visibilities and closure phases. The channels
	 *    XXX_min and XXX_max are included in the averaging procedure! */


	if(strcmp(calib, "cal")==0){
		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, cen_min, cen_max,
				"ESO QC CALV2 CEN BAS1",
				"ESO QC CALV2 CEN BAS2",
				"ESO QC CALV2 CEN BAS3",
				"ESO QC CALCP CEN");

		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin1_min, bin1_max,
				"ESO QC CALV2 BIN1 BAS1",
				"ESO QC CALV2 BIN1 BAS2",
				"ESO QC CALV2 BIN1 BAS3",
				"ESO QC CALCP BIN1");

		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin2_min, bin2_max,
				"ESO QC CALV2 BIN2 BAS1",
				"ESO QC CALV2 BIN2 BAS2",
				"ESO QC CALV2 BIN2 BAS3",
				"ESO QC CALCP BIN2");

		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin3_min, bin3_max,
				"ESO QC CALV2 BIN3 BAS1",
				"ESO QC CALV2 BIN3 BAS2",
				"ESO QC CALV2 BIN3 BAS3",
				"ESO QC CALCP BIN3");

		amber_qc_calc_snr(imdVis, qclist,
				"ESO QC CALSNR BAS1",
				"ESO QC CALSNR BAS2",
				"ESO QC CALSNR BAS3");
	}
	else if(strcmp(calib, "trf")==0)
	{
		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, cen_min, cen_max,
				"ESO QC TRFV2 CEN BAS1",
				"ESO QC TRFV2 CEN BAS2",
				"ESO QC TRFV2 CEN BAS3",
				"ESO QC TRFCP CEN");

		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin1_min, bin1_max,
				"ESO QC TRFV2 BIN1 BAS1",
				"ESO QC TRFV2 BIN1 BAS2",
				"ESO QC TRFV2 BIN1 BAS3",
				"ESO QC TRFCP BIN1");

		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin2_min, bin2_max,
				"ESO QC TRFV2 BIN2 BAS1",
				"ESO QC TRFV2 BIN2 BAS2",
				"ESO QC TRFV2 BIN2 BAS3",
				"ESO QC TRFCP BIN2");
		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin3_min, bin3_max,
				"ESO QC TRFV2 BIN3 BAS1",
				"ESO QC TRFV2 BIN3 BAS2",
				"ESO QC TRFV2 BIN3 BAS3",
				"ESO QC TRFCP BIN3");

		amber_qc_calc_snr(imdVis, qclist,
				"ESO QC TRFSNR BAS1",
				"ESO QC TRFSNR BAS2",
				"ESO QC TRFSNR BAS3");
	}
	else {
		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, cen_min, cen_max,
				"ESO QC UNCALV2 CEN BAS1",
				"ESO QC UNCALV2 CEN BAS2",
				"ESO QC UNCALV2 CEN BAS3",
				"ESO QC UNCALCP CEN");

		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin1_min, bin1_max,
				"ESO QC UNCALV2 BIN1 BAS1",
				"ESO QC UNCALV2 BIN1 BAS2",
				"ESO QC UNCALV2 BIN1 BAS3",
				"ESO QC UNCALCP BIN1");

		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin2_min, bin2_max,
				"ESO QC UNCALV2 BIN2 BAS1",
				"ESO QC UNCALV2 BIN2 BAS2",
				"ESO QC UNCALV2 BIN2 BAS3",
				"ESO QC UNCALCP BIN2");
		amber_qc_calc_new(imdVis, imdVis2, imdVis3, qclist, bin3_min, bin3_max,
				"ESO QC UNCALV2 BIN3 BAS1",
				"ESO QC UNCALV2 BIN3 BAS2",
				"ESO QC UNCALV2 BIN3 BAS3",
				"ESO QC UNCALCP BIN3");
		amber_qc_calc_snr(imdVis, qclist,
				"ESO QC UNCALSNR BAS1",
				"ESO QC UNCALSNR BAS2",
				"ESO QC UNCALSNR BAS3");
	}


	if(spectrum !=NULL){

		amber_qc_average_spectrum(spectrum, qclist, cen_min, cen_max,
				"ESO QC SPECTRUM CEN TEL1",
				"ESO QC SPECTRUM CEN TEL2",
				"ESO QC SPECTRUM CEN TEL3");
	}


	return 0;
}

/*
static int amber_qc_calc(amdlibVIS *imdVis, amdlibVIS2 *imdVis2,
		amdlibVIS3 *imdVis3, cpl_propertylist * qclist, int channel_min,
		int channel_max, const char * base1name, const char * base2name,
		const char * base3name, const char * cpname)
{
	int        iFrame= 0;
	int        iWave=0;
	double     base1=0.;
	double     base2=0.;
	double     base3=0.;
	double     cp=0.;

	 Looping and Summing up Visibility2...
	for(iFrame = 0; iFrame < imdVis->nbFrames*imdVis->nbBases; iFrame++){
		for(iWave = channel_min; iWave <= channel_max; iWave++){
			base1+=imdVis2->table[iFrame].vis2[iWave];

		}
		if(imdVis->nbBases>1){
			iFrame++;
			for(iWave = channel_min; iWave <= channel_max; iWave++){
				base2+=imdVis2->table[iFrame].vis2[iWave];
			}
			iFrame++;
			for(iWave = channel_min; iWave <= channel_max; iWave++){
				base3+=imdVis2->table[iFrame].vis2[iWave];
			}
		}
	}

	base1=base1/((channel_max-channel_min+1))/imdVis->nbFrames;

	if (imdVis->nbBases>1){

		base2=base2/((channel_max-channel_min+1))/imdVis->nbFrames;
		base3=base3/((channel_max-channel_min+1))/imdVis->nbFrames;


		 Looping and Summing up Closure Phase...
		for(iFrame = 0; iFrame < imdVis->nbFrames; iFrame++){
			for(iWave = channel_min; iWave <= channel_max; iWave++){
				cp+=imdVis3->table[iFrame].vis3Phi[iWave];
			}
		}
		cp=cp/ ((channel_max-channel_min+1)*imdVis->nbFrames) * (180. / M_PI);
	}

	cpl_propertylist_update_double(qclist, base1name, base1);
	if (imdVis->nbBases>1){
		cpl_propertylist_update_double(qclist, base2name, base2);
		cpl_propertylist_update_double(qclist, base3name, base3);
		cpl_propertylist_update_double(qclist, cpname, cp);
	}
	return 0;
}
 */

static int amber_qc_average_spectrum(amdlibSPECTRUM *spectrum,
		cpl_propertylist * qclist, int channel_min, int channel_max,
		const char * base1name, const char * base2name, const char * base3name)
{
	cpl_array      * base1_array=NULL;
	cpl_array      * base2_array=NULL;
	cpl_array      * base3_array=NULL;
	cpl_size         iWave=0;

	if (channel_max>((spectrum->nbWlen)-1)){
		channel_max=(spectrum->nbWlen)-1;
	}

	base1_array=cpl_array_new((cpl_size)spectrum->nbWlen,CPL_TYPE_DOUBLE);
	base2_array=cpl_array_new((cpl_size)spectrum->nbWlen,CPL_TYPE_DOUBLE);
	base3_array=cpl_array_new((cpl_size)spectrum->nbWlen,CPL_TYPE_DOUBLE);

	if(spectrum->nbTels>2){
		for(iWave = channel_min; iWave <= channel_max; iWave++){
			cpl_array_set_double(base1_array,iWave,spectrum->spec[0][iWave]);
			cpl_array_set_double(base2_array,iWave,spectrum->spec[1][iWave]);
			cpl_array_set_double(base3_array,iWave,spectrum->spec[2][iWave]);
		}
	}
	else{
		for(iWave = channel_min; iWave <= channel_max; iWave++){
			cpl_array_set_double(base1_array,iWave,spectrum->spec[0][iWave]);
		}
	}
	/*update the QC list*/
	cpl_propertylist_update_double(qclist, base1name,
			cpl_array_get_mean(base1_array));
	if (spectrum->nbTels>2){
		cpl_propertylist_update_double(qclist, base2name,
				cpl_array_get_mean(base2_array));
		cpl_propertylist_update_double(qclist, base3name,
				cpl_array_get_mean(base3_array));
	}


	cpl_array_delete(base1_array);
	cpl_array_delete(base2_array);
	cpl_array_delete(base3_array);

	return 0;


}


static int amber_qc_calc_new(amdlibVIS *imdVis, amdlibVIS2 *imdVis2,
		amdlibVIS3 *imdVis3, cpl_propertylist * qclist, int channel_min,
		int channel_max, const char * base1name, const char * base2name,
		const char * base3name, const char * cpname)
{
	int          iFrame= 0;
	int          iFrame_single=0;
	int          NumberOfChannels=0;
	int          iWave=0;
	double       base1=0.;
	double       base2=0.;
	double       base3=0.;
	double       cp=0.;
	const char * base1name_stdev=NULL;
	const char * base2name_stdev=NULL;
	const char * base3name_stdev=NULL;
	const char * cpname_stdev=NULL;
	cpl_array  * base1_array=NULL;
	cpl_array  * base2_array=NULL;
	cpl_array  * base3_array=NULL;
	cpl_array  * cp_array=NULL;


	base1_array=cpl_array_new(imdVis->nbFrames,CPL_TYPE_DOUBLE);
	base2_array=cpl_array_new(imdVis->nbFrames,CPL_TYPE_DOUBLE);
	base3_array=cpl_array_new(imdVis->nbFrames,CPL_TYPE_DOUBLE);
	cp_array=cpl_array_new(imdVis->nbFrames,CPL_TYPE_DOUBLE);

	iFrame_single=0;

	/* Looping and Summing up Visibility2... */
	for(iFrame = 0; iFrame < imdVis->nbFrames*imdVis->nbBases; iFrame++){
		base1=0.;
		NumberOfChannels=0;
		for(iWave = channel_min; iWave <= channel_max; iWave++){
			if(imdVis2->table[iFrame].flag[iWave]==amdlibFALSE){
				base1+=imdVis2->table[iFrame].vis2[iWave];
				NumberOfChannels++;
			}
		}
		if(NumberOfChannels>0){
			cpl_array_set_double(base1_array,iFrame_single,base1/
					NumberOfChannels);
		}
		else {
			cpl_array_set_invalid(base1_array,iFrame_single);
		}

		if(imdVis->nbBases>1){
			iFrame++;
			base2=0.;
			NumberOfChannels=0;
			for(iWave = channel_min; iWave <= channel_max; iWave++){
				if(imdVis2->table[iFrame].flag[iWave]==amdlibFALSE){
					base2+=imdVis2->table[iFrame].vis2[iWave];
					NumberOfChannels++;
				}
			}
			if(NumberOfChannels>0){
				cpl_array_set_double(base2_array,iFrame_single,base2/
						NumberOfChannels);
			}
			else {
				cpl_array_set_invalid(base2_array,iFrame_single);
			}
			iFrame++;
			base3=0.;
			NumberOfChannels=0;
			for(iWave = channel_min; iWave <= channel_max; iWave++){
				if(imdVis2->table[iFrame].flag[iWave]==amdlibFALSE){
					base3+=imdVis2->table[iFrame].vis2[iWave];
					NumberOfChannels++;
				}
			}

			if(NumberOfChannels>0){
				cpl_array_set_double(base3_array,iFrame_single,base3/
						NumberOfChannels);
			}
			else {
				cpl_array_set_invalid(base3_array,iFrame_single);
			}
		}
		iFrame_single++;
	}

	if (imdVis->nbBases>1){

		/* Looping and Summing up Closure Phase... */
		for(iFrame = 0; iFrame < imdVis->nbFrames; iFrame++){
			cp=0.;
			NumberOfChannels=0;
			for(iWave = channel_min; iWave <= channel_max; iWave++){
				if(imdVis3->table[iFrame].flag[iWave]==amdlibFALSE){
					cp+=imdVis3->table[iFrame].vis3Phi[iWave];
					NumberOfChannels++;
				}
			}

			if(NumberOfChannels>0){
				cpl_array_set_double(cp_array,iFrame,cp /
						NumberOfChannels *(180. / M_PI));
			}
			else {
				cpl_array_set_invalid(cp_array,iFrame);
			}

		}
	}

	base1name_stdev=cpl_sprintf("%s STDEV",base1name);
	base2name_stdev=cpl_sprintf("%s STDEV",base2name);
	base3name_stdev=cpl_sprintf("%s STDEV",base3name);
	cpname_stdev=cpl_sprintf("%s STDEV",cpname);

	cpl_propertylist_update_double(qclist, base1name,
			cpl_array_get_mean(base1_array));
	cpl_propertylist_update_double(qclist, base1name_stdev,
			cpl_array_get_stdev(base1_array));


	if (imdVis->nbBases>1){
		cpl_propertylist_update_double(qclist, base2name,
				cpl_array_get_mean(base2_array));
		cpl_propertylist_update_double(qclist, base2name_stdev,
				cpl_array_get_stdev(base2_array));

		cpl_propertylist_update_double(qclist, base3name,
				cpl_array_get_mean(base3_array));
		cpl_propertylist_update_double(qclist, base3name_stdev,
				cpl_array_get_stdev(base3_array));

		cpl_propertylist_update_double(qclist, cpname,
				cpl_array_get_mean(cp_array));
		cpl_propertylist_update_double(qclist, cpname_stdev,
				cpl_array_get_stdev(cp_array));
	}

	cpl_array_delete(base1_array);
	cpl_array_delete(base2_array);
	cpl_array_delete(base3_array);
	cpl_array_delete(cp_array);

	cpl_free((void *)base1name_stdev);
	cpl_free((void *)base2name_stdev);
	cpl_free((void *)base3name_stdev);
	cpl_free((void *)cpname_stdev);

	return 0;
}


static int amber_qc_calc_snr(amdlibVIS *imdVis, cpl_propertylist * qclist,
		const char * base1name, const char * base2name, const char * base3name)
{
	int        iFrame= 0;
	double     snrbase1=0.;
	double     snrbase2=0.;
	double     snrbase3=0.;

	/* Looping and Summing the SNR... */
	for(iFrame = 0; iFrame < imdVis->nbFrames*imdVis->nbBases; iFrame++){
		snrbase1+=imdVis->table[iFrame].frgContrastSnr;
		if(imdVis->nbBases>1){
			iFrame++;
			snrbase2+=imdVis->table[iFrame].frgContrastSnr;
			iFrame++;
			snrbase3+=imdVis->table[iFrame].frgContrastSnr;
		}
	}

	snrbase1=snrbase1/imdVis->nbFrames;
	snrbase2=snrbase2/imdVis->nbFrames;
	snrbase3=snrbase3/imdVis->nbFrames;


	cpl_propertylist_update_double(qclist, base1name, snrbase1);
	if (imdVis->nbBases>1){
		cpl_propertylist_update_double(qclist, base2name, snrbase2);
		cpl_propertylist_update_double(qclist, base3name, snrbase3);
	}
	return 0;
}
