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

#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 function declaration */
static void amdlibInitSpectralCalibrationData(amdlibSC_INPUT_DATA *);

/* Public functions */
/**
 * Add raw data to the input data needed for spectral calibration. 
 *
 * This function stores the given raw data, which should be calibrated, into the
 * spectral calibration data structure. 
 *
 * @param rawData raw data to be added to spectral calibration data.
 * @param specCalData structure where data for spectral calibration will be
 * stored
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAddToSpectralCalibrationData (
                                amdlibRAW_DATA      *rawData,
                                amdlibSC_INPUT_DATA *specCalData,
                                amdlibERROR_MSG     errMsg)
{
    int i;

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

    /* 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 != amdlibTEL1_FRAME) &&
        (rawData->frameType != amdlibTEL2_FRAME) &&
        (rawData->frameType != amdlibTEL3_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 spectral "
                        "calibration: must be 1", rawData->nbRows);
        return amdlibFAILURE;
    }

    /* Check if this frame type is already loaded */
    i = rawData->frameType - amdlibTEL1_FRAME;
    if (specCalData->dataLoaded[i] == amdlibTRUE)
    {
        amdlibSetErrMsg("Frame type %d already loaded (see amdlibFRAME_TYPE)",
                        rawData->frameType);
        return amdlibFAILURE;
    }

    if (amdlibDuplicateRawData(rawData, &specCalData->rawData[i],
                               errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }
    specCalData->dataLoaded[i] = amdlibTRUE;

    return amdlibSUCCESS;
}

amdlibCOMPL_STAT amdlibAddP2VDataToSpectralCalibrationData (
                                amdlibRAW_DATA      *rawData,
                                amdlibSC_INPUT_DATA *specCalData,
                                amdlibERROR_MSG     errMsg)
{
    int i;

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

    /* 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. Return immediately if not the good ones */
    if ((rawData->frameType != amdlibTEL1_FRAME) &&
        (rawData->frameType != amdlibTEL2_FRAME) &&
        (rawData->frameType != amdlibTEL3_FRAME))
    {
        return amdlibSUCCESS;
    }

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

    /* Check if this frame type is already loaded at its good place */
    i = rawData->frameType - amdlibTEL1_FRAME + 3;
    if (specCalData->dataLoaded[i] == amdlibTRUE)
    {
        amdlibSetErrMsg("Frame type %d already loaded (see amdlibFRAME_TYPE)",
                        rawData->frameType);
        return amdlibFAILURE;
    }

    if (amdlibDuplicateRawData(rawData, &specCalData->rawData[i],
                               errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }
    specCalData->dataLoaded[i] = amdlibTRUE;

    return amdlibSUCCESS;
}

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

    amdlibLogTrace("amdlibReleaseSpectralCalibrationData()");
    
    for (image = 0; image < amdlibMAX_NB_FRAMES_SC; image++)
    {
        amdlibReleaseRawData(&specCalData->rawData[image]);
        specCalData->dataLoaded[image] = amdlibFALSE;
    }
    memset(specCalData, '\0', sizeof(amdlibSC_INPUT_DATA));
}

/* 
 * Local functions 
 */
/**
 * Initialize spectral calibration data structure.
 *
 * @warning 
 * This function must be called first before using a new 'spectral calibration
 * data' structure.
 *
 * @param specCalData pointer to spectral calibration data structure
 */
void amdlibInitSpectralCalibrationData(amdlibSC_INPUT_DATA *specCalData)
{
    int i;

    amdlibLogTrace("amdlibInitSpectralCalibrationData()");
    
    /* Initialize data structure */
    memset (specCalData, '\0', sizeof(amdlibSC_INPUT_DATA));
    specCalData->thisPtr = specCalData;

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

/*___oOo___*/

