/*******************************************************************************
 * JMMC project ( http://www.jmmc.fr ) - Copyright (C) CNRS.
 ******************************************************************************/
/**
 * @file
 * Functions to handle data used for P2VM computation. 
 */

#define _POSIX_SOURCE 1

/* 
 * System Headers
 */
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fitsio.h"
/* 
 * Local Headers
 */
#include "amdlib.h"
#include "amdlibProtected.h"

/* Local functions declaration */
static void amdlibInitP2vmData(amdlibP2VM_INPUT_DATA *p2vmData);

/*
 * Public functions
 */
/**
 * Add data to P2Vm data structure. 
 *
 * This function converts the given raw data, which should be calibrated, to
 * science data, and then stores into the P2VM data structure. 
 *
 * @param rawData raw data to be added to P2VM calibration data.
 * @param waveData wave data used during science data conversion; could be null
 * pointer, see amdlibRawData2ScienceData().
 * @param p2vmData structure where data for P2VM calibration will be stored
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAddToP2vmData (amdlibRAW_DATA        *rawData,
                                      amdlibWAVEDATA        *waveData,
                                      amdlibP2VM_INPUT_DATA *p2vmData,
                                      amdlibERROR_MSG       errMsg)
{
    int i, j;

    amdlibLogTrace("amdlibAddToP2vmData()");
    
    /* If data structure is not initialized, do it */
    if (p2vmData->thisPtr != p2vmData)
    {
        /* Initialise data structure */
        amdlibInitP2vmData(p2vmData);
    }

    /* Check raw data structure contains data */
    if (rawData->dataLoaded == amdlibFALSE)
    {
        amdlibSetErrMsg("The raw data structure does not "
                        "contain data. Check call to amdlibLoadRawData()");
        return amdlibFAILURE;
    }

    /* Check frame type */
    if ((rawData->frameType == amdlibDARK_FRAME) ||
        (rawData->frameType == amdlibTEL123_FRAME) ||
        (rawData->frameType == amdlibUNKNOWN_FRAME))
    {
        amdlibSetErrMsg("Invalid frame type %d (see amdlibFRAME_TYPE)",
                        rawData->frameType);
        return amdlibFAILURE;
    }

    /* Check the raw data only contains 1 row */
    if (rawData->nbRows != 1)
    {
        amdlibSetErrMsg("Wrong number of data rows (%d) for"
                        " P2VM computation. Must be 1", rawData->nbRows);
        return amdlibFAILURE;
    }

    /* Check if this frame type is already loaded */
    j = rawData->frameType - amdlibTEL1_FRAME;
    if (p2vmData->dataLoaded[j] == amdlibTRUE)
    {
        amdlibSetErrMsg("Frame type %d already loaded"
                        "(see amdlibFRAME_TYPE)", rawData->frameType);
        return amdlibFAILURE;
    }
    
    /* Store calibrated data into P2VM data structure */ 
    if (amdlibRawData2ScienceData(rawData, waveData, &p2vmData->scienceData[j],
                                  amdlibTRUE, errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }
    p2vmData->dataLoaded[j] = amdlibTRUE;
    p2vmData->nbFrames = rawData->nbFrames;

#if amdlibDEBUG
    amdlibLogTest("scienceData pour %d ajoutee", j);
    amdlibDisplayScienceData(&p2vmData->scienceData[j]);
#endif

    /* Get DATE keyword used to compute P2VM id */
    for (i=0; i < rawData->insCfg.nbKeywords; i++)
    {
        double obsDate;
        if ( strncmp(rawData->insCfg.keywords[i].name, "MJD-OBS", 7) == 0)
        {
            sscanf(rawData->insCfg.keywords[i].value, "%lf", &obsDate);
            /* Convert MJD to minutes from 01/01/2000 */
            /* Note that MJD is given from 17/11/1858, and 51544 is the number
             * of days between 01/01/2000 and this date.*/
            obsDate = (obsDate-51544.0)*1440;
            p2vmData->p2vmId += obsDate;
            break;
        }
    }
    return amdlibSUCCESS;
}

/**
 * Free memory allocated memory of P2VM data structure.
 *
 * This function frees previously allocated memory (if any) where data for
 * P2VM has been stored, and resets all the structure fields, including thisPtr
 * pointer.
 *
 * @param p2vmData structure where data for P2VM calibration is stored
 */
void amdlibReleaseP2vmData(amdlibP2VM_INPUT_DATA *p2vmData)
{
    int image;

    amdlibLogTrace("amdlibReleaseP2vmData()");
    
    for (image = 0; image < amdlibMAX_NB_FRAMES_P2VM; image++)
    {
        amdlibFreeScienceData(&p2vmData->scienceData[image]);
        p2vmData->dataLoaded[image] = amdlibFALSE;
    }

    amdlibInitP2vmData(p2vmData);

    memset (p2vmData, '\0', sizeof(amdlibP2VM_INPUT_DATA));
}

/*
 * Local function definition
 */
/**
 * Initialize P2VM data structure.
 *
 * @warning 
 * This function must be called first before using a new 'spectral calibration
 * data' structure.
 *
 * @param p2vmData structure where data for P2VM calibration is stored
 */
void amdlibInitP2vmData(amdlibP2VM_INPUT_DATA *p2vmData)
{
    int i;

    amdlibLogTrace("amdlibInitP2vmData()");

    /* Initialize data structure */
    memset (p2vmData, '\0', sizeof(amdlibP2VM_INPUT_DATA));
    p2vmData->thisPtr = p2vmData;

    for (i = 0; i < amdlibMAX_NB_FRAMES_P2VM; i++)
    {
        p2vmData->dataLoaded[i] = amdlibFALSE;
    }
}

/*___oOo___*/
