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

#include <stdio.h>
#include <string.h>
#include <pslib.h>
#include "pmFPA.h"
#include "pmDetrendDB.h"

// ************* detrend select functions **************

//
static void pmDetrendSelectOptionsFree (pmDetrendSelectOptions *options)
{

    if (!options)
        return;

    psFree (options->camera);
    psFree (options->filter);

    return;
}

// define basic options for a new detrend database query
pmDetrendSelectOptions *pmDetrendSelectOptionsAlloc(char *camera, psTime time, pmDetrendType type)
{

    pmDetrendSelectOptions *options = psAlloc(sizeof(pmDetrendSelectOptions));
    psMemSetDeallocator(options, (psFreeFunc) pmDetrendSelectOptionsFree);

    // basic options required by every query
    options->camera = psMemIncrRefCounter(camera);
    options->time   = time;
    options->type   = type;

    // these other options depend on the type of detrend data
    options->filter = NULL;
    options->exptime = 0.0;
    options->airmass = 0.0;

    return options;
}

static void pmDetrendSelectResultsFree (pmDetrendSelectResults *results)
{

    if (!results)
        return;

    psFree (results->detID);

    return;
}

pmDetrendSelectResults *pmDetrendSelectResultsAlloc ()
{

    pmDetrendSelectResults *results = psAlloc(sizeof(pmDetrendSelectResults));
    psMemSetDeallocator(results, (psFreeFunc) pmDetrendSelectResultsFree);

    results->detID = NULL;
    results->level = PM_FPA_LEVEL_NONE;

    return results;
}

psString pmDetrendTypeToString (pmDetrendType type)
{

    # define DETREND_STRING_CASE(TTT) \
case PM_DETREND_TYPE_##TTT: \
    return psStringCopy (#TTT);

    switch (type) {
        DETREND_STRING_CASE (MASK);
        DETREND_STRING_CASE (BIAS);
        DETREND_STRING_CASE (DARK);
        DETREND_STRING_CASE (FLAT);
        DETREND_STRING_CASE (FLAT_CORRECTION);
        DETREND_STRING_CASE (FRINGE_IMAGE);
        DETREND_STRING_CASE (FRINGE_TABLE);
    default:
        return NULL;
    }
    return NULL;
}

// detselect -camera (camera) -time (time) -type (type) [others]
pmDetrendSelectResults *pmDetrendSelect (pmDetrendSelectOptions *options)
{
    bool status;
    char *line = NULL;

    char *time = psTimeToISO (&options->time);
    char *type = pmDetrendTypeToString (options->type);

    // generate the detselect command
    psStringAppend (&line, "detselect -camera %s -time %s -type %s", options->camera, time, type);
    psFree (time);
    psFree (type);

    // use psPipe to exec the command, wait for response
    psIOBuffer *buffer = psIOBufferAlloc (512);
    psPipe *pipe = psPipeOpen (line);
    status = psIOBufferReadEmpty (buffer, 100, pipe->stdout);
    if (!status) {
        psError (PS_ERR_IO, false, "detselect is not responding");
        psFree (buffer);
        psFree (pipe);
        psFree (line);
        return NULL;
    }
    psPipeClose (pipe);
    psFree (pipe);
    psFree (line);

    // XXX need to parse the response more robustly
    // XXX for now, assume a single line
    psArray *array = psStringSplitArray (buffer->data, " ", false);
    psFree (buffer);

    if (!array)
        return NULL;
    if (!array->n)
        return NULL;
    if (!strcasecmp(array->data[0], "ERROR"))
        return NULL;

    pmFPALevel level = pmFPALevelFromName (array->data[1]);
    if (level == PM_FPA_LEVEL_NONE)
        return NULL;

    pmDetrendSelectResults *results = pmDetrendSelectResultsAlloc();
    results->level = level;
    results->detID = psStringCopy (array->data[2]);

    psFree (array);
    return results;
}

// ************* detrend file functions **************

char *pmDetrendFile (char *detID, char *classID)
{
    bool status;
    char *line = NULL;

    // generate the detselect command
    psStringAppend (&line, "detselect -select -detID %s -classID %s", detID, classID);

    // use psPipe to exec the command, wait for response
    psIOBuffer *buffer = psIOBufferAlloc (512);
    psPipe *pipe = psPipeOpen (line);
    status = psIOBufferReadEmpty (buffer, 100, pipe->stdout);
    if (!status) {
        psError (PS_ERR_IO, false, "detselect is not responding");
        psFree (buffer);
        psFree (pipe);
        psFree (line);
        return NULL;
    }
    psPipeClose (pipe);
    psFree (pipe);
    psFree (line);

    // XXX need to parse the response more robustly
    // XXX for now, assume a single line
    psArray *array = psStringSplitArray (buffer->data, " ", false);
    psFree (buffer);

    if (!array)
        return NULL;
    if (!array->n)
        return NULL;
    if (!strcasecmp(array->data[0], "ERROR"))
        return NULL;

    char *result = psStringCopy (array->data[2]);

    psFree (array);
    return result;
}
