/*******************************************************************************
 * JMMC project ( http://www.jmmc.fr ) - Copyright (C) CNRS.
 ******************************************************************************/

#ifndef amdlibPublic_H
#define amdlibPublic_H
/**
 * @file
 * This file contains public functions and structures of the AMBER data
 * reduction software.
 */ 

/* The following piece of code alternates the linkage type to C for all
 * functions declared within the braces, which is necessary to use the
 * functions in C++-code.
 */
#ifdef __cplusplus
extern "C" { 
#endif

/*float types - change fftw definitions accordingly */
#define amdlibDOUBLE double

/* System files */
#include "fitsio.h"

/** Definition of boolean */
typedef enum 
{
    amdlibFALSE = 0,
    amdlibTRUE
} amdlibBOOLEAN;

/** Error message  */
#define amdlibERROR_LENGTH 256
typedef char amdlibERROR_MSG[amdlibERROR_LENGTH];

/** Definition of the routine completion status */
typedef enum
{
    amdlibFAILURE = 1,
    amdlibSUCCESS
} amdlibCOMPL_STAT;

/*
 * This diagram shows the detector arrays (512x512 pixels) with a possible
 * sub-windowing configuration.
 *
 *      +---------------------------------------------+
 *      |                                             |
 *      |  +---+    +---+    +---+    +---+    +---+  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  +---+    +---+    +---+    +---+    +---+  |
 *      |                                             |
 *      |  +---+    +---+    +---+    +---+    +---+  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  +---+    +---+    +---+    +---+    +---+  |
 *      |                                             |
 *      |  +---+    +---+    +---+    +---+    +---+  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  |   |    |   |    |   |    |   |    |   |  |
 *      |  +---+    +---+    +---+    +---+    +---+  |
 *      +---------------------------------------------+
 *
 * The following naming convention for the variables has been adopted :
 *   - nbCols    : specifies the number of colunms defined in the current
 *                 detector configuration (5 in the above example) 
 *   - nbRows    : specifies the number of spectral windows read on the
 *                 detector (3 in the above example) 
 *   - nx        : the number of pixels in column (in X direction)
 *   - ny        : the number of pixels in rows (in Y direction)
 *    
 */

/* Definition of the structure corresponding to the binary tables included in
 * the FITS files produced by the AMBER instrument (see document
 * VLT-SPE-ESO-15000-2764) */

#define amdlibNB_TEL      3
#define amdlibNBASELINE amdlibNB_TEL*(amdlibNB_TEL-1)/2

/* Dimension of detector array */
#define amdlibDET_SIZE_X  512
#define amdlibDET_SIZE_Y  512

/* Detector windowing definition */
#define amdlibMAX_NB_ROWS       3
#define amdlibMAX_NB_COLS       5
#define amdlibNB_PHOTO_CHANNELS 3

/* Frame definition. */
#define amdlibFIRST_FRAME  1
#define amdlibALL_FRAMES  -1

/** Values used for bad pixels in bad pixel map */
#define amdlibBAD_PIXEL_FLAG  0
/** Values used for good pixels in bad pixel map */
#define amdlibGOOD_PIXEL_FLAG 1

/** 
 * Telescopes
 */
typedef enum 
{
    amdlibTEL1 = 0,
    amdlibTEL2,
    amdlibTEL3
} amdlibTELS;

/** 
 * Baselines
 */
typedef enum 
{
    amdlibBASE12 = 0,
    amdlibBASE23,
    amdlibBASE31
} amdlibBASELINE;

/** 
 * Frame type. DO NOT CHANGE ORDER, JUST ADD AT END!!!!!
 */
typedef enum 
{
    amdlibDARK_FRAME = -1,
    amdlibTEL1_FRAME,
    amdlibTEL2_FRAME,
    amdlibTEL3_FRAME,
    amdlibTEL12_FRAME,
    amdlibTEL23_FRAME,
    amdlibTEL13_FRAME,
    amdlibTEL12Q_FRAME,
    amdlibTEL23Q_FRAME,
    amdlibTEL13Q_FRAME,
    amdlibTEL123_FRAME,
    amdlibSKY_FRAME,
    amdlibUNKNOWN_FRAME
} amdlibFRAME_TYPE;

#define amdlibNB_INS_CFG_KEYW 1024
#define amdlibKEYW_LINE_LEN 80
#define amdlibKEYW_NAME_LEN 80
#define amdlibKEYW_VAL_LEN 80
#define amdlibKEYW_CMT_LEN 80
typedef char amdlibKEYW_LINE[amdlibKEYW_LINE_LEN+1];
/** 
 * Simple definition of keyword
 */
typedef struct 
{
    char name[amdlibKEYW_NAME_LEN+1];
    char value[amdlibKEYW_VAL_LEN+1];
    char comment[amdlibKEYW_CMT_LEN+1];
} amdlibKEYWORD;

/**
 * Table containing instrument configuration table */ 
typedef struct 
{
    int           nbKeywords;
    amdlibKEYWORD keywords[amdlibNB_INS_CFG_KEYW];
} amdlibINS_CFG;

/**
 * Structure describing the setup and characteristics of the 2-dimensional
 * detector used to record photometric and visibility data. This information
 * comes from IMAGING_DETECTOR binary table.
 */
typedef struct
{
    /** Origine of the data */
    char origin[amdlibKEYW_VAL_LEN+1];
    /** Instrument name */
    char instrument[amdlibKEYW_VAL_LEN+1];
    /** Observation date (Modified Julian Date) */
    double dateObsMJD;
    /** Observation date (YYY-MM-DDThh:mm:ss UTC) */
    char dateObs[amdlibKEYW_VAL_LEN+1];
    /** HDU creation date (YYY-MM-DDThh:mm:ss UTC) */
    char date[amdlibKEYW_VAL_LEN+1];
    /** Data dictionary name */
    char detDictionaryId[amdlibKEYW_VAL_LEN+1];
    /** DCS software version string */
    char detId[amdlibKEYW_VAL_LEN+1];
    /** Number of detectors */
    int nbDetectors;
    /** Number of regions */
    int nbRegions;
    /** Maximum number of polynomial coefficients for DMC and DMP */
    int maxCoef;
    /** Number of dimensions of detector array */
    int numDim;
    /** Maximun number of telescopes for instrument */
    int maxTel;
} amdlibIMAGING_DETECTOR;

/**
 * Structure containing the detector pixel data for an exposure coming form
 * IMAGING_DATA binary table.
 */
typedef struct
{
    /** Origin of the data */
    char origin[amdlibKEYW_VAL_LEN+1];
    /** Instrument name */
    char instrument[amdlibKEYW_VAL_LEN+1];
    /** Observation date (Modified Julian Date) */
    double dateObsMJD;
    /** Observation date (YYY-MM-DDThh:mm:ss UTC) */
    char dateObs[amdlibKEYW_VAL_LEN+1];
    /** HDU creation date (YYY-MM-DDThh:mm:ss UTC) */
    char date[amdlibKEYW_VAL_LEN+1];
    /** Data dictionary name */
    char detDictionaryId[amdlibKEYW_VAL_LEN+1];
    /** DCS software version string */
    char detId[amdlibKEYW_VAL_LEN+1];
    /** Number of regions */
    int nbRegions;
    /** Maximun number of telescopes for instrument */
    int maxTel;
    /** Maximum number of entries in OPTICAL_TRAIN table */
    int maxIns;
    /** Maximum number of steps in an observational cycle */
    int maxStep;
} amdlibIMAGING_DATA;

#define amdlibMAX_NB_AXIS 3
/**
 * Structure containing all informations describing regions coming from
 * either IMAGING_DETECTOR or IMAGING_DATA binary tables.
 */
typedef struct
{
    /* The first part gives informations on the regions. These informations are
     * stored in the IMAGING_DETECTOR binary table */
    /*** Be careful, here you can replace 2 by amdlibMAX_NB_AXIS ***/
    /** Region number that is being described */
    int regionNumber;
    /** Descriptive name of the region; e.g. I1, I2, PA, PB or QL */
    char regionName[amdlibKEYW_VAL_LEN+1];
    /** Detector that is on the region */
    int detectorNumber;
    /** Entrance ports of the interferometer that contribute to this region */
    int ports[amdlibNB_TEL];
    /** Correlation type, 0=background, 1=photometric and 2=interferometric */
    int correlation;
    /** Corner of this region on the detector as low value of x, low value of
     ** y, inclusive */
    int corner[2];
    /** Detector conversion factor from electron to ADU (e-/ADU) */
    double gain;
    /** Coordinates at the reference pixels */
    double crVal[2];
    /** Reference pixels on 'x' and 'y' axes for this region */
    double crPix[2];     
    /** Type de coordinates for the 'x' and 'y' axes for this region. Standard
     ** WCS conventions are used */
    char cType[2][8];
    /** Transformation applied after DMPn/DMCn transformations. Standard
     ** WCS conventions are used */
    double cd[2][2];
    /** Distorsion correction array */
    double ***dmp;
    /** Distorsion correction array */
    double ***dmc;
    /* The second part contains the data which are stored in the IMAGING_DATA
     * binary table */
    /** Dimension of each axis */
    int dimAxis[amdlibMAX_NB_AXIS];
    /** Data */
    amdlibDOUBLE *data;
} amdlibREGION;

/**
 * Position and dimension of photometric or interferometric channel (1 column)
 */
typedef struct
{
    /** Start pixel (in X direction) of the column */
    int startPixel;
    /** Number of pixels */
    int nbPixels;
} amdlibCOL_INFO;

/** 
 * Structure containing position and characteristic of a telescope.
 */
typedef struct
{
    /** Telescope name. */
    char telescopeName[amdlibKEYW_VAL_LEN+1];
    /** Station name. */
    char stationName[amdlibKEYW_VAL_LEN+1];
    /** Station number. */
    int stationIndex; 
    /** Element diameter (meters). */
    amdlibDOUBLE elementDiameter;
    /** Station coordinates relative to array center (meters). */
    double stationCoordinates[3];
} amdlibOI_ARRAY_ELEMENT;

/** 
 * Structure containing positions and characteristics of the telescopes used in
 * observation.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Number of stations defined. */
    int  nbStations;
    /** Array name, for cross-referencing. */
    char arrayName[amdlibKEYW_VAL_LEN+1];
    /** Coordinate frame. */
    char coordinateFrame[amdlibKEYW_VAL_LEN+1];
    /** Array center coordinates (meters). */
    double arrayCenterCoordinates[3];
    /** Array containing telescope descriptions. */
    amdlibOI_ARRAY_ELEMENT *element;
} amdlibOI_ARRAY;

#define amdlibNB_SPECTRAL_CHANNELS   amdlibDET_SIZE_Y
#define amdlibOFFSETY_NOT_CALIBRATED 999.0
/**
 * Structure containing the effective wavelengths/bandwidths for each spectral
 * channel for the interferometric data, and the wavelength offset for each
 * photometric column. This information comes from AMBER_WAVEDATA binary table.
 */
typedef struct
{
    /** Origine of the data */
    char origin[amdlibKEYW_VAL_LEN+1];
    /** Instrument name */
    char instrument[amdlibKEYW_VAL_LEN+1];
    /** Observation date (Modified Julian Date) */
    double dateObsMJD;
    /** Observation date (YYY-MM-DDThh:mm:ss UTC) */
    char dateObs[amdlibKEYW_VAL_LEN+1];
    /** HDU creation date (YYY-MM-DDThh:mm:ss UTC) */
    char date[amdlibKEYW_VAL_LEN+1];
    /** Instrument dictionary name */
    char insDictionaryId[amdlibKEYW_VAL_LEN+1];
    /** INS software version string */
    char insId[amdlibKEYW_VAL_LEN+1];
    /** Number of wavelengths */
    int nbWlen;
    /** Arrays containing the wavelengths and bandwidth (microns) corresponding
     * to the interferometric data */
    amdlibDOUBLE wlen[amdlibNB_SPECTRAL_CHANNELS];
    amdlibDOUBLE bandwidth[amdlibNB_SPECTRAL_CHANNELS];
    /** Wavelength offset, in pixel, for each photometric column */
    amdlibDOUBLE photoOffset[3];
} amdlibWAVEDATA;

/** Number of spectral bands */
#define amdlibNB_BANDS 3

/**
 * Spectral bands
 */
typedef enum 
{
    amdlibUNKNOWN_BAND = -1,
    amdlibJ_BAND,
    amdlibH_BAND,
    amdlibK_BAND,
    amdlibALL_BANDS
} amdlibBAND;

/**
 * Structure characterizing a spectral band.
 */
typedef struct
{
    /** Name of spectral band */
    char *name;
    /** Bounds of the spectral band considered */
    amdlibDOUBLE lowerBound;
    amdlibDOUBLE upperBound;
} amdlibBAND_DESC;

/**
 * Structure containing raw data.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Id of the P2VM which can be used to reduce this data */
    int p2vmId;
    /** Time for this exposure (Modified Julian Date) */
    double time;
    /** Dit time in seconds */
    amdlibDOUBLE expTime;
    /** Number of spectral windows read (up to 3) */
    int nbRows;
    /** Number of columns */
    int nbCols;
    /** Number of frames */
    int nbFrames;
    /** Array of keywords corresponding to the instrument configuration at the
     * time of the data acquisition */
    amdlibINS_CFG insCfg;
    /** Wave data */
    amdlibWAVEDATA   waveData;
    /** Imaging Detector informations */
    amdlibIMAGING_DETECTOR imagingDetector;
    /** Imaging data informations */
    amdlibIMAGING_DATA     imagingData;
    /** Array Geometry */
    amdlibOI_ARRAY         arrayGeometry;
    /** Number of regions = nbRows * nbCols */
    int                    nbRegions; 
    /** List of regions */
    amdlibREGION           *region;
    amdlibREGION           *variance;
    /** Time each Frame obtained (given by DCS in IMAGING_DATA */
    double *timeTag;
    /** True if file only contains detector data; i.e. does not contains
     * ICS sub-system keywords nor wave data binary table */
    amdlibBOOLEAN detDataOnly;
    /** True if the data has been loaded */ 
    amdlibBOOLEAN dataLoaded;
    /** True if the data has been already calibrated */
    amdlibBOOLEAN dataCalibrated;
    /** True if the raw data has [a number of] saturated pixels */ 
    amdlibBOOLEAN dataIsSaturated;
    /** Frame type */
    amdlibFRAME_TYPE frameType;
} amdlibRAW_DATA;

/* CALIBRATION MAPS */
/**
 * Structure containing flat-field map.
 */
typedef struct
{
    /** True if the flat field map has already been initialized */
    amdlibBOOLEAN mapIsInitialized;
    /** Flat field map */
    amdlibDOUBLE data[amdlibDET_SIZE_Y][amdlibDET_SIZE_X];
} amdlibFLAT_FIELD_MAP;

/**
 * Structure containing bad pixel map.
 */
typedef struct
{
    /** True if the bad pixel map has already been initialized */
    amdlibBOOLEAN mapIsInitialized;
    /** Bad pixel map */
    amdlibDOUBLE data[amdlibDET_SIZE_Y][amdlibDET_SIZE_X];
} amdlibBAD_PIXEL_MAP;

/**
 * Structure containing background (dark) data.
 */
 typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Dit time in seconds. darks MUST have same dit as frame
     * to which it is applied */
    amdlibDOUBLE expTime;
    /** Number of spectral windows and columns */ 
    int nbRows;      
    int nbCols;      
    /** Imaging Detector informations */
    amdlibIMAGING_DETECTOR imagingDetector;
    /** Number of regions = nbRows * nbCols */
    int                    nbRegions; 
    /** List of regions */
    amdlibREGION           *region; /* dark (bias) value*/
    amdlibREGION           *noise; /* variance of the readout noise computed
                                    * on dark, pixel per pixel. (=sigma2det)*/
    amdlibBOOLEAN otfBadIsPresent; /* tells whether the otfBad has been estimated */
    amdlibREGION           *otfBad; /* on-the-fly bad pixel estimate */
    /** Time each Frame obtained (given by DCS in IMAGING_DATA) */
    double *timeTag;

} amdlibDARK_DATA;


/**
 * Structure containing ISS configuration information
 */
typedef struct
{
    /** Array containing station indexes corresponding on detectors beams */
    int stationIndex[amdlibNB_TEL];
    /** Coordinates of these stations wrt phase center */
    double stationCoordinates[3][amdlibNB_TEL];
    /** Other info necessary for U and V computation*/
    double geoLat;
    double lst;
    double ra;
    double dec;
    /** Array containing real prejected baselines position at start of
     * observation */
    double projectedBaseStart[amdlibNBASELINE];
    /** Array containing real prejected baselines position at end of
     * observation */
    double projectedBaseEnd[amdlibNBASELINE];
    /** Array containing real projected baselines angles at start of
     * observartion */
    double projectedAngleStart[amdlibNBASELINE];
    /** Array containing real projected baselines angles at end of
     * observartion */
    double projectedAngleEnd[amdlibNBASELINE];
} amdlibISS_INFO;

/**
 * Structure containing science data for one frame.
 */
typedef struct 
{   
    /** Flux Ratio */
    amdlibDOUBLE fluxRatio[amdlibNB_PHOTO_CHANNELS];
    /** Array containing the interferometric data */
    amdlibDOUBLE *intf;
    amdlibDOUBLE *sigma2Intf;
    /** Arrays containing the photometric data row and corresponding variance */
    amdlibDOUBLE *photo1;
    amdlibDOUBLE *photo2;
    amdlibDOUBLE *photo3;
    amdlibDOUBLE *sigma2Photo1;
    amdlibDOUBLE *sigma2Photo2;
    amdlibDOUBLE *sigma2Photo3;
    /** Integrated values and corresponding SNR */
    double snrPhoto1;
    double snrPhoto2;
    double snrPhoto3;
    double integratedPhoto1;
    double integratedPhoto2;
    double integratedPhoto3;
} amdlibFRAME_SCIENCE_DATA;

/**
 * Structure containing spectral dispersion. 
 * Since the SPECTRAL CALIBRATION Changes with AMBER setup and Time, it is
 * necessary to TAG this table with an unique identifier, because the OI-FITS
 * format will need to refer to this identifier */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Number of wavelengths */
    int nbWlen;
    /** Arrays containing wavelength and bandwidth */
    amdlibDOUBLE *wlen;
    amdlibDOUBLE *bandwidth;
} amdlibWAVELENGTH;

/**
 * Structure containing spectra.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /* Number of telescopes */
    int nbTels;
    /* Number of wavelengths */
    int nbWlen;
    /* Arrays containing spectra and associated errors */
    double *spec[amdlibNB_TEL];      /* [nbChannels] */
    double *specErr[amdlibNB_TEL]; /* [nbChannels] */
} amdlibSPECTRUM;

/* Whole science data */
/* Indexes referencing photometric and interferometric channels */
#define amdlibPHOTO1_CHANNEL    0
#define amdlibPHOTO2_CHANNEL    1
#define amdlibPHOTO3_CHANNEL    2
#define amdlibINTERF_CHANNEL    3

/**
 * Structure containing whole science data.
 */
typedef struct 
{   
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Id of the P2VM which can be used to reduce this data */
    int p2vmId;
    /** Array of keywords corresponding to the instrument configuration at the
     * time of the data acquisition for P2VM calibration */
    amdlibINS_CFG insCfg;
    /** Integration Time per frame (supposedly globally constant) */ 
    amdlibDOUBLE expTime;    
    /** Time each Frame obtained (given by DCS in IMAGING_DATA) */
    double *timeTag;
    /** Number of columns (3 or 4) */ 
    int nbCols;      
    /** Dimension and position of columns (shielded area not in science data) */
    amdlibCOL_INFO col[amdlibMAX_NB_COLS-1];
    /** Number of usefull channels */
    int nbChannels;
    /** Array containing the number of each spectral channel */
    int *channelNo;
    /** Number of frames */ 
    int nbFrames;
    /** Structure containing information about ISS configuration */
    amdlibISS_INFO issInfo;
    /** Array containing the bad pixel flags corresponding to the
     * interferometric channel */
    unsigned char *badPixels;   /* [nbChannels][nx] */
    unsigned char **badPixelsPt;
    /** Array containing the frames */
    amdlibFRAME_SCIENCE_DATA *frame;
} amdlibSCIENCE_DATA;

#define amdlibMAX_NB_FRAMES_SC 6
/**
 * Structure containing data for spectral calibration.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Array containing flag indicating whether corresponding raw data is
     * loaded or not. */  
    amdlibBOOLEAN  dataLoaded[amdlibMAX_NB_FRAMES_SC];
    /** Array containing raw data needed for spectral calibration. */
    amdlibRAW_DATA rawData[amdlibMAX_NB_FRAMES_SC];
} amdlibSC_INPUT_DATA;

/** Spectral calibration type */
typedef enum 
{
    amdlibSC_2T = 1,
    amdlibSC_3T
} amdlibSC_TYPE;

#define amdlibMAX_NB_FRAMES_P2VM 9
/**
 * Structure containing data for P2VM computation.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Id of the P2VM to be computed */
    int p2vmId;
    /** Number of frames which has been used to compute P2VM */
    int nbFrames;
    /** Array containing flag indicating whether corresponding science data is
     * loaded or not. */ 
    amdlibBOOLEAN      dataLoaded[amdlibMAX_NB_FRAMES_P2VM];
    /** Array containing science data needed for P2VM computation. */
    amdlibSCIENCE_DATA scienceData[amdlibMAX_NB_FRAMES_P2VM];
} amdlibP2VM_INPUT_DATA;

/** P2VM type */
typedef enum 
{
    amdlibP2VM_2T = 1,
    amdlibP2VM_3T
} amdlibP2VM_TYPE;

/** P2VM accuracy */
typedef enum 
{
    amdlibP2VM_UNKNOWN_ACC = 0,
    amdlibP2VM_STD_ACC,
    amdlibP2VM_HIGH_ACC
} amdlibP2VM_ACCURACY;

/**
 * Structure containing data for P2VM.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Unique P2VM Id */
    int id;
    /** Array of keywords corresponding to the instrument configuration at the
     * time of the data acquisition for P2VM calibration */
    amdlibINS_CFG insCfg;
    /** P2VM type (amdlibP2VM_2T or amdlibP2VM_3T) */
    amdlibP2VM_TYPE type;
    /** P2VM accuracy (amdlibP2VM_STD_ACC or amdlibP2VM_HIGH_ACC) */
    amdlibP2VM_ACCURACY accuracy;
    /** first valid channel (in Y direction) of the row corresponding to the
     * P2VM */
    int    firstChannel;
    /** Number of pixels in column */
    int    nx;
    /** Number of spectral channels */
    int    nbChannels;  
    /** Number of frames which has been used to compute P2VM */
    int nbFrames;
    /** Array containing the wavelengths */
    amdlibDOUBLE  *wlen;       /* [nbChannels] */
    /** Array containing the ck and dk coefficients */
    double *matrix;     /* [nbChannels][nx][2*nbBase] */
    double ***matrixPt;
    /** Arrays containing the vk coefficients */
    double *vk;         /* [nbTel][nbChannels][nx] */
    double ***vkPt;
    double *sumVk;       /* [nbBase][nbChannels] */   
    double **sumVkPt;              
    /** Array containing the bad pixel flags corresponding to the
     * interferometric channel */
    unsigned char *badPixels;   /* [nbChannels][nx] */
    unsigned char **badPixelsPt;
    /** Array containing the Flat field corresponding to the 
     * interferometric channel*/
    amdlibDOUBLE *flatField;
    amdlibDOUBLE **flatFieldPt;
    /** Arrays containing the photometric data */
    double *photometry; /* [2*nbBase+1][3][nbChannels] */
    double ***photometryPt;
    /** Arrays containing the validity flag */
    unsigned char *flag;        /* [nbChannels]*/
    /** Array containing the phase shift */
    double *phase;      /* [nbBase][nbChannels] */
    double **phasePt;
    /** Arrays containing the instrument visibilities */
    amdlibDOUBLE insVis[amdlibNBASELINE];
    amdlibDOUBLE insVisErr[amdlibNBASELINE];
    /** Arrays containing the instrument visibilities per band*/
    amdlibDOUBLE insVisInBand[amdlibNBASELINE][amdlibNB_BANDS];
    amdlibDOUBLE insVisErrInBand[amdlibNBASELINE][amdlibNB_BANDS];
    
} amdlibP2VM_MATRIX;

/* OI-FITS */
/** Complex */
typedef struct
{
    double re;
    double im;
} amdlibCOMPLEX;

#define amdlib_OI_REVISION 1 /*Current revision number*/

/** 
 * Structure containing information about observed source.
 */
typedef struct
{
    /** Source number. This is an index used to reference this entry from other
     * tables. */
    int targetId;
    /** Source name. */
    char targetName[16+1];
    /** Equinox */
    amdlibDOUBLE equinox;
    /** Right ascenion at the beginning of observation. */
    double raEp0;
    /** Declinaison at the beginning of observation. */
    double decEp0;
    /** Error in apparent RA. */
    double raErr;
    /** Error in apparent DEC. */
    double decErr;
    /** Systematic radial velocity. */
    double sysVel;
    /** Velocity type. */
    char velTyp[8+1];
    /** Definition of velocity. */
    char velDef[8+1];
    /** Proper motion in RA. */
    double pmRa;
    /** Proper motion in DEC. */
    double pmDec;
    /** Error in proper motion in RA. */
    double pmRaErr;
    /** Error in proper motion in DEC. */
    double pmDecErr;
    /** Parallax value. */
    double parallax;
    /** Error in parallax value. */
    amdlibDOUBLE paraErr;
    /** Spectral type. */
    char specTyp[16+1];
} amdlibOI_TARGET_ELEMENT;


/** 
 * Structure containing information about all observed sources.
 */
typedef struct
{
    void *thisPtr;
    /** Number of observed sources. */
    int  nbTargets; 
    /** Array containing observed sources. */
    amdlibOI_TARGET_ELEMENT *element;
} amdlibOI_TARGET;

/** 
 * Structure containing photometries for one baseline.
 */
typedef struct
{
    /** Array[nbWlen] containing the number of electrons collected
     ** in the spectral channel */
    double *fluxSumPiPj;
    double *sigma2FluxSumPiPj;
    /** Array[nbWlen] containing the flux ratio
     ** in the spectral channel */
    double *fluxRatPiPj;
    double *sigma2FluxRatPiPj;
    /** Array[nbWlen] containing the photometric correction on the mks
     ** in the spectral channel */
    double *PiMultPj; 

} amdlibPHOTOMETRY_TABLE_ENTRY;

/** 
 * Structure containing photometries for all baselines.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Number of frames */
    int nbFrames;
    /** Number of Baselines */
    int nbBases;
    /** Number of wavelengths */
    int nbWlen;
    
    amdlibPHOTOMETRY_TABLE_ENTRY *table;
    
} amdlibPHOTOMETRY;
  
/** 
 * Structure containing calibrated visibilities for one baseline.
 */
typedef struct
{
    /** Target ID */
    int targetId;
    /** UTC time of observation */
    double time;
    /** Observation date (Modified Julian Date) */
    double dateObsMJD;
    /** Integration Time per frame (supposedly globally constant) */ 
    amdlibDOUBLE expTime;    
    /** U coord of this visibility measurement */
    double uCoord;
    /** V coord of this visibility measurement */
    double vCoord;
    /** Stations Number contributing to the Data */
    int stationIndex[2];
    /** Array[nbWlen] containing the Visibility Expressed as Complex */
    amdlibCOMPLEX *vis;
    /** Array[nbWlen] containing the corresponding variance */
    amdlibCOMPLEX *sigma2Vis;
    /** Array[nbWlen] containing the covariance
     ** between Real and Imaginary part of the visibilities */
    double *visCovRI;
    /** Array[nbWlen] containing the differential Visibility Amplitude*/
    double *diffVisAmp;
    /** Array[nbWlen] containing the corresponding error */
    double *diffVisAmpErr;
    /** Array[nbWlen] containing the differential phase */
    double *diffVisPhi;
    /** Array[nbWlen] containing the corresponding error */
    double *diffVisPhiErr;
    /** Criterion to say whether there are fringes or not */
    double frgContrastSnrArray[amdlibNB_BANDS];
    /** Flag determining which bands are taken into account */
    amdlibBOOLEAN bandFlag[amdlibNB_BANDS];
    /** warning: obsolete field assuring compatibility with old versions*/
    double frgContrastSnr;
    /* Flag : if a value in this vector is true, the corresponding datum should
     * be ignored in all analysis */
    amdlibBOOLEAN* flag;

} amdlibVIS_TABLE_ENTRY;

/** 
 * Structure containing calibrated visibilities for all baseline.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /* Number of frames */
    int nbFrames;
    /* Number of Baselines */
    int nbBases;
    /* Number of wavelengths */
    int nbWlen;
    /** Observation date (YYY-MM-DDThh:mm:ss UTC) */
    char dateObs[amdlibKEYW_VAL_LEN+1];
    /* IAU_VIS structure with nbSamples components */
    amdlibVIS_TABLE_ENTRY *table;
} amdlibVIS;

/**
 * IAU_VIS2 structure. According to last IAU Draft, 
 * that should update the ESO one about OI_VIS2 
 */
typedef struct
{
    /** Target ID */
    int targetId;
    /** UTC time of observation */
    double time;
    /** Observation date (Modified Julian Date) */
    double dateObsMJD;
    /** Integration Time per frame (supposedly globally constant) */ 
    amdlibDOUBLE expTime;
    /** Array containing the Squared Visibility */
    double  *vis2;
    /** Array containing the corresponding error */
    double *vis2Error;
    /** U coord of this visibility measurement */
    double uCoord;
    /** V coord of this visibility measurement */
    double vCoord;
    /** Stations Number contributing to the Data */
    int stationIndex[2];
    /* Flag : if a value in this vector is true, the corresponding datum should
     * be ignored in all analysis */
    amdlibBOOLEAN* flag;

} amdlibVIS2_TABLE_ENTRY;

/** 
 * Structure containing calibrated square visibilities for all baseline.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /* Number of frames */
    int nbFrames;
    /* Number of Baselines */
    int nbBases;
    /* Number of wavelengths */
    int nbWlen;
    /** Mean visibility with corresponding error */
    amdlibDOUBLE vis12;
    amdlibDOUBLE vis23;
    amdlibDOUBLE vis31;
    amdlibDOUBLE sigmaVis12;
    amdlibDOUBLE sigmaVis23;
    amdlibDOUBLE sigmaVis31;
    /** Observation date (YYY-MM-DDThh:mm:ss UTC) */
    char dateObs[amdlibKEYW_VAL_LEN+1];
    /* IAU_VIS2 structure with nbWlen components */
    amdlibVIS2_TABLE_ENTRY *table;
} amdlibVIS2;  

/**
 * V^2 bias computation type.
 */ 
typedef enum
{ 
    /** Phasors algorythm, very slow and maybe inaccurate */
    amdlibSTATISTICAL_ERROR = 0,  
    /** Fit of the unwrapped phase */
    amdlibTHEORETICAL_ERROR
} amdlibERROR_TYPE;

/**
 * IAU_VIS3 structure. According to last IAU Draft, 
 * that should update the ESO one about OI_VIS3 
 */
typedef struct
{
    /** Target ID */
    int targetId;
    /** UTC time of observation */
    double time;
    /** Observation date (Modified Julian Date) */
    double dateObsMJD;
    /** Integration Time per frame (supposedly globally constant) */ 
    amdlibDOUBLE expTime;    
    /** Array[nbWlen] containing the Triple Product Amplitude */
    double  *vis3Amplitude;
    /** Array[nbWlen] containing the corresponding error */
    double *vis3AmplitudeError;
    /** Array[nbWlen] containing the Triple Product Phase (degrees)*/
    double  *vis3Phi;
    /** Array[nbWlen] containing the corresponding error (degrees)*/
    double *vis3PhiError;
    /** U1 coord of baseline AB of the triangle */
    double u1Coord;
    /** V1 coord of baseline AB of the triangle */
    double v1Coord;
    /** U2 coord of baseline BC of the triangle */
    double u2Coord;
    /** V2 coord of baseline BC of the triangle */
    double v2Coord;
    /** Stations Number contributing to the triple product (3 values) */
    int stationIndex[3];
    /* Flag : if a value in this vector is true, the corresponding datum should
     * be ignored in all analysis */
    amdlibBOOLEAN* flag;
    
} amdlibVIS3_TABLE_ENTRY;

/** 
 * Structure containing calibrated phase closures for all baseline.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Number of frames */
    int nbFrames;
    /** Number of phase closures */
    int nbClosures;
    /** Number of wavelengths */
    int nbWlen;
    /** Returns the closure averaged over all frames and wavelength */
    amdlibDOUBLE averageClosure;
    amdlibDOUBLE averageClosureError;
    /** Observation date (YYY-MM-DDThh:mm:ss UTC) */
    char dateObs[amdlibKEYW_VAL_LEN+1];
    /** IAU_VIS3 structure with nbWlen components */
    amdlibVIS3_TABLE_ENTRY *table;
} amdlibVIS3;  

/** 
 * Structure containing calibrated pistons for all baseline.
 */
typedef struct
{
    /* The following pointer is used to know if the data structure is
     * initialized or not. When initialized, it contains pointer to itself */
    void *thisPtr;
    /** Number of frames */
    int nbFrames;
    /** Number of Baselines */
    int nbBases;
    /** Flag determining which bands are taken into account */
    amdlibBOOLEAN bandFlag[amdlibNB_BANDS];
    /** Piston values for each baseline in same unit as lambda */
    amdlibDOUBLE *pistonOPDArray[amdlibNB_BANDS];
    /** Error on Piston same unit as above */
    amdlibDOUBLE *sigmaPistonArray[amdlibNB_BANDS];
    /** warning: obsolete fields assuring compatibility with old versions*/
    amdlibDOUBLE *pistonOPD; 
    amdlibDOUBLE *sigmaPiston;
} amdlibPISTON;

/**
 * Piston algorithm.
 */ 
typedef enum
{ 
    /** Phasors algorythm, very slow and maybe inaccurate */
    amdlibITERATIVE_PHASOR = 0,  
    /** Fit of the unwrapped phase */
    amdlibUNWRAPPED_PHASE
} amdlibPISTON_ALGORITHM;

/**
 * Frame selection criteria.
 */ 
typedef enum
{
    /** No selection */
    amdlibNO_FRAME_SEL = 0,
    /** Selection on flux ratio */
    amdlibFLUX_SEL_PCG,      /* ratio = percentage */
    amdlibFLUX_SEL_THR,      /* ratio = threshold */
    /** Selection on fringe contrast SNR */
    amdlibFRG_CONTRAST_SEL_PCG,
    amdlibFRG_CONTRAST_SEL_THR,
    /** Selection on piston */
    amdlibOPD_SEL_PCG,
    amdlibOPD_SEL_THR
} amdlibFRAME_SELECTION;

/** 
 * Structure containing information on selected frames for 1 band.
 */
typedef struct
{
    /** Number of selected frames for each baseline */
    int nbSelectedFrames[amdlibNBASELINE];
    /** Index of first selected frame for each baseline */
    int firstSelectedFrame[amdlibNBASELINE];
    /** Array containing criteria to say whether a frame is selected or not 
     * for each baseline */
    unsigned char **isSelectedPt;
    unsigned char *isSelected;    /* [nbBases][nbFrames] */
    /** Array containing index of frames selected for all baselines and its real
     * size */
    int nbFramesOkForClosure;     /* Number of phase closures */
    int *frameOkForClosure;       /* [nbFrames] */
} amdlibSELECTION_BAND;

typedef struct
{
    /** Total number of frames */
    int nbFrames;
    /** Number of baselines */
    int nbBases;
    /** Selected frames per band */
    amdlibSELECTION_BAND band[amdlibNB_BANDS]; 
} amdlibSELECTION;

#define amdlibDEFAULT_CPT_VIS_OPTIONS {999999, amdlibSTATISTICAL_ERROR,    \
                                       amdlibUNWRAPPED_PHASE, amdlibFALSE, \
                                       amdlibNO_FRAME_SEL, 1.0}

/**
 * Structure containing information necessary for visibilities computation.
 */
typedef struct
{
    /** Number of frames used to measure a visibility in output */
    int binSize;
    /** Noise computation type */
    amdlibERROR_TYPE errorType;
    /** Piston computation type */
    amdlibPISTON_ALGORITHM pistonType;
    /** Forces to use the given p2vm even if its id is not OK */
    amdlibBOOLEAN noCheckP2vmId;
    /** Frame selection */
    amdlibFRAME_SELECTION frameSelectionType;
    /** Percentage of frames to be selected */
    double frameSelectionRatio;
} amdlibCPT_VIS_OPTIONS;

/* Function prototypes */
/* Version */
void amdlibGetVersion(char version[32]);
void amdlibPrintVersion(void);

/* Raw data */
amdlibCOMPL_STAT amdlibLoadRawData(const char      *filename,
                                   amdlibRAW_DATA  *rawData,
                                   amdlibERROR_MSG errMsg);

amdlibCOMPL_STAT amdlibLoadRawDataHdr(const char      *filename,
                                      amdlibRAW_DATA  *rawData,
                                      amdlibERROR_MSG errMsg);

amdlibCOMPL_STAT amdlibLoadRawFrames(const char      *filename,
                                     amdlibRAW_DATA  *rawData,
                                     int             firstFrame,
                                     int             nbFrames,
                                     amdlibERROR_MSG errMsg);
void amdlibReleaseRawData(amdlibRAW_DATA  *rawData);

amdlibCOMPL_STAT amdlibGluedImage2RawData(amdlibDOUBLE *gluedImage,
                                          int   nbRows,
                                          int   nbCols,
                                          int   colWidth[amdlibMAX_NB_COLS],
                                          int   rowHeight[amdlibMAX_NB_ROWS],
                                          amdlibRAW_DATA  *rawData,
                                          amdlibERROR_MSG errMsg);

amdlibCOMPL_STAT amdlibExtractColPos(amdlibRAW_DATA *rawData, 
                                     amdlibDOUBLE colPos[amdlibMAX_NB_COLS],
                                     amdlibDOUBLE maxVal[amdlibMAX_NB_COLS]);
amdlibCOMPL_STAT amdlibExtractSpectPos(amdlibRAW_DATA *rawData, 
                                       amdlibDOUBLE spectPos[amdlibMAX_NB_COLS]
                                                     [amdlibMAX_NB_ROWS]);

amdlibBOOLEAN amdlibIsSameDetCfg(amdlibRAW_DATA *rawData1, 
                                 amdlibRAW_DATA *rawData2);

/* Calibration maps */
amdlibCOMPL_STAT amdlibLoadBadPixelMap(const char      *filename,
                                       amdlibERROR_MSG errMsg);
amdlibCOMPL_STAT amdlibSetBadPixelMap(amdlibBOOLEAN goodPixel);

amdlibCOMPL_STAT amdlibLoadFlatFieldMap(const char           *filename,
                                        amdlibERROR_MSG      errMsg);
amdlibCOMPL_STAT amdlibSetFlatFieldMap(double value);

/* Dark data */
void amdlibReleaseDarkData(amdlibDARK_DATA *dark);
amdlibCOMPL_STAT amdlibGenerateDarkData(amdlibRAW_DATA        *rawData,
                                        amdlibDARK_DATA *dark,
                                        amdlibERROR_MSG       errMsg);
amdlibCOMPL_STAT amdlibSetDarkData (amdlibRAW_DATA  *rawData,
                                    amdlibDARK_DATA *dark,
                                    amdlibDOUBLE     value,
                                    amdlibDOUBLE     ron,
                                    amdlibERROR_MSG  errMsg);
/* Calibrated data */
amdlibCOMPL_STAT amdlibRemoveGlobalBias(amdlibRAW_DATA  *rawData,
                                        amdlibERROR_MSG  errMsg);

amdlibCOMPL_STAT amdlibCalibrateRawData(amdlibDARK_DATA *dark,
                                        amdlibRAW_DATA  *rawData,
                                        amdlibERROR_MSG  errMsg);

/* Spectral calibration */
amdlibCOMPL_STAT amdlibPerformSpectralCalibration
                                (amdlibSC_INPUT_DATA  *scData,
                                 amdlibSC_TYPE        scType,
                                 amdlibWAVEDATA       *calWaveData,
                                 amdlibERROR_MSG      errMsg);

/* Science data */
amdlibCOMPL_STAT amdlibRawData2ScienceData(amdlibRAW_DATA     *rawData,
                                           amdlibWAVEDATA     *waveData,
                                           amdlibSCIENCE_DATA *scienceData,
                                           amdlibBOOLEAN      sumData,
                                           amdlibERROR_MSG    errMsg);
void amdlibReleaseScienceData(amdlibSCIENCE_DATA  *scienceData);

/* Spectral calibration data */
amdlibCOMPL_STAT amdlibAddToSpectralCalibrationData 
                                (amdlibRAW_DATA      *rawData,
                                 amdlibSC_INPUT_DATA *spectralCalibrationData,
                                 amdlibERROR_MSG     errMsg);
amdlibCOMPL_STAT amdlibAddP2VDataToSpectralCalibrationData 
                                (amdlibRAW_DATA      *rawData,
                                 amdlibSC_INPUT_DATA *spectralCalibrationData,
                                 amdlibERROR_MSG     errMsg);
void amdlibReleaseSpectralCalibrationData
                                (amdlibSC_INPUT_DATA *spectralCalibrationData);

amdlibBAND amdlibGetBand(amdlibDOUBLE wavelength);
amdlibBAND_DESC *amdlibGetBandDescription(amdlibBAND band);
char amdlibBandNumToStr (amdlibBAND band);

amdlibCOMPL_STAT amdlibGetWaveDataFromRawData(amdlibRAW_DATA  *rawData,
                                              amdlibWAVEDATA  *waveData,
                                              amdlibERROR_MSG errMsg);
amdlibCOMPL_STAT amdlibGetWaveDataFromP2vm(amdlibP2VM_MATRIX *p2vm,
                                           amdlibWAVEDATA    *waveData,
                                           amdlibERROR_MSG    errMsg);
amdlibCOMPL_STAT amdlibGetChannelsInBand(amdlibP2VM_MATRIX  *p2vm,
                                         amdlibSCIENCE_DATA *data,
                                         amdlibWAVEDATA     *waveData,
                                         amdlibBAND         band, 
                                         int                *nbChannelsInBand,
                                         int                *channelNoInBand);

/* Spectra */
amdlibCOMPL_STAT amdlibAllocateSpectrum(amdlibSPECTRUM *spc,
                                        const int      nbTels,
                                        const int      nbWlen);
void amdlibReleaseSpectrum(amdlibSPECTRUM *spc);

amdlibCOMPL_STAT amdlibGetSpectrumFromP2VM(amdlibP2VM_MATRIX *p2vm, 
                                           amdlibWAVELENGTH  *wave,
                                           amdlibSPECTRUM    *spectrum, 
                                           amdlibERROR_MSG   errMsg);
amdlibCOMPL_STAT amdlibGetSpectrumFromScienceData (amdlibSCIENCE_DATA *data, 
                                                   amdlibWAVEDATA     *waveData,
                                                   amdlibWAVELENGTH   *wave,
                                                   amdlibSPECTRUM     *spectrum,
                                                   amdlibERROR_MSG    errMsg);
amdlibCOMPL_STAT amdlibGetAndNormalizeSpectrumFromScienceData (amdlibSCIENCE_DATA *data, 
                                                              amdlibP2VM_MATRIX *p2vm,
                                                              amdlibWAVEDATA     *waveData,
                                                              amdlibWAVELENGTH   *wave,
                                                              amdlibSPECTRUM     *spectrum,
                                                              amdlibERROR_MSG    errMsg);

/* P2VM data */
amdlibCOMPL_STAT amdlibAddToP2vmData (amdlibRAW_DATA        *rawData,
                                      amdlibWAVEDATA        *waveData,
                                      amdlibP2VM_INPUT_DATA *p2vmData,
                                      amdlibERROR_MSG       errMsg);
void amdlibReleaseP2vmData(amdlibP2VM_INPUT_DATA *p2vmData);

/* P2VM */
amdlibCOMPL_STAT amdlibComputeP2VM(amdlibP2VM_INPUT_DATA *p2vmData,
                                   amdlibP2VM_TYPE       p2vmType,
                                   amdlibWAVEDATA        *waveData,
                                   amdlibP2VM_MATRIX     *p2vm,
                                   amdlibERROR_MSG       errMsg);
void amdlibReleaseP2VM(amdlibP2VM_MATRIX *p2vm);
amdlibBOOLEAN amdlibIsValidChannel(amdlibP2VM_MATRIX *p2vm,
                                   int channelNo,
                                   int *iChannel);
amdlibBOOLEAN amdlibIsP2VMUsable(amdlibSCIENCE_DATA *scienceData,
                                 amdlibP2VM_MATRIX  *p2vm,
                                 amdlibDOUBLE              *percentage);
amdlibCOMPL_STAT amdlibSaveP2VM(const char          *filename,
                                amdlibP2VM_MATRIX   *p2vm,
                                amdlibP2VM_ACCURACY accuracy,
                                amdlibERROR_MSG     errMsg);
amdlibCOMPL_STAT amdlibLoadP2VM(const char        *filename,
                                amdlibP2VM_MATRIX *p2vm,
                                amdlibERROR_MSG   errMsg);
amdlibCOMPL_STAT amdlibDuplicateP2VM (amdlibP2VM_MATRIX *srcP2vm, 
                                      amdlibP2VM_MATRIX *dstP2vm, 
                                      amdlibERROR_MSG   errMsg);
amdlibCOMPL_STAT amdlibMergeP2VM(amdlibP2VM_MATRIX *firstP2vm,
                                 amdlibP2VM_MATRIX *secondP2vm,
                                 amdlibP2VM_MATRIX *mergedP2vm,
                                 amdlibERROR_MSG   errMsg);
amdlibCOMPL_STAT amdlibCopyP2VM(amdlibP2VM_MATRIX *srcP2vm, 
                                amdlibP2VM_MATRIX *dstP2vm, 
                                amdlibERROR_MSG   errMsg);

/* Frame selection */
amdlibCOMPL_STAT amdlibReadSelectionFile(const char      *fileName, 
                                         amdlibINS_CFG   *selKeywList,
                                         amdlibSELECTION *selectionBand,
                                         amdlibERROR_MSG errMsg);
amdlibCOMPL_STAT amdlibWriteSelectionFile(const char      *fileName,
                                          amdlibSELECTION *selection,
                                          amdlibERROR_MSG errMsg);
void amdlibReleaseSelection(amdlibSELECTION *selection);

/* Visibilities */
int amdlibComputeVisibilities(/* Input */
                              amdlibSCIENCE_DATA     *data,
                              amdlibP2VM_MATRIX      *p2vm,
                              amdlibWAVEDATA         *waveData,
                              amdlibBAND             band,
                              amdlibCPT_VIS_OPTIONS  *visOptions,
                              /* Output */
                              amdlibPHOTOMETRY       *photometry,
                              amdlibVIS              *vis,
                              amdlibVIS2             *vis2,
                              amdlibVIS3             *vis3,
                              amdlibWAVELENGTH       *wave,
                              amdlibPISTON           *opd,
                              amdlibERROR_MSG        errMsg);
int  amdlibExtractVisibilities(/* Input */
                               amdlibSCIENCE_DATA     *data,
                               amdlibP2VM_MATRIX      *p2vm,
                               amdlibWAVEDATA         *waveData,
                               amdlibBAND             band,
                               int                    nbBinning,
                               amdlibERROR_TYPE       errorType,
                               amdlibPISTON_ALGORITHM pistonType,
                               amdlibBOOLEAN         noCheckP2vmId,
                               /* Output */
                               amdlibPHOTOMETRY       *photometry,
                               amdlibVIS              *vis,
                               amdlibVIS2             *vis2,
                               amdlibVIS3             *vis3,
                               amdlibWAVELENGTH       *wave,
                               amdlibPISTON           *opd,
                               amdlibERROR_MSG        errMsg);
amdlibCOMPL_STAT 
amdlibComputeVisibilitiesFor(/* Input */
                             amdlibSCIENCE_DATA     *data,
                             amdlibP2VM_MATRIX      *p2vm,
                             amdlibWAVEDATA         *waveData,
                             int                    *channelNo,
                             int                    nbChannels,
                             int                    nbBinning,
                             amdlibERROR_TYPE       errorType,
                             amdlibPISTON_ALGORITHM pistonType,
                             amdlibBOOLEAN       noCheckP2vmId,
                             /* Output */
                             amdlibPHOTOMETRY      *photometry,
                             amdlibVIS              *vis,
                             amdlibVIS2             *vis2,
                             amdlibVIS3             *vis3,
                             amdlibWAVELENGTH       *wave,
                             amdlibPISTON           *opd,
                             amdlibERROR_MSG        errMsg);
amdlibCOMPL_STAT amdlibAverageVisibilities(amdlibPHOTOMETRY *phot,
                                           amdlibVIS        *vis, 
                                           amdlibVIS2       *vis2, 
                                           amdlibVIS3       *vis3,
                                           amdlibPISTON     *opd,
                                           amdlibBAND       band,
                                           amdlibWAVELENGTH *wave,
                                           amdlibSELECTION  *selectedFrames,
                                           amdlibERROR_MSG  errMsg);


/* Allocation functions, used for link with yorick */

amdlibCOMPL_STAT amdlibAllocatePhotometry(amdlibPHOTOMETRY *photometry,
                                          const int nbFrames,
                                          const int nbBases,
                                          const int nbWlen);
void amdlibReleasePhotometry(amdlibPHOTOMETRY *photometry);

/* Visibilities */
amdlibCOMPL_STAT amdlibAllocateVis(amdlibVIS *vis, 
                                   const int nbFrames,
                                   const int nbBases, 
                                   const int nbWlen);
void amdlibReleaseVis(amdlibVIS *vis);

/* squared Visibilities */
amdlibCOMPL_STAT amdlibAllocateVis2(amdlibVIS2 *vis2, 
                                    const int nbFrames,
                                    const int nbBases, 
                                    const int nbWlen);
void amdlibReleaseVis2(amdlibVIS2 *vis2);

/* Bispectrum, closure phase */
amdlibCOMPL_STAT amdlibAllocateVis3(amdlibVIS3 *vis3, 
                                    const int nbFrames,
                                    const int nbClosures,
                                    const int nbWlen);
void amdlibReleaseVis3(amdlibVIS3 *vis3);

/* Wavelength table */
amdlibCOMPL_STAT amdlibAllocateWavelength(amdlibWAVELENGTH *wave,
                                          const int nbWlen,
                                          amdlibERROR_MSG  errMsg);

void amdlibReleaseWavelength(amdlibWAVELENGTH *wave);

/* Piston table */
amdlibCOMPL_STAT amdlibAllocatePiston(amdlibPISTON *piston,
                                      const int nbFrames,
                                      const int nbBases);
void amdlibReleasePiston(amdlibPISTON *opd);

/* OI target table */
amdlibCOMPL_STAT amdlibAllocateOiTarget(amdlibOI_TARGET *target,
                                        const int nbElements);
void amdlibReleaseOiArray(amdlibOI_ARRAY *array);

/* OI array table */
amdlibCOMPL_STAT amdlibAllocateOiArray(amdlibOI_ARRAY *array,
                                       const int nbElements,
                                       amdlibERROR_MSG  errMsg);
void amdlibReleaseOiTarget(amdlibOI_TARGET *target);

/* OI-FITS */
amdlibCOMPL_STAT amdlibSaveOiFile(const char           *filename,
                                  amdlibINS_CFG        *insCfg,  
                                  amdlibOI_ARRAY       *array,
                                  amdlibOI_TARGET      *target,
                                  amdlibPHOTOMETRY     *photometry,
                                  amdlibVIS            *vis,
                                  amdlibVIS2           *vis2,
                                  amdlibVIS3           *vis3,
                                  amdlibWAVELENGTH     *wave, 
                                  amdlibPISTON         *pst,
                                  amdlibSPECTRUM       *spectrum,
                                  amdlibERROR_MSG      errMsg);

amdlibCOMPL_STAT amdlibLoadOiFile(const char           *filename,
                                  amdlibINS_CFG        *insCfg,  
                                  amdlibOI_ARRAY       *array,
                                  amdlibOI_TARGET      *target,
                                  amdlibPHOTOMETRY     *photometry,
                                  amdlibVIS            *vis,
                                  amdlibVIS2           *vis2,
                                  amdlibVIS3           *vis3,
                                  amdlibWAVELENGTH     *wave,
                                  amdlibPISTON         *pst,
                                  amdlibSPECTRUM       *spectrum,
                                  amdlibERROR_MSG      errMsg);

amdlibCOMPL_STAT amdlibGetOiArrayFromRawData(amdlibRAW_DATA  *rawData,
                                             amdlibOI_ARRAY  *array,
                                             amdlibERROR_MSG errMsg);

amdlibCOMPL_STAT amdlibGetOiTargetFromRawData(amdlibRAW_DATA  *data,
                                              amdlibOI_TARGET *target);



void amdlibSetUserPref(int code, amdlibDOUBLE value);

/* Backward compatibility */
#define amdlibExtractVisibilitiesFor amdlibComputeVisibilitiesFor
#ifdef __cplusplus
}
#endif


#endif /*!amdlibPublic_H*/
