/* $Id: amber_SciCal.c,v 1.49 2013-09-16 14:56:43 agabasch Exp $
 *
 * This file is part of the AMBER 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
 */



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

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

#include <math.h>
#include <cpl.h>
#include <string.h>
#include "amdrs.h"
#include "amber_qc.h"
#include "esolibSelector.h"
#include "esolibTransferfunction.h"
#include "amber_dfs.h"
#include "esolibCalibVis.h"

/* PAF file and QC log */
#include "giqclog.h"
/* #include "giutils.h" */

#define MAXFILESRAW 5000
#define MAXFILESPRODUCTS (MAXFILESRAW*3)


#define amdlibTYPICAL_RON 10.0

static int                   errorType; 
static int                   pistonType; 
static int                   iBinningOfFrames;
int                          iProductNumber;

int                          i;                         /*The currently reduced  imput frame number */ 
char                  szFilenameProduct[512];
char              **  szFilenameSCIENCE;  /* 3 bands * MAXFILESRAW raw frames = MAXFILESPRODUCTS products */ 
int               *   isFrameScience;
cpl_frame         **  pframeSCIENCE;

cpl_parameterlist *   gparlist; 
cpl_frameset      *   gframelist;
cpl_propertylist  *   pHeader;

FILE *                pFITSFile;


amdlibERROR_MSG       errMsg;
static    amdlibDARK_DATA dark = {NULL};
static    amdlibRAW_DATA        rawData = {NULL};
amdlibSCIENCE_DATA    sky = {NULL};
amdlibSCIENCE_DATA    scienceData = {NULL};
amdlibP2VM_MATRIX     p2vm = {NULL};
amdlibPHOTOMETRY      photometry = {NULL}, imdPhot = {NULL};
amdlibWAVELENGTH      wave = {NULL}, imdWave = {NULL};
amdlibPISTON          opd = {NULL}, imdOpd = {NULL};
amdlibSPECTRUM       spectrum={NULL};
amdlibOI_TARGET       target = {NULL};
amdlibOI_ARRAY        array = {NULL};
amdlibVIS             vis = {NULL}, imdVis = {NULL};
amdlibVIS2            vis2 = {NULL}, imdVis2 = {NULL};
amdlibVIS3            vis3 = {NULL}, imdVis3 = {NULL};
amdlibSCIENCE_DATA    *skyPtr;
amdlibSCIENCE_DATA    *sciencePtr;
amdlibWAVEDATA        waveData;

int                   band;

/*-----------------------------------------------------------------------------
                            Functions prototypes
 -----------------------------------------------------------------------------*/

/* cpl related */
static int amber_SciCal_create(cpl_plugin *) ;
static int amber_SciCal_exec(cpl_plugin *) ;
static int amber_SciCal_destroy(cpl_plugin *) ;
static int amber_SciCal(cpl_parameterlist *, cpl_frameset *) ;
static void select_frames(cpl_parameterlist *parlist, cpl_frameset * framelist,
		int iProductNumber );

static void get_selection_param(double * x1_pst, double * x2_pst,
		double * x3_pst, int * isScience, cpl_frame * cur_frame);

amdlibCOMPL_STAT amdlibExtractVisESO( const char *badPixelFile,
		const char *flatFieldFile,
		const char *p2vmFile,
		const char *darkFile,
		const char *skyFile,
		const char *inputFile,
		/*		const char *outputFile,*/
		const int nbBinning,
		const amdlibERROR_TYPE errorType,
		const amdlibPISTON_ALGORITHM pistonType,
		const amdlibBOOLEAN noCheckP2vmId,
		const char * fctid);
cpl_propertylist * SciCalCreateProduct( const char * fctid, char * szRawFile );

/* amdlib */
/*
int amdlibIsJHKMode(amdlibRAW_DATA *data);
amdlibCOMPL_STAT amdlibExplodeJHKScienceData (amdlibSCIENCE_DATA *srcScienceData, 
                                              amdlibSCIENCE_DATA *dstScienceData, 
                                              amdlibERROR_MSG    errMsg);
 */


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

/* static struct { */
/*     /\* Inputs *\/ */
/*     int         bool_option ; */
/*     char        str_option[512] ; */

/*     /\* Outputs *\/ */
/*     double      qc_param ; */
/* } amber_SciCal_config ; */

static char amber_SciCal_man[] =
		"This recipe calculates Visibilities from a Pixel-To-Visibility-Matrix and Raw Files in 2- and 3-Telescope Mode (HL-version)\n"
		"\n";

/*-----------------------------------------------------------------------------
                                Functions code
 -----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
  @brief    Append the properties in one list to another
  @param    self   The PAF propertylist to append to
  @param    other  The propertylist whose elements are copied or NULL
  @return   CPL_ERROR_NONE or the relevant #_cpl_error_code_ on error

  If other is NULL or empty nothing happens

  Comments are copied as well, but it is (currently) undefined how this works
  for non-unique properties.

  In addition the hierarchical keys will be changed according to the PAF rules:

  No ESO as first part
  No blank separator but a .
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code amber_propertylist_append(cpl_propertylist * self,
		const cpl_propertylist * other)
{

	int i, c;
	char szPAF[2048];
	char szTMP[2048];

	if (other == NULL) return CPL_ERROR_NONE;

	/*visir_assure_code(self, CPL_ERROR_NULL_INPUT);*/

	for (i=0; i < cpl_propertylist_get_size(other); i++)
	{
		const cpl_property * prop = cpl_propertylist_get((cpl_propertylist *)
				other, i);
		const char * name    = cpl_property_get_name(prop);
		/*const char * comment = cpl_property_get_comment(prop);*/

		cpl_error_code err;

		/* Change the key to PAF syntax */
		strcpy( szPAF, name );

		/* Get rid of ESO (HAR, what a joke!) */
		if( !strncmp( szPAF, "ESO", 3 ) )
		{
			strcpy( szTMP, &szPAF[4] );
			strcpy( szPAF, szTMP );
		}

		/* Substitute spaces by points (YEAH!) */
		for( c=0; c<(int)strlen(szPAF); c++ )
			if( szPAF[c] == ' ' )
				szPAF[c] = '.';

		strcpy( (char *)name, szPAF );

		/* Append prop to self */

		switch (cpl_property_get_type(prop)) {
		case CPL_TYPE_CHAR:
			err = cpl_propertylist_append_char(self, name,
					cpl_property_get_char(prop));
		case CPL_TYPE_BOOL:
			err = cpl_propertylist_append_bool(self, name,
					cpl_property_get_bool(prop));
			break;
		case CPL_TYPE_INT:
			err = cpl_propertylist_append_int(self, name,
					cpl_property_get_int(prop));
			break;
		case CPL_TYPE_LONG:
			err = cpl_propertylist_append_long(self, name,
					cpl_property_get_long(prop));
			break;
		case CPL_TYPE_FLOAT:
			err = cpl_propertylist_append_float(self, name,
					cpl_property_get_float(prop));
			break;
		case CPL_TYPE_DOUBLE:
			err = cpl_propertylist_append_double(self, name,
					cpl_property_get_double(prop));
			break;
		case CPL_TYPE_STRING:
			err = cpl_propertylist_append_string(self, name,
					cpl_property_get_string(prop));
			break;

			/* Avoid compiler warnings but do nothing */
		case CPL_TYPE_FLAG_ARRAY:
		case CPL_TYPE_INVALID:
		case CPL_TYPE_UCHAR:
		case CPL_TYPE_UINT:
		case CPL_TYPE_ULONG:
		case CPL_TYPE_POINTER:
		case CPL_TYPE_FLOAT_COMPLEX:
		case CPL_TYPE_DOUBLE_COMPLEX:
		case CPL_TYPE_UNSPECIFIED:
			/*case CPL_TYPE_COMPLEX: not anymode in CPL 3.0 */
			break;
			/*default:
            visir_assure_code(0, CPL_ERROR_UNSUPPORTED_MODE);*/
		}

		/*visir_assure_code(!err, err);

        if (comment && cpl_propertylist_set_comment(self, name, comment))
            visir_assure_code(0, cpl_error_get_code());*/
	}

	return CPL_ERROR_NONE;
}


cpl_propertylist * SciCalCreateProduct( const char * fctid, char * szRawFile )
				{
	int  iStatus = 0;
	char szMessage[1024];
	cpl_table        * pTable;
	cpl_propertylist * pTableHeader;
	int                iTable;
	int                iError;

	cpl_frameset * frameSetTmp;
	cpl_frame    * frameTmp;
	/*cpl_propertylist *  pHeader;*/

	/* For DFS fill Header function later */;
	/* pHeader = cpl_propertylist_new(); */
	/*pFrame  = cpl_frame_new();*/

	/* Now write the OiFile as Productfilename */
	sprintf( szFilenameProduct, "amber_%04d.fits", iProductNumber );



	pframeSCIENCE[iProductNumber] = cpl_frame_new();

	if( pframeSCIENCE[iProductNumber] )
	{
		cpl_frame_set_filename( pframeSCIENCE[iProductNumber], szFilenameProduct );
		cpl_frame_set_type( pframeSCIENCE[iProductNumber], CPL_FRAME_TYPE_TABLE );
		if( isFrameScience[i] )
			cpl_frame_set_tag( pframeSCIENCE[iProductNumber], "SCIENCE_REDUCED" );
		else
			cpl_frame_set_tag( pframeSCIENCE[iProductNumber], "CALIB_REDUCED" );

		cpl_frame_set_group( pframeSCIENCE[iProductNumber], CPL_FRAME_GROUP_PRODUCT );
		cpl_frame_set_level( pframeSCIENCE[iProductNumber], CPL_FRAME_LEVEL_FINAL );
	}
	else
	{
		cpl_msg_info( fctid, "No memory for product frame." );
		iStatus = 15;
	}

	/*
    sprintf( szMessage, "cpl_frame_set (\"%s\")", cpl_frame_get_filename(pframeSCIENCE[iProductNumber])  ); 
    cpl_msg_info( fctid, "%s", szMessage );   
	 */

	/*
	 * Create the Product file, start with filling the header
	 *
	 * Attention: for the time of this workaround for cpl 3D tables the amdlib must
	 * be patched to NOT create OWN files, but APPEND to existing ones!!
	 *
	 * see comment below
	 *
	 */


	/*
	 * Workaround for cpl_dfs_setup_product_header picking the wrong Header in this CPL release and
	 * also might pick the wrong in the future! It uses the first RAW frame, but this recipe can handle
	 * many raw frames. Hence:
	 *
	 * Read the Header of the RAW file to be written as a product and send it to the function
	 */
	pHeader = cpl_propertylist_load(  szRawFile, 0 );
	sprintf( szMessage, "Extracting product header from file %s for target named %s [%s].",  szRawFile,  cpl_propertylist_get_string( pHeader, "ESO OBS NAME" ), cpl_error_get_message()  );
	cpl_msg_info( fctid, "%s", szMessage );

	/*The ARCFILE is needed for the paf file in the selector and trf products*/
	if (cpl_propertylist_has(pHeader, "ARCFILE") == 1)
	{
		cpl_propertylist_append_string(pHeader,"ESO QC ARC",
				(cpl_propertylist_get_string(pHeader, "ARCFILE")));
	}

	/* Create a set of frames with just this frame, so header will be correct */
	frameSetTmp = cpl_frameset_new();
	frameTmp    = cpl_frame_new();

	cpl_frame_set_filename( frameTmp, szRawFile );
	cpl_frame_set_type( frameTmp, CPL_FRAME_TYPE_TABLE );
	if( isFrameScience[iProductNumber] )
		cpl_frame_set_tag( frameTmp, "AMBER_SCIENCE" );
	else
		cpl_frame_set_tag( frameTmp, "AMBER_CALIB" );
	cpl_frame_set_group( frameTmp, CPL_FRAME_GROUP_RAW );
	cpl_frame_set_level( frameTmp, CPL_FRAME_LEVEL_NONE );
	cpl_frameset_insert( frameSetTmp, frameTmp );




	/* Add the necessary DFS fits header information to the product */
#if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
	if( cpl_dfs_setup_product_header(  pHeader,
			pframeSCIENCE[iProductNumber],
			frameSetTmp,
			gparlist,
			"amber_SciCal", /* const char *  recid,  */
			PACKAGE "/" PACKAGE_VERSION, /* const char *  pipeline_id,  */
			PRODUCT_DID,  /* const char *  dictionary_id */
			NULL
	)  != CPL_ERROR_NONE )
	{
		/* Error */
		sprintf( szMessage, "Error in setting up the product header." );
		cpl_msg_info( fctid, "%s", szMessage );
		iStatus = 16;
	}
#else 
	if( cpl_dfs_setup_product_header(  pHeader,
			pframeSCIENCE[iProductNumber],
			frameSetTmp,
			gparlist,
			"amber_SciCal", /* const char *  recid,  */
			PACKAGE "/" PACKAGE_VERSION, /* const char *  pipeline_id,  */
			PRODUCT_DID  /* const char *  dictionary_id */
	)  != CPL_ERROR_NONE )
	{
		/* Error */
		sprintf( szMessage, "Error in setting up the product header." );
		cpl_msg_info( fctid, "%s", szMessage );
		iStatus = 16;
	}
#endif   



	sprintf( szMessage, "Header from file %s for target named %s [%s].",  szRawFile,  cpl_propertylist_get_string( pHeader, "ESO OBS NAME" ), cpl_error_get_message()  );
	cpl_msg_info( fctid, "%s", szMessage );

	/* Destroy tmpFrameset and implicitly its contents */
	cpl_frameset_delete( frameSetTmp );
	/*cpl_frame_delete( frameTmp );*/

	/* Write the product including proper DFS header*/

	pTable       = NULL;
	pTableHeader = NULL;
	iTable = 1;
	iError = CPL_ERROR_NONE;

	sprintf( szMessage, "Creating product file%s...", szFilenameProduct );
	cpl_msg_info( fctid, "%s", szMessage );

	/*
	 * Workaround:
	 * CPL cannot handle 3D-tables, hence, write just the header to a fits file and let
	 * the amdlibWriteOI just append the data (and not create a whole file as intended by amdlib design
	 * see Module amdlibWriteOI.c
	 */


	return pHeader;
				}

amdlibCOMPL_STAT amdlibExtractVisESO( const char *badPixelFile,
		const char *flatFieldFile,
		const char *p2vmFile,
		const char *darkFile,
		const char *skyFile,
		const char *inputFile,
		/*		const char *outputFile,*/
		const int nbBinning,
		const amdlibERROR_TYPE errorType,
		const amdlibPISTON_ALGORITHM pistonType,
		const amdlibBOOLEAN noCheckP2vmId,
		const char * fctid
)
{


	char szCommand[1024];
	const char * pszARCFILE;

	amdlibCOMPL_STAT Status = amdlibSUCCESS;

	int  i;
	char szMessage[1024];

	amdlibCPT_VIS_OPTIONS visOptions = {nbBinning, errorType, pistonType,
			noCheckP2vmId, amdlibNO_FRAME_SEL, 1.0};


	/* Product FITS QC header */
	cpl_propertylist * qc_properties = NULL;
	amdlibBAND_DESC *bandDesc;
	int   iFrame                 = 0;
	int   iFrame_GT_SNR2         = 0;
	float fFrame_GT_SNR2_Percent = 0.F;
	AmPaf            * qc            = NULL;
	cpl_propertylist * qclog         = NULL;
	cpl_propertylist * qcFromProduct = NULL;
	cpl_propertylist * qcFromRawfile = NULL;



	amdlibLogTrace("amdlibExtractVisESO()\n");


	/* Load bad pixel map */
	sprintf( szMessage, "Loading BAD PIXEL MAP %s ...", badPixelFile );
	cpl_msg_info( fctid, "%s", szMessage );

	if( amdlibLoadBadPixelMap( badPixelFile, errMsg) != amdlibSUCCESS)
	{
		printf ("Could not load bad pixel map '%s'\n", badPixelFile);
		cpl_msg_info( fctid, "%s", errMsg );
		return (amdlibFAILURE);
	}

	/* Load flat field map */
	sprintf( szMessage, "Loading FLAT FIELD %s ...", flatFieldFile );
	cpl_msg_info( fctid, "%s", szMessage );

	if( amdlibLoadFlatFieldMap( flatFieldFile, errMsg)!=amdlibSUCCESS)
	{
		printf ("Could not load Flat Field file '%s'n", flatFieldFile);
		cpl_msg_info( fctid, "%s", errMsg );
		return (amdlibFAILURE);
	}

	/* Load P2VM */
	sprintf( szMessage, "Loading P2VM %s ...", p2vmFile );
	cpl_msg_info( fctid, "%s", szMessage );

	if( amdlibLoadP2VM( p2vmFile, &p2vm, errMsg) == amdlibFAILURE)
	{
		printf ("Could not load P2VM file '%s'\n", p2vmFile);
		cpl_msg_info( fctid, "%s", errMsg );
		return (amdlibFAILURE);
	}

	/* Retrieve wavedata */
	if( amdlibGetWaveDataFromP2vm( &p2vm, &waveData, errMsg ) != amdlibSUCCESS)
	{
		printf ("Could not get wave data from P2VM file '%s'\n", p2vmFile);
		cpl_msg_info( fctid, "%s", errMsg );
		return (amdlibFAILURE);
	}

	/* Load bias file */
	if (strlen(darkFile) != 0)
	{
		sprintf( szMessage, "Loading DARK (BIAS) %s ...\n", darkFile );
		cpl_msg_info( fctid, "%s", szMessage );

		if (amdlibLoadRawData(darkFile, &rawData, errMsg) != amdlibSUCCESS)
		{
			cpl_msg_error(cpl_func,"Could not load bias file '%s'", darkFile);
			return (amdlibFAILURE);
		}
		/* Compute pixel bias map */
		sprintf( szMessage, "Computing PIXEL BIAS MAP..." );
		cpl_msg_info( fctid, "%s", szMessage );

		if (amdlibGenerateDarkData(&rawData, &dark,
				errMsg) != amdlibSUCCESS)
		{
			printf ("Could not generate pixel bias map\n");
			cpl_msg_info( fctid, "%s", errMsg );
			return (amdlibFAILURE);
		}
		amdlibReleaseRawData(&rawData);
	}
	else
	{
		sprintf( szMessage, "No PIXEL BIAS MAP available due to no DARK file." );
		cpl_msg_info( fctid, "%s", szMessage );

		/* Load data file so that the false bias mimics its structure */
		i=6;
		sprintf( szMessage, "Getting PIXEL BIAS MAP from raw %s ...", inputFile );
		cpl_msg_info( fctid, "%s", szMessage );
		if (amdlibLoadRawData(inputFile, &rawData, errMsg) != amdlibSUCCESS)
		{
			sprintf( szMessage, "Could not load raw data file '%s'", inputFile);
			cpl_msg_info( fctid, "%s", errMsg );
			return (amdlibFAILURE);
		}
		amdlibSetDarkData( &rawData,  &dark, 0.0, amdlibTYPICAL_RON , errMsg);
		amdlibReleaseRawData(&rawData);
	}

	/* Load sky file */
	if (strlen(skyFile) != 0)
	{
		printf ("Loading %s ...\n", skyFile);
		if (amdlibLoadRawData(skyFile, &rawData, errMsg) != amdlibSUCCESS)
		{
			printf ("Could not load sky file '%s'\n", skyFile);
			cpl_msg_info( fctid, "%s", errMsg );
			return (amdlibFAILURE);
		}
		/* Equalize raw data */
		if( amdlibCalibrateRawData( &dark, &rawData, errMsg) !=amdlibSUCCESS )
		{
			cpl_msg_info( fctid, "%s", errMsg );
			return (amdlibFAILURE);
		}

		/* Equalize raw map */
		if (amdlibRawData2ScienceData(&rawData, &waveData, &sky, amdlibTRUE, errMsg) != amdlibSUCCESS)
		{
			printf ("Could not get science data\n");
			cpl_msg_info( fctid, "%s", errMsg );
			return (amdlibFAILURE);
		}
		/* if in JHK Mode, split Science Data in rows accordingly */
		skyPtr = &sky;
		amdlibReleaseRawData(&rawData);

	}
	else
	{
		sprintf( szMessage, "No SKY will be  used...\n" );
		cpl_msg_info( fctid, "%s", szMessage );
		skyPtr = NULL;
	}

	/* Load data file */
	sprintf( szMessage, "Loading RawData %s ...", inputFile );
	cpl_msg_info( fctid, "%s", szMessage );
	if (amdlibLoadRawData(inputFile, &rawData, errMsg) != amdlibSUCCESS)
	{
		sprintf( szMessage, "Could not load raw data file '%s'", inputFile );
		cpl_msg_info( fctid, "%s", szMessage );
		cpl_msg_info( fctid, "%s", errMsg );
		return (amdlibFAILURE);
	}
	/* Equalize raw data */
	sprintf( szMessage, "Equalizing Raw Data." );
	cpl_msg_info( fctid, "%s", szMessage );
	if (amdlibCalibrateRawData(&dark, &rawData, errMsg) !=amdlibSUCCESS)
	{
		cpl_msg_info( fctid, "%s", errMsg );
		return (amdlibFAILURE);
	}

	/* Retrieve array information from raw data*/
	if (amdlibGetOiArrayFromRawData(&rawData, &array, errMsg) != amdlibSUCCESS)
	{
		sprintf( szMessage, "Warning -- Unable to retrieve OI_ARRAY information from input file");
		cpl_msg_info( fctid, "%s", szMessage );
		amdlibReleaseOiArray(&array);
	}

	/* retrieve target information */
	if (amdlibAllocateOiTarget(&target, 1) != amdlibSUCCESS)
	{
		printf ("Could not Allocate Target Structure\n");
		cpl_msg_info( fctid, "%s", szMessage );
		return (amdlibFAILURE);
	}
	if (amdlibGetOiTargetFromRawData(&rawData,&target) != amdlibSUCCESS)
	{
		printf ("Could not Add to Target Structure\n");
		cpl_msg_info( fctid, "%s", szMessage );
		return (amdlibFAILURE);
	}


	/* Produce science data */
	sprintf( szMessage, "Producing Science Data..." );
	cpl_msg_info( fctid, "%s", szMessage ); 

	if (amdlibRawData2ScienceData(&rawData, &waveData, &scienceData, amdlibFALSE,
			errMsg) != amdlibSUCCESS)
	{
		printf ("Could not get science data");
		cpl_msg_info( fctid, "%s", errMsg );
		return (amdlibFAILURE);
	}

	sciencePtr = &scienceData;
	amdlibReleaseRawData(&rawData);
	amdlibReleaseDarkData(&dark);


	for (band = amdlibJ_BAND; band <= amdlibK_BAND; band++)
	{
		int nbChannels;

		sprintf( szMessage, "Working on '%c' band", amdlibBandNumToStr(band));
		cpl_msg_info( fctid, "%s", szMessage );

		/* Compute visibilities */
		nbChannels = amdlibComputeVisibilities
				(/* Input */
						sciencePtr, &p2vm, &waveData, band, &visOptions,
						/* Output */
						&imdPhot, &imdVis, &imdVis2, &imdVis3, &imdWave, &imdOpd,
						errMsg);
		if (nbChannels == -1)
		{
			sprintf( szMessage, "Could NOT extract visibilities for '%c' band !", amdlibBandNumToStr(band));
			cpl_msg_info( fctid, "%s", szMessage );

			return (amdlibFAILURE);
		}
		else if (nbChannels == 0)
		{
			sprintf( szMessage, "There is no channel for '%c' band", amdlibBandNumToStr(band));
			cpl_msg_info( fctid, "%s", szMessage );
		}
		else
		{
			/* Print results */
			sprintf( szMessage, "Band: %c", amdlibBandNumToStr(band) );
			cpl_msg_info( fctid, "%s", szMessage );

			if (vis2.nbBases == 1)
			{
				sprintf( szMessage, "         VIS (err)");
				cpl_msg_info( fctid, "%s", szMessage );

				sprintf( szMessage, "%12.3f (%8.03g)\n", imdVis2.vis12, imdVis2.sigmaVis12 );
				cpl_msg_info( fctid, "%s", szMessage );
			}
			else
			{
				sprintf( szMessage, "Global Averaged Visibilities Squared (using all Frames):");
				cpl_msg_info( fctid, "%s", szMessage );

				sprintf( szMessage, "       VIS 12 (err)          VIS 23 (err)          VIS 31 (err)");
				cpl_msg_info( fctid, "%s", szMessage );
				sprintf( szMessage, "%12.3f(%8.03g)  %12.3f(%8.03g)  %12.3f(%8.03g)",
						imdVis2.vis12, imdVis2.sigmaVis12, imdVis2.vis12, imdVis2.sigmaVis12, imdVis2.vis31, imdVis2.sigmaVis31 );
				cpl_msg_info( fctid, "%s", szMessage );
				sprintf( szMessage, "AverageClosurePhase (deg)= %8.03g  (%8.03g)", imdVis3.averageClosure,imdVis3.averageClosureError );
				cpl_msg_info( fctid, "%s", szMessage );
			} /* 2 Tel or 3 Tel */

#ifdef NEVER_PERFORM_FRAME_SELECTION_USE_AMBER_SELECTOR_AFTERWARDS	 
			/* If required, perform frame selection */
			if (visOptions->frameSelectionType != amdlibNO_FRAME_SEL)
			{
				amdlibAllocateSelection(&selectedFrames, vis->nbFrames);
				/* Select 'good' frames depending on selection criterion */
				if (amdlibSelectFrames(vis, photometry,
						visOptions->frameSelectionType,
						visOptions->frameSelectionRatio,
						&selectedFrames,
						band, errMsg) != amdlibSUCCESS)
				{
					return -1;
				}

				/* Average visibilities, photometries and pistons on good frames */
				if (amdlibAverageVisibilities(photometry,
						vis, vis2, vis3,
						opd, band, wave,
						&selectedFrames, errMsg) != amdlibSUCCESS)
				{
					return -1;
				}

				amdlibReleaseSelection(&selectedFrames);
			}

			/*return nbChannelsInBand;    */
#endif





			/*---------------------------------------------------------------------------------------------------------------*/
			/* Creates Product File and sets up DFO compliant Header */
			qc_properties = SciCalCreateProduct( fctid, (char *)inputFile );

			/*---------------------------------------------------------------------------------------------------------------*/
			/* Calculating and Writing QC1 Parameters to header */
			cpl_msg_info(fctid, "Computing QC1 parameters ...");

			/* Get spectrum */
			if (amdlibGetSpectrumFromScienceData
					(sciencePtr, &waveData, &imdWave,
							&spectrum, errMsg) != amdlibSUCCESS)
			{
				amdlibLogError("Could not get spectrum from science "
						"data");
				amdlibLogErrorDetail(errMsg);
				return amdlibFAILURE;
			}


			if (nbChannels > 0){
				amber_qc(&imdWave, &imdVis, &imdVis2, &imdVis3, &spectrum, qc_properties,
						"uncal");
			}


			iFrame                 = 0;
			iFrame_GT_SNR2         = 0;
			fFrame_GT_SNR2_Percent = 0.F;

			sprintf( szMessage, "Number of Frames = %d",  imdVis.nbFrames );
			cpl_msg_info( fctid, "%s", szMessage );

			/* Count Frames with Fringe SNR greater than 2 */
			for(iFrame = 0; iFrame < imdVis.nbFrames; iFrame++)
				if( imdVis.table[iFrame].frgContrastSnr > 2 )
					iFrame_GT_SNR2++;

			/* Calc the Percentage of these Frames */
			fFrame_GT_SNR2_Percent = (float)iFrame_GT_SNR2 / (float)imdVis.nbFrames;

			sprintf( szMessage, "QC: %d of %d Frames having SNR greater than 2 = %0.2f percent", iFrame_GT_SNR2, imdVis.nbFrames, fFrame_GT_SNR2_Percent*100.0 );
			cpl_msg_info( fctid, "%s", szMessage );

			cpl_propertylist_append_long( qc_properties, "ESO QC FRAMES SELECTED SNRGT2", iFrame_GT_SNR2 );
			cpl_propertylist_set_comment( qc_properties, "ESO QC FRAMES SELECTED SNRGT2", "Frames selected with SNR greater than 2 ");

			cpl_propertylist_append_float( qc_properties, "ESO QC FRAMES SELECTED PERCENT", fFrame_GT_SNR2_Percent*100.0 );
			cpl_propertylist_set_comment( qc_properties, "ESO QC FRAMES SELECTED PERCENT", "Frames selected percentage");


			bandDesc = amdlibGetBandDescription(band);

			cpl_propertylist_append_string( qc_properties, "ESO QC BAND", bandDesc->name );
			cpl_propertylist_set_comment( qc_properties, "ESO QC BAND", "wavelength band ");

			/* Write the telescope station indices as QC parameters, for later easy plotting etc. */
			cpl_propertylist_append_int( qc_properties, "ESO QC STA1", array.element[0].stationIndex );
			cpl_propertylist_set_comment( qc_properties, "ESO QC STA1", "index of station ");
			cpl_propertylist_append_int( qc_properties, "ESO QC STA2", array.element[1].stationIndex );
			cpl_propertylist_set_comment( qc_properties, "ESO QC STA2", "index of station ");

			if( array.nbStations == 3 )
			{
				cpl_propertylist_append_int( qc_properties, "ESO QC STA3", array.element[2].stationIndex );
				cpl_propertylist_set_comment( qc_properties, "ESO QC STA3", "index of station ");
			}

			/*Adding the JMMC acknowledgements*/
			amber_JMMC_acknowledgement(pHeader);

			if (CPL_ERROR_NONE != cpl_image_save(NULL, szFilenameProduct, CPL_BPP_16_SIGNED, pHeader, CPL_IO_DEFAULT ))
			{
				cpl_msg_error(cpl_func,"Error in cpl_image_save");
			}


			/*---------------------------------------------------------------------------------------------------------------*/
			/* Writes instrument scientific data */

			if (strlen(szFilenameProduct) != 0)
			{
				sprintf ( szMessage, "Now writing Scientific Data to %s...", szFilenameProduct );
				cpl_msg_info( fctid, "%s", szMessage );








				if( amdlibSaveOiFile( szFilenameProduct, NULL,
						&array, &target,
						&imdPhot, &imdVis, &imdVis2,
						&imdVis3, &imdWave,
						&imdOpd,&spectrum, errMsg
				) != amdlibSUCCESS)
				{
					Status = amdlibFAILURE;
					sprintf ( szMessage, "ERROR saving Scientific Data to %s.", szFilenameProduct );
					cpl_msg_info( fctid, "%s", szMessage );

				}
				else
				{
					sprintf ( szMessage, "Scientific Data %s saved successfully.", szFilenameProduct );
					cpl_msg_info( fctid, "%s", szMessage );

					/* Now copy the file to tmp to be able to plot the files after the
	         originals are renamed by ESOREX 
					 */
					//sprintf( szCommand, "cp %s /tmp/%s", szFilenameProduct, szFilenameProduct );
					//system( szCommand );
				}
			} /* if product filname */


			/*---------------------------------------------------------------------------------------------------------------*/
			/* Writing QC1 Parameters to log */
			qc            = NULL;
			qclog         = NULL;
			qcFromProduct = NULL;
			qcFromRawfile = NULL;


			qcFromRawfile= cpl_propertylist_load(inputFile, 0 );

			qc = amber_qclog_open(iProductNumber);

			if( qc )
			{
				cpl_msg_info(fctid, "QC1 log open ...");

				qclog = amber_paf_get_properties( qc );

				/* Read original ARCFILE entry and copy to PAF-File */
				pszARCFILE = cpl_propertylist_get_string( qcFromRawfile, "ARCFILE" );

				/* Add mandatory keys */
				cpl_propertylist_append_string( qclog, "ARCFILE", pszARCFILE );

				/* Read the whole header including QC parameters */
				qcFromProduct = cpl_propertylist_load( szFilenameProduct, 0 );

				/* copy to PAF */
				amber_propertylist_append( qclog, qcFromProduct);
				cpl_propertylist_delete(qcFromProduct);

				/* Finished... */
				cpl_msg_info(fctid, "QC1 finished.");
				amber_qclog_close(qc);


			} /* if qc */

			cpl_propertylist_delete( qc_properties );
			cpl_propertylist_delete( qcFromRawfile );
			iProductNumber++;
		} /* Write the product */
	} /* all bands */


	amdlibReleaseScienceData(sciencePtr);
	if (skyPtr != NULL)
	{
		amdlibReleaseScienceData(skyPtr);
	}
	amdlibReleaseP2VM(&p2vm);
	amdlibReleaseVis(&vis);
	amdlibReleaseVis2(&vis2);
	amdlibReleaseVis3(&vis3);
	amdlibReleaseOiArray(&array);
	amdlibReleaseWavelength(&wave);
	amdlibReleasePiston(&opd);
	amdlibReleasePhotometry(&photometry);
	amdlibReleaseOiTarget(&target);

	amdlibReleasePhotometry(&imdPhot);
	amdlibReleaseVis(&imdVis);
	amdlibReleaseVis2(&imdVis2);
	amdlibReleaseVis3(&imdVis3);
	amdlibReleaseWavelength(&imdWave);
	amdlibReleasePiston(&imdOpd);
	amdlibReleaseSpectrum(&spectrum);

	return (Status);
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Build the list of available plugins, for this module. 
  @param    list    the plugin list
  @return   0 if everything is ok

  This function is exported.
 */
/*----------------------------------------------------------------------------*/
int cpl_plugin_get_info(cpl_pluginlist * list)
{
	cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe)) ;
	cpl_plugin  *   plugin = &recipe->interface ;

	cpl_plugin_init(plugin,
			CPL_PLUGIN_API,
			AMBER_BINARY_VERSION,
			CPL_PLUGIN_TYPE_RECIPE,
			"amber_SciCal",
			"AMBER Science and Calibration Recipe",
			amber_SciCal_man,
			"Tom Licha",
			PACKAGE_BUGREPORT,
			"GP",
			amber_SciCal_create,
			amber_SciCal_exec,
			amber_SciCal_destroy) ;

	cpl_pluginlist_append(list, plugin) ;

	return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Setup the recipe options    
  @param    plugin  the plugin
  @return   0 if everything is ok

  Create the recipe instance and make it available to the application using the 
  interface. 
 */
/*----------------------------------------------------------------------------*/
static int amber_SciCal_create(cpl_plugin * plugin)
{
	cpl_recipe * recipe = (cpl_recipe *)plugin ;
	cpl_parameter * p ;

	/* Create the parameters list in the cpl_recipe object */
	recipe->parameters = cpl_parameterlist_new() ;

	/* Fill the parameters list */

	/* binning int */
	p = cpl_parameter_new_value("amber.amber_SciCal.int_binning",
			CPL_TYPE_INT, "Number of Frames to be averaged per Visibility", "amber.amber_SciCal", 1 ) ;
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "binning") ;
	cpl_parameterlist_append(recipe->parameters, p) ;


	p = cpl_parameter_new_value("amber.amber_SciCal.selectPlusTrf",
			CPL_TYPE_BOOL, "select good visibilities and try to calculate "
			"the transfer function", "amber.amber_SciCal", TRUE) ;
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "selectPlusTrf") ;
	cpl_parameterlist_append(recipe->parameters, p) ;


	//
	//
	p = cpl_parameter_new_value("amber.amber_SciCal.activate_BEAUTIFY_PISTON", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",TRUE);
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_BEAUTIFY_PISTON");
	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_CHISQUARE_LIMIT", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_CHISQUARE_LIMIT");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_MAX_PISTON_ERROR", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_MAX_PISTON_ERROR");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_SHIFT_WLENTABLE", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_SHIFT_WLENTABLE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	p = cpl_parameter_new_value("amber.amber_SciCal.activate_MIN_PHOTOMETRY", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",TRUE);
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_MIN_PHOTOMETRY");
	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_CORRECT_OPD0", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_CORRECT_OPD0");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_LINEARIZE_P2VM_PHASE", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_LINEARIZE_P2VM_PHASE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_NORMALIZE_P2VM", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_NORMALIZE_P2VM");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_NO_FUDGE", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_NO_FUDGE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_NO_BIAS", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_NO_BIAS");
	//	cpl_parameterlist_append(recipe->parameters, p);
	p = cpl_parameter_new_value("amber.amber_SciCal.activate_DROP", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_DROP");
	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_NORMALIZE_SPECTRUM", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_NORMALIZE_SPECTRUM");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_BOXCARSMOOTH_P2VM_PHASE", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_BOXCARSMOOTH_P2VM_PHASE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_GAUSSSMOOTH_P2VM_PHASE", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_GAUSSSMOOTH_P2VM_PHASE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_AUTO_BADPIXEL", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_AUTO_BADPIXEL");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_MAX_PISTON_EXCURSION", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_MAX_PISTON_EXCURSION");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_GLOBAL_PHOTOMETRY", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_GLOBAL_PHOTOMETRY");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_USE_GAIN", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_USE_GAIN");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_ZAP_JHK_DISCONTINUTIES", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_ZAP_JHK_DISCONTINUTIES");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.activate_AUTO_SHIFT_JHK", CPL_TYPE_BOOL, "TBD", "amber.amber_SciCal",FALSE);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"activate_AUTO_SHIFT_JHK");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//
	//
	p = cpl_parameter_new_value("amber.amber_SciCal.value_BEAUTIFY_PISTON", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",1.0);
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_BEAUTIFY_PISTON");
	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_CHISQUARE_LIMIT", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_CHISQUARE_LIMIT");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_MAX_PISTON_ERROR", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_MAX_PISTON_ERROR");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_SHIFT_WLENTABLE", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_SHIFT_WLENTABLE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	p = cpl_parameter_new_value("amber.amber_SciCal.value_MIN_PHOTOMETRY", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_MIN_PHOTOMETRY");
	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_CORRECT_OPD0", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_CORRECT_OPD0");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_LINEARIZE_P2VM_PHASE", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_LINEARIZE_P2VM_PHASE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_NORMALIZE_P2VM", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_NORMALIZE_P2VM");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_NO_FUDGE", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_NO_FUDGE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_NO_BIAS", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_NO_BIAS");
	//	cpl_parameterlist_append(recipe->parameters, p);
	p = cpl_parameter_new_value("amber.amber_SciCal.value_DROP", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_DROP");
	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_NORMALIZE_SPECTRUM", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_NORMALIZE_SPECTRUM");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_BOXCARSMOOTH_P2VM_PHASE", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_BOXCARSMOOTH_P2VM_PHASE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_GAUSSSMOOTH_P2VM_PHASE", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_GAUSSSMOOTH_P2VM_PHASE");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_AUTO_BADPIXEL", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_AUTO_BADPIXEL");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_MAX_PISTON_EXCURSION", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_MAX_PISTON_EXCURSION");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_GLOBAL_PHOTOMETRY", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_GLOBAL_PHOTOMETRY");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_USE_GAIN", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_USE_GAIN");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_ZAP_JHK_DISCONTINUTIES", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_ZAP_JHK_DISCONTINUTIES");
	//	cpl_parameterlist_append(recipe->parameters, p);
	//	p = cpl_parameter_new_value("amber.amber_SciCal.value_AUTO_SHIFT_JHK", CPL_TYPE_DOUBLE, "TBD", "amber.amber_SciCal",0.0);
	//	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"value_AUTO_SHIFT_JHK");
	//	cpl_parameterlist_append(recipe->parameters, p);




	/* Return */
	return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Execute the plugin instance given by the interface
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_SciCal_exec(cpl_plugin * plugin)
{
	cpl_recipe * recipe = (cpl_recipe *)plugin ;
	return amber_SciCal(recipe->parameters, recipe->frames) ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Destroy what has been created by the 'create' function
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_SciCal_destroy(cpl_plugin * plugin)
{
	cpl_recipe  *   recipe = (cpl_recipe *)plugin ;
	cpl_parameterlist_delete(recipe->parameters) ;
	return 0 ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Get the command line options and execute the data reduction
  @param    parlist     the parameters list
  @param    framelist   the frames list
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_SciCal(
		cpl_parameterlist     *   parlist,
		cpl_frameset    *   framelist)
{
	/* CPL structures */
	/*  cpl_frameset  * cur_set;*/
	cpl_frame     * cur_frame;
	cpl_parameter * cur_param;

	int    selectPlusTrf=0;
	char   szMessage[1024];
	char * pszFilename;
	char * pszFileTag;
	char   szFilenameOI[512];

	char   szFilenameP2VM[512];
	char   szFilenameSKY[512];
	char   szFilenameDARK[512];
	char   szFilenameBADPIX[512];
	char   szFilenameFLAT[512];

	int  iStatus = 0;

	int  iFrameCount       = 0;
	int  iLoadedFrameCount = 0;
	int  iReduction        = 0;
	FILE * fpTmp = NULL;
	cpl_frameset_iterator * it = NULL;

	/*int  iOnlyWriteOne     = 0;*/

	const char      *   fctid = "amber_SciCal" ;
	//FILE * fp = NULL;
	amber_dfs_set_groups(framelist);



	if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_BEAUTIFY_PISTON")))          {amdlibSetUserPref(amdlibBEAUTIFY_PISTON, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_BEAUTIFY_PISTON")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_CHISQUARE_LIMIT")))          {amdlibSetUserPref(amdlibCHISQUARE_LIMIT, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_CHISQUARE_LIMIT")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_SHIFT_WLENTABLE")))          {amdlibSetUserPref(amdlibSHIFT_WLENTABLE, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_SHIFT_WLENTABLE")));}
	if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_MIN_PHOTOMETRY")))           {amdlibSetUserPref(amdlibMIN_PHOTOMETRY, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_MIN_PHOTOMETRY")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_CORRECT_OPD0")))             {amdlibSetUserPref(amdlibCORRECT_OPD0, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_CORRECT_OPD0")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_LINEARIZE_P2VM_PHASE")))     {amdlibSetUserPref(amdlibLINEARIZE_P2VM_PHASE, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_LINEARIZE_P2VM_PHASE")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_NORMALIZE_P2VM")))           {amdlibSetUserPref(amdlibNORMALIZE_P2VM, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_NORMALIZE_P2VM")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_NO_FUDGE")))                 {amdlibSetUserPref(amdlibNO_FUDGE, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_NO_FUDGE")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_NO_BIAS")))                  {amdlibSetUserPref(amdlibNO_BIAS, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_NO_BIAS")));}
	if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_DROP")))                     {amdlibSetUserPref(amdlibDROP, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_DROP")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_NORMALIZE_SPECTRUM")))       {amdlibSetUserPref(amdlibNORMALIZE_SPECTRUM, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_NORMALIZE_SPECTRUM")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_BOXCARSMOOTH_P2VM_PHASE")))  {amdlibSetUserPref(amdlibBOXCARSMOOTH_P2VM_PHASE, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_BOXCARSMOOTH_P2VM_PHASE")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_GAUSSSMOOTH_P2VM_PHASE")))   {amdlibSetUserPref(amdlibGAUSSSMOOTH_P2VM_PHASE, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_GAUSSSMOOTH_P2VM_PHASE")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_AUTO_BADPIXEL")))            {amdlibSetUserPref(amdlibAUTO_BADPIXEL, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_AUTO_BADPIXEL")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_GLOBAL_PHOTOMETRY")))        {amdlibSetUserPref(amdlibGLOBAL_PHOTOMETRY, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_GLOBAL_PHOTOMETRY")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_USE_GAIN")))                 {amdlibSetUserPref(amdlibUSE_GAIN, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_USE_GAIN")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_ZAP_JHK_DISCONTINUTIES")))   {amdlibSetUserPref(amdlibZAP_JHK_DISCONTINUTIES, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_ZAP_JHK_DISCONTINUTIES")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_AUTO_SHIFT_JHK")))           {amdlibSetUserPref(amdlibAUTO_SHIFT_JHK, cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_AUTO_SHIFT_JHK")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_MAX_PISTON_ERROR")))         {amdlibSetUserPref(amdlibMAX_PISTON_ERROR, 1000*cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_MAX_PISTON_ERROR")));}
	//if (cpl_parameter_get_bool(cpl_parameterlist_find(parlist, "amber.amber_SciCal.activate_MAX_PISTON_EXCURSION")))     {amdlibSetUserPref(amdlibMAX_PISTON_EXCURSION, 1000*cpl_parameter_get_double(cpl_parameterlist_find(parlist, "amber.amber_SciCal.value_MAX_PISTON_EXCURSION")));};






	gframelist = framelist;
	gparlist   = parlist;

	cpl_msg_info( fctid, "Start of DataReduction");

	strcpy( szFilenameOI, "OiVisibilities.fits" );

	strcpy( szFilenameP2VM, "" );
	strcpy( szFilenameSKY, "" );
	strcpy( szFilenameDARK, "" );
	strcpy( szFilenameBADPIX, "" );
	strcpy( szFilenameFLAT, "" );



	szFilenameSCIENCE = cpl_calloc(MAXFILESPRODUCTS, sizeof(char*));
	isFrameScience= cpl_calloc(MAXFILESPRODUCTS, sizeof(int));
	pframeSCIENCE = cpl_calloc(MAXFILESPRODUCTS, sizeof(cpl_frame*));

	for(i=0;i<MAXFILESPRODUCTS;i++)
	{
		szFilenameSCIENCE[i]= cpl_calloc(512, sizeof(char));
	}


	/* log of the fprint of the amdlib */

	//fp = freopen( "amdlib_SciCal.log", "w", stdout );

	/* Set some defaults, should be input parameters later! */
	errorType  = amdlibSTATISTICAL_ERROR;
	pistonType = amdlibITERATIVE_PHASOR;
	/*pistonType = amdlibUNWRAPPED_PHASE;*/

	cur_param = cpl_parameterlist_find( parlist, "amber.amber_SciCal.int_binning" );
	iBinningOfFrames = cpl_parameter_get_int( cur_param );

	cur_param=cpl_parameterlist_find(parlist,
			"amber.amber_SciCal.selectPlusTrf");
	selectPlusTrf=cpl_parameter_get_bool(cur_param);


	if( iBinningOfFrames == 0 )
		iBinningOfFrames = 99999; /* Binning of all Frames */

	sprintf ( szMessage, "BINNING of %d frames will be used", iBinningOfFrames );
	cpl_msg_info( fctid, "%s", szMessage );

	if( iBinningOfFrames == 1 )
	{
		errorType = amdlibTHEORETICAL_ERROR;
		sprintf ( szMessage, "ERROR BAR calculation with amdlibTHEORETICAL_ERROR will be used for BINNING of 1 frame." );
		cpl_msg_info( fctid, "%s", szMessage );
	}


	/* BadPix and FlatField P2VM are needed as first Frames - the Rest can be loaded in random Order later */
	cur_frame = cpl_frameset_find( framelist, "AMBER_FLATFIELD" );

	if( cur_frame )
	{
		/* Get Filename and Classification Tag */
		pszFilename = (char *)cpl_frame_get_filename( cur_frame );
		pszFileTag  = (char *)cpl_frame_get_tag( cur_frame );

		strcpy( szFilenameFLAT, pszFilename );

		sprintf ( szMessage, "FLAT FIELD identified %s", pszFilename );
		cpl_msg_info( fctid, "%s", szMessage );
	}

	cur_frame = cpl_frameset_find( framelist, "AMBER_BADPIX" );

	if( cur_frame )
	{
		/* Get Filename and Classification Tag */
		pszFilename = (char *)cpl_frame_get_filename( cur_frame );
		pszFileTag  = (char *)cpl_frame_get_tag( cur_frame );

		strcpy( szFilenameBADPIX, pszFilename );

		sprintf ( szMessage, "BAD PIXEL MAP identified %s", pszFilename );
		cpl_msg_info( fctid, "%s", szMessage );
	}

	/* Try to load the optional SKY frame */
	cur_frame = cpl_frameset_find( framelist, "AMBER_SKY" );

	if (cur_frame==NULL){
		cur_frame = cpl_frameset_find( framelist, "AMBER_SKY_CALIB" );
	}

	if (cur_frame==NULL){
		cur_frame = cpl_frameset_find( framelist, "AMBER_SKY_SCIENCE" );
	}

	if( cur_frame )
	{
		/* Get Filename and Classification Tag */
		pszFilename = (char *)cpl_frame_get_filename( cur_frame );
		pszFileTag  = (char *)cpl_frame_get_tag( cur_frame );

		strcpy( szFilenameSKY, pszFilename );

		sprintf ( szMessage, "SKY identified %s", pszFilename );
		cpl_msg_info( fctid, "%s", szMessage );

	}


	/* Loading either 2 or 3 Telescope P2VM */
	cur_frame = cpl_frameset_find( framelist, "AMBER_P2VM" );

	if( cur_frame )
	{
		/* Get Filename and Classification Tag */
		pszFilename = (char *)cpl_frame_get_filename( cur_frame );
		pszFileTag  = (char *)cpl_frame_get_tag( cur_frame );

		strcpy( szFilenameP2VM, pszFilename );

		sprintf ( szMessage, "P2VM identified %s", pszFilename );
		cpl_msg_info( fctid, "%s", szMessage );

	}
	else
	{
		cur_frame = cpl_frameset_find( framelist, "P2VM_REDUCED" );

		if( cur_frame )
		{
			/* Get Filename and Classification Tag */
			pszFilename = (char *)cpl_frame_get_filename( cur_frame );
			pszFileTag  = (char *)cpl_frame_get_tag( cur_frame );

			strcpy( szFilenameP2VM, pszFilename );

			sprintf ( szMessage, "P2VM identified %s", pszFilename );
			cpl_msg_info( fctid, "%s", szMessage );
		}
	}

	/*
     In case no P2VM was sent (i.e. during online pipeline run) then
     rely on the latest P2VM from tmp dir
	 */
	if( !cur_frame )
	{
		/* PIPELINE will not send the P2VM. Try to load it from tmp */
		strcpy( szFilenameP2VM, "/tmp/current_P2VM.fits" );

		fpTmp = fopen( szFilenameP2VM, "r" );

		if( fpTmp )
		{
			fclose( fpTmp );
			sprintf ( szMessage, "latest pipeline P2VM identified %s", szFilenameP2VM );
			cpl_msg_info( fctid, "%s", szMessage );
		}
	}

	/*
	 *
    Walk through the whole Set of Frames SOF and search for SCIENCE, CALIB or DARK

    for each OBJECT we will perform a calculation of visibilities and write a product

	 */
	it = cpl_frameset_iterator_new(framelist);
	cur_frame = cpl_frameset_iterator_get(it);

	while( cur_frame )
	{


		iFrameCount++;

		/* Get Filename and Classification Tag */
		pszFilename = (char *)cpl_frame_get_filename( cur_frame );
		pszFileTag  = (char *)cpl_frame_get_tag( cur_frame );

		/* Check Tag and Filename */
		if( pszFilename && pszFileTag )
		{
			sprintf( szMessage, "Frame #%d [Current execution status=%d]", iFrameCount, iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			/* SCIENCE / CALIB DARK */
			if(!strcmp( pszFileTag, "AMBER_DARK" ) ||
					!strcmp( pszFileTag, "AMBER_DARK_SCIENCE" ) ||
					!strcmp( pszFileTag, "AMBER_DARK_CALIB" ))
			{
				/* Use this Dark for the next Data Reduction */
				strcpy( szFilenameDARK, pszFilename );

				sprintf ( szMessage, "DARK identified %s", pszFilename );
				cpl_msg_info( fctid, "%s", szMessage );
				iLoadedFrameCount++;
			}


			if (iReduction >MAXFILESRAW)
			{

				cpl_msg_warning(cpl_func, "Currently only %d interferometric frames can be processed",MAXFILESRAW);
				cpl_msg_warning(cpl_func, "Scipping frame: %s", pszFilename);
				cpl_frameset_iterator_advance(it, 1);
				cur_frame = cpl_frameset_iterator_get(it);

				continue;
			}



			/* SCIENCE OR SCIENCE_CALIB OBJECT */
			if( !strcmp( pszFileTag, "AMBER_SCIENCE" ) )
			{
				/* Data Reduction on the highest level possible for amdlib, appending DATA to the file with product header */
				if( iStatus == 0 )
				{
					/* Add Filename to List */
					strcpy( szFilenameSCIENCE[iReduction], pszFilename );
					isFrameScience[iReduction] = 1;
					sprintf ( szMessage, "SCIENCE identified %s", pszFilename );
					cpl_msg_info( fctid, "%s", szMessage );
					iReduction++;
					iLoadedFrameCount++;
				} /* Status still OK */
			}  /* All SCIENCE frames */
			else if( !strcmp( pszFileTag, "AMBER_SCIENCE_CALIB" ) || !strcmp( pszFileTag, "AMBER_CALIB" ) )
			{
				/* Data Reduction on the highest level possible for amdlib, appending DATA to the file with product header */
				if( iStatus == 0 )
				{
					/* Add Filename to List */
					strcpy( szFilenameSCIENCE[iReduction], pszFilename );
					isFrameScience[iReduction] = 0;
					sprintf ( szMessage, "CALIB identified %s", pszFilename );
					cpl_msg_info( fctid, "%s", szMessage );
					iReduction++;
					iLoadedFrameCount++;
				} /* Status still OK */
			}  /* All CALIB frames */


		} /* Filename and Tag present */
		else
		{
			sprintf( szMessage, "Missing FileName or Tag for Frame #%d", iFrameCount );
			cpl_msg_info( fctid, "%s", szMessage );
		} /* Filename and Tag present */

		cpl_frameset_iterator_advance(it, 1);
		cur_frame = cpl_frameset_iterator_get(it);

	} /* while more frames */
	cpl_frameset_iterator_delete(it);

	/* For all existing tmp products create the real products */
	iProductNumber = 0;

	for( i=0; i<iReduction && i<MAXFILESRAW; i++ )
	{
		/* This is a science object frame we can reduce the data now */
		sprintf( szMessage, "Reducing %s now... [Status=%d]", szFilenameSCIENCE[i], iStatus );
		cpl_msg_info( fctid, "%s", szMessage );

		cpl_msg_info( fctid, "Now calling high level data reduction amdlibExtractVisESO..." );
		if( amdlibExtractVisESO( szFilenameBADPIX, szFilenameFLAT, szFilenameP2VM, szFilenameDARK, szFilenameSKY,
				szFilenameSCIENCE[i], iBinningOfFrames, errorType, pistonType, amdlibTRUE, fctid )
				!= amdlibSUCCESS
		)
		{
			sprintf( szMessage, "Error in Extracting Visibilities." );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = 2;
		}
		else
		{
			/* success */
			iStatus = 0;


			/* CPL Free !!!  */

			/* pframeSCIENCE[i] will be deleted by Caller */

		}
	} /* All Frames to be reduced */

	/* 3 bands per reduction */
	for( i=0; i<iProductNumber && i<MAXFILESPRODUCTS; i++ )
	{
		/* Insert this frame, so that caller can rename it to proper DMD product */
		if( pframeSCIENCE[i] )
		{
			sprintf( szMessage, "cpl_frame_insert (\"%s\")", cpl_frame_get_filename(pframeSCIENCE[i])  );
			cpl_msg_info( fctid, "%s", szMessage );
			cpl_frameset_insert( framelist, pframeSCIENCE[i] );
		}
	}

	/*run the selctor and try to calculate the transfer function*/
	if(selectPlusTrf==1)
	{
		select_frames(parlist, framelist, iProductNumber);
	}
	/* Close the amdlib logfile */
	//if( fp )
	//	fclose( fp );

	cpl_msg_info( fctid, "End of DataReduction");

	/* there is one remaining, due to a workarround above. Ignore it, ESOREX shall NOT talk about that :) */
	cpl_error_reset();


	/* Free the memory */
	for(i=0;i<MAXFILESPRODUCTS;i++)
	{
		cpl_free(szFilenameSCIENCE[i]);
	}
	cpl_free(szFilenameSCIENCE);
	cpl_free(isFrameScience);
	cpl_free(pframeSCIENCE);

	return iStatus ;
}

static void select_frames(cpl_parameterlist * parlist, cpl_frameset * framelist,
		int iProductNumber )
{
	char           * outname_selector=NULL;
	cpl_frameset   * local_framelist=NULL;
	cpl_frame      * local_frame=NULL;
	cpl_frame     ** frame_selector_snr=NULL;
	cpl_frame     ** frame_selector_pst=NULL;
	cpl_errorstate   prestate=0;
	int i=0;
	int status_snr=0;
	int status_pst=0;
	double x1_pst=0.;
	double x2_pst=0.;
	double x3_pst=0.;
	int isScience=1;
	frame_selector_snr = cpl_calloc(MAXFILESPRODUCTS, sizeof(cpl_frame*));
	frame_selector_pst = cpl_calloc(MAXFILESPRODUCTS, sizeof(cpl_frame*));

	/*------------------------------------------------------------------------*/
	/*Run the selector*/
	for( i=0; i<iProductNumber && i<MAXFILESPRODUCTS; i++ )
	{
		/* Insert this frame, so that caller can rename it to proper DMD product */

		if( pframeSCIENCE[i] )
		{
			local_framelist=cpl_frameset_new();
			local_frame=cpl_frame_duplicate(pframeSCIENCE[i]);
			cpl_frame_set_group(local_frame,CPL_FRAME_GROUP_CALIB);
			cpl_frameset_insert(local_framelist, local_frame);

			/*Get the pst selection values and the isScience value*/
			get_selection_param(&x1_pst, &x2_pst, &x3_pst, &isScience,
					pframeSCIENCE[i]);

			/*Select according to SNR*/
			outname_selector = cpl_sprintf("snr_filtered_%s",
					cpl_frame_get_filename(pframeSCIENCE[i]));
			status_snr=amber_selector_lib(50, 50, 50, 1, 0,
					"Fringe_SNR_percentage_x",
					cpl_frame_get_filename(pframeSCIENCE[i]),
					outname_selector, isScience,
					local_framelist, parlist, "amber_SciCal");
			if(status_snr==0)
			{
				frame_selector_snr[i]=cpl_frame_duplicate(
						cpl_frameset_get_position(local_framelist,1));
				cpl_frameset_insert(framelist,frame_selector_snr[i]);
				cpl_frameset_erase_frame(local_framelist,
						cpl_frameset_get_position(local_framelist,1));

				/*------------------------------------------------------------*/
				/*Derive the transfer function*/
				if(isScience==0)
				{
					prestate = cpl_errorstate_get();
					amber_TransferFunction("amber_SciCal", outname_selector,
							parlist, framelist);
					cpl_errorstate_set(prestate);
					/*
					if (!cpl_errorstate_is_equal(prestate)) {
						 An error happened
						cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
					}
					 */
				}
				/*------------------------------------------------------------*/
				/*Calibrate the Visibilities*/
				if(isScience!=0)
				{
					prestate = cpl_errorstate_get();
					amber_CalibVis("amber_SciCal", outname_selector,
							parlist, framelist);
					cpl_errorstate_set(prestate);
					/*
					if (!cpl_errorstate_is_equal(prestate)) {
						 An error happened
						cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
					}
					 */
				}
				/*------------------------------------------------------------*/

			}
			else
			{
				cpl_msg_warning(cpl_func,"File %s is not complete!",
						outname_selector);
			}
			cpl_free(outname_selector);

			/*Select according to PISTON*/

			outname_selector = cpl_sprintf("pst_filtered_%s",
					cpl_frame_get_filename(pframeSCIENCE[i]));
			status_pst=amber_selector_lib(x1_pst, x2_pst, x3_pst, 1, 0,
					"Absolute_piston_value_lt_x",
					cpl_frame_get_filename(pframeSCIENCE[i]),
					outname_selector, isScience,
					local_framelist, parlist, "amber_SciCal");
			if(status_pst==0)
			{
				frame_selector_pst[i]=cpl_frame_duplicate(
						cpl_frameset_get_position(local_framelist,1));
				cpl_frameset_insert(framelist,frame_selector_pst[i]);
				cpl_frameset_erase_frame(local_framelist,
						cpl_frameset_get_position(local_framelist,1));

				/*------------------------------------------------------------*/
				/*Derive the transfer function*/
				if(isScience==0)
				{
					prestate = cpl_errorstate_get();
					amber_TransferFunction("amber_SciCal", outname_selector,
							parlist, framelist);
					cpl_errorstate_set(prestate);
					/*
					if (!cpl_errorstate_is_equal(prestate)) {
						 An error happened
						cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
					}
					 */
				}
				/*------------------------------------------------------------*/
				/*Calibrate the Visibilities*/
				if(isScience!=0)
				{
					prestate = cpl_errorstate_get();
					amber_CalibVis("amber_SciCal", outname_selector,
							parlist, framelist);
					cpl_errorstate_set(prestate);
					/*
					if (!cpl_errorstate_is_equal(prestate)) {
						 An error happened
						cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
					}
					 */
				}
				/*------------------------------------------------------------*/

			}
			else
			{
				cpl_msg_warning(cpl_func,"File %s is not complete!",
						outname_selector);
			}
			cpl_free(outname_selector);
			cpl_frameset_delete(local_framelist);

		}
	}
	cpl_free(frame_selector_snr);
	cpl_free(frame_selector_pst);
	return;
}

static void get_selection_param(double * x1_pst, double * x2_pst,
		double * x3_pst, int * isScience, cpl_frame * cur_frame)
{
	cpl_propertylist * plist=NULL;
	cpl_errorstate     prestate = cpl_errorstate_get();
	const char * ft_sensor="";
	const char * grat_name="";
	int pro_science=1;

	plist = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);


	if (cpl_propertylist_has(plist, "ESO PRO SCIENCE") == 1)
	{
		pro_science=cpl_propertylist_get_bool(plist, "ESO PRO SCIENCE");
	}
	if(!pro_science)
	{
		*isScience=0;
	}
	if (cpl_propertylist_has(plist, "ESO DEL FT SENSOR") == 1)
	{
		ft_sensor=cpl_propertylist_get_string(plist, "ESO DEL FT SENSOR");
	}
	if (cpl_propertylist_has(plist, "ESO INS GRAT1 NAME") == 1)
	{
		grat_name=cpl_propertylist_get_string(plist, "ESO INS GRAT1 NAME");
	}



	if (!cpl_errorstate_is_equal(prestate)) {
		cpl_msg_warning(cpl_func,"Unable to determine the values for x1, x2, "
				"and x3 from the file");
		cpl_msg_warning(cpl_func,"Using default values of 0.0002 !!!");
		*x1_pst=0.0002;
		*x2_pst=0.0002;
		*x3_pst=0.0002;
		cpl_error_reset();
		if(plist!=NULL)
		{
			cpl_propertylist_delete(plist);
		}
		return;
	}

	if (strcmp(ft_sensor,"FINITO")==0)
	{
		if (strcmp(grat_name,"PRISM")==0)
		{
			*x1_pst=0.000020;
			*x2_pst=0.000020;
			*x3_pst=0.000020;
		}
		if (strcmp(grat_name,"GHR")==0)
		{
			*x1_pst=0.000200;
			*x2_pst=0.000200;
			*x3_pst=0.000200;
		}
		if (strcmp(grat_name,"GMR")==0)
		{
			*x1_pst=0.000200;
			*x2_pst=0.000200;
			*x3_pst=0.000200;
		}
	}
	else if (strcmp(ft_sensor,"NONE")==0)
	{
		if (strcmp(grat_name,"PRISM")==0)
		{
			*x1_pst=0.000040;
			*x2_pst=0.000040;
			*x3_pst=0.000040;
		}
		if (strcmp(grat_name,"GHR")==0)
		{
			*x1_pst=0.000400;
			*x2_pst=0.000400;
			*x3_pst=0.000400;
		}
		if (strcmp(grat_name,"GMR")==0)
		{
			*x1_pst=0.000400;
			*x2_pst=0.000400;
			*x3_pst=0.000400;
		}
	}
	else
	{
		cpl_msg_warning(cpl_func,"Unable to determine the values for x1, x2, "
				"and x3 from the file");
		cpl_msg_warning(cpl_func,"Using default values of 0.0002 !!!");
		*x1_pst=0.0002;
		*x2_pst=0.0002;
		*x3_pst=0.0002;
		cpl_error_reset();
	}

	if(plist!=NULL)
	{
		cpl_propertylist_delete(plist);
	}
	cpl_msg_info(cpl_func,"Using  X1=%f,  X2=%f, and X3=%f  meter for the "
			"selection on the Piston", *x1_pst, *x1_pst, *x1_pst);
	cpl_msg_info(cpl_func,"isScience is: %d", *isScience);


	return;
}

