/* $Id: naco_parameter.c,v 1.31 2011-11-18 09:05:51 llundin Exp $
 *
 * This file is part of the NACO 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., 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */

/*
 * $Author: llundin $
 * $Date: 2011-11-18 09:05:51 $
 * $Revision: 1.31 $
 * $Name: not supported by cvs2svn $
 */

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

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

#include <string.h>
#include <math.h>
#include <float.h>
#include <assert.h>
#include <cpl.h>

#include <irplib_stdstar.h>
#include <irplib_strehl.h>

#include "irplib_utils.h"

#include "naco_parameter.h"
#include "naco_dfs.h"
#include "naco_pfits.h"

/*-----------------------------------------------------------------------------
                                   Define
 -----------------------------------------------------------------------------*/

#define naco_plot_manpage                                       \
    "The recipe can produce a number of predefined plots. "     \
    "Zero means that none of the plots are produced, while "    \
    "increasing values (e.g. 1 or 2) increases the number "     \
    "of plots produced. If the plotting fails a warning is "    \
    "produced, and the recipe continues. "                      \
    "The default behaviour of the plotting is to use "          \
    "gnuplot (with option -persist). The recipe currently "     \
    "produces 1D-plots using gnuplot commands. The recipe "     \
    "user can control the actual plotting-command used by "     \
    "the recipe to create the plot by setting the "             \
    "environment variable CPL_PLOTTER. Currently, if "          \
    "CPL_PLOTTER "                                              \
    "is set it must contain the string 'gnuplot'. Setting "     \
    "it to 'cat > my_gnuplot_$$.txt' causes a number of "       \
    "ASCII-files to be created, which each produce a plot "     \
    "when given as standard input to gnuplot (e.g. later "      \
    "or on a different computer). A finer control of the "      \
    "plotting options can be obtained by writing an "           \
    "executable script, e.g. my_gnuplot.pl, that "              \
    "executes gnuplot after setting the desired gnuplot "       \
    "options (e.g. set terminal pslatex color) "                \
    "and then setting CPL_PLOTTER to my_gnuplot.pl. "           \
    "The predefined plots include plotting of images. "         \
    "Images can be plotted not only with gnuplot, but also "    \
    "using the pnm format. This is controlled with the "        \
    "environment variable CPL_IMAGER. If CPL_IMAGER "           \
    "is set to a string that does not contain the word "        \
    "gnuplot, the recipe will generate the plot in pnm "        \
    "format. E.g. setting CPL_IMAGER to "                       \
    "'display - &' will produce a gray-scale image "            \
    "using the image viewer display."


#define NACO_XCORR_SX            10
#define NACO_XCORR_SY            10

/* To be called from naco_parameter_set() */
#define NACO_PARAMETER_SET(MASK, VARNAME, TYPE, MAN, DEFAULT, SHORT)           \
if (bitmask & MASK) {                                                          \
    char * paramname = cpl_sprintf(PACKAGE ".%s." VARNAME, recipe);            \
                                                                               \
    p = cpl_parameter_new_value(paramname, TYPE, MAN, context, DEFAULT);       \
    cpl_free(paramname);                                                       \
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, SHORT);                 \
    cpl_parameterlist_append(self, p);                                         \
                                                                               \
    if (cpl_error_get_code()) /* Propagate error */                            \
        (void)cpl_error_set_where(cpl_func);                                   \
                                                                               \
    bitmask ^= MASK; /* Reset bit. At the end bitmask must be zero */          \
                                                                               \
    /* Verify that each mask value is unique */                                \
    if (chkmask & MASK)                                                        \
        (void)cpl_error_set(cpl_func, CPL_ERROR_UNSPECIFIED);                  \
    chkmask |= MASK;                                                           \
                                                                               \
}

/* To be called from naco_parameterlist_get_bool() */
#define NACO_PARAMETER_GET_BOOL(MASK, VARNAME)                                 \
if (bitmask & MASK) {                                                          \
    value = irplib_parameterlist_get_bool(self, PACKAGE, recipe, VARNAME);     \
                                                                               \
    cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), CPL_FALSE);        \
                                                                               \
    nbits++;         /* Total number of bits must be one  */                   \
    bitmask ^= MASK; /* - bitmask must be zero at the end */                   \
                                                                               \
}

/* To be called from naco_parameterlist_get_int() */
#define NACO_PARAMETER_GET_INT(MASK, VARNAME)                                  \
if (bitmask & MASK) {                                                          \
    value = irplib_parameterlist_get_int(self, PACKAGE, recipe, VARNAME);      \
                                                                               \
    cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), 0);                \
                                                                               \
    nbits++;         /* Total number of bits must be one  */                   \
    bitmask ^= MASK; /* - bitmask must be zero at the end */                   \
                                                                               \
}

/* To be called from naco_parameterlist_get_double() */
#define NACO_PARAMETER_GET_DOUBLE(MASK, VARNAME)                               \
if (bitmask & MASK) {                                                          \
    value = irplib_parameterlist_get_double(self, PACKAGE, recipe, VARNAME);   \
                                                                               \
    cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), 0.0);              \
                                                                               \
    nbits++;         /* Total number of bits must be one  */                   \
    bitmask ^= MASK; /* - bitmask must be zero at the end */                   \
                                                                               \
}

/* To be called from naco_parameterlist_get_string() */
#define NACO_PARAMETER_GET_STRING(MASK, VARNAME)                               \
if (bitmask & MASK) {                                                          \
    value = irplib_parameterlist_get_string(self, PACKAGE, recipe, VARNAME);   \
                                                                               \
    cpl_ensure(value != NULL, cpl_error_get_code(), NULL);                     \
                                                                               \
    nbits++;         /* Total number of bits must be one  */                   \
    bitmask ^= MASK; /* - bitmask must be zero at the end */                   \
                                                                               \
}


/*----------------------------------------------------------------------------*/
/**
 * @defgroup naco_parameter NACO recipe parameters
 *
 * TBD
 */
/*----------------------------------------------------------------------------*/

/**@{*/


/*----------------------------------------------------------------------------*/
/**
  @brief    Define the specified parameters
  @param    self     The parameterlist to set
  @param    recipe   The recipe name
  @param    bitmask  parameter specification
  @return   CPL_ERROR_NONE or the relevant CPL error code on error

 */
/*----------------------------------------------------------------------------*/
cpl_error_code naco_parameter_set(cpl_parameterlist * self,
                                  const char * recipe,
                                  naco_parameter bitmask)
{

    cpl_parameter * p;
    char * context;
    naco_parameter chkmask = 0; /* Verify that each mask value is unique */


    cpl_ensure_code(self,   CPL_ERROR_NULL_INPUT);
    cpl_ensure_code(recipe, CPL_ERROR_NULL_INPUT);


    context = cpl_sprintf(PACKAGE ".%s", recipe);

    /* --xtmax */
    NACO_PARAMETER_SET(NACO_PARAM_XTMAX, "extract_max", CPL_TYPE_INT,
                       "Stop the spectrum extraction at this column", 1024,
                       "xtmax");

    /* --xtmin */
    NACO_PARAMETER_SET(NACO_PARAM_XTMIN, "extract_min", CPL_TYPE_INT,
                       "Start the spectrum extraction at this column", 1,
                       "xtmin");

    /* --save */
    NACO_PARAMETER_SET(NACO_PARAM_SAVE, "save", CPL_TYPE_INT,
                       "A positive value causes additional, intermediate "
                       "products to be saved", 0, "save");

    /* --plot */
    NACO_PARAMETER_SET(NACO_PARAM_PLOT, "plot", CPL_TYPE_INT,
                       naco_plot_manpage, 0, "plot");

    /* --star_r */
    NACO_PARAMETER_SET(NACO_PARAM_STAR_R, "star_r", CPL_TYPE_DOUBLE,
                       "The star radius [arcsecond]",
                       IRPLIB_STREHL_STAR_RADIUS, "star_r");

    /* --bg_r1 */
    NACO_PARAMETER_SET(NACO_PARAM_BG_RINT, "bg_r1", CPL_TYPE_DOUBLE,
                       "The internal radius of the background [arcsecond]",
                       IRPLIB_STREHL_BACKGROUND_R1, "bg_r1");

    /* --bg_r2 */
    NACO_PARAMETER_SET(NACO_PARAM_BG_REXT, "bg_r2", CPL_TYPE_DOUBLE,
                       "The external radius of the background [arcsecond]",
                       IRPLIB_STREHL_BACKGROUND_R2, "bg_r2");

    /* --r */
    NACO_PARAMETER_SET(NACO_PARAM_REJBORD, "rej_bord", CPL_TYPE_STRING,
                       "Rejected left right bottom and top border [pixel]",
                       "200 200 200 200", "r");

    /* --hot_t */
    NACO_PARAMETER_SET(NACO_PARAM_HOT_LIM, "hot_threshold", CPL_TYPE_DOUBLE,
                       "Hot pixel map threshold", 10.0, "hot_t");

    /* --cold_t */
    NACO_PARAMETER_SET(NACO_PARAM_COLD_LIM, "cold_threshold", CPL_TYPE_DOUBLE,
                       "Cold pixel map threshold", 6.0, "cold_t");

    /* --dev_t */
    NACO_PARAMETER_SET(NACO_PARAM_DEV_LIM, "dev_threshold", CPL_TYPE_DOUBLE,
                       "Deviant pixel map threshold", 5.0, "dev_t");

    /* --nsamples */
    NACO_PARAMETER_SET(NACO_PARAM_NSAMPLES, "nsamples", CPL_TYPE_INT,
                       "Number of samples for RON computation", 100,
                       "nsamples");

    /* --hsize */
    NACO_PARAMETER_SET(NACO_PARAM_HALFSIZE, "hsize", CPL_TYPE_INT,
                       "Half size of the window for RON computation", 2,
                       "hsize");

    /* --force */
    NACO_PARAMETER_SET(NACO_PARAM_FORCE, "force", CPL_TYPE_BOOL,
                       "Force the computation", FALSE, "force");

    /* --slit_w */
    NACO_PARAMETER_SET(NACO_PARAM_SLIT_W, "slit_width", CPL_TYPE_INT,
                       "Slit width", 20, "slit_w");

    /* --t */
    NACO_PARAMETER_SET(NACO_PARAM_BPMTHRES, "thresholds", CPL_TYPE_STRING,
                       "Low and high thresholds for the Bad Pixel Map",
                       "0.5 2.0", "t");

    /* --prop */
    NACO_PARAMETER_SET(NACO_PARAM_PROPFIT, "proport", CPL_TYPE_BOOL,
                       "Use the proportional fit", FALSE, "prop");

    /* --bpm */
    NACO_PARAMETER_SET(NACO_PARAM_BPM, "bpm", CPL_TYPE_BOOL,
                       "Create the bad pixel map", FALSE, "bpm");

    /* --errmap */
    NACO_PARAMETER_SET(NACO_PARAM_ERRORMAP, "errmap", CPL_TYPE_BOOL,
                       "Create the error map", FALSE, "errmap");

    /* --intercept */
    NACO_PARAMETER_SET(NACO_PARAM_INTCEPT, "intercept", CPL_TYPE_BOOL,
            "Create the intercept image", FALSE, "intercept");

    /* --ra */
    NACO_PARAMETER_SET(NACO_PARAM_RA, "ra", CPL_TYPE_DOUBLE,
                       "Right Ascension [Degrees]", 999.0, "ra");

    /* --dec */
    NACO_PARAMETER_SET(NACO_PARAM_DEC, "dec", CPL_TYPE_DOUBLE,
                       "DEClination  [Degrees]", 999.0, "dec");

    /* --pscale */
    NACO_PARAMETER_SET(NACO_PARAM_PIXSCALE, "pscale", CPL_TYPE_DOUBLE,
                       "Pixel scale", -1.0, "pscale");

    /* --mag */
    NACO_PARAMETER_SET(NACO_PARAM_MAGNITD, "mag", CPL_TYPE_DOUBLE,
                       "Magnitude", IRPLIB_STDSTAR_NOMAG, "mag");

    /* --sx */
    NACO_PARAMETER_SET(NACO_PARAM_SX, "sx", CPL_TYPE_INT, 
                       "Size of the search window in X-direction [pixel]",
                       NACO_XCORR_SX, "sx");

    /* --sy */
    NACO_PARAMETER_SET(NACO_PARAM_SY, "sy", CPL_TYPE_INT, 
                       "Size of the search window in Y-direction [pixel]",
                       NACO_XCORR_SY, "sy");

    /* --check_im */
    NACO_PARAMETER_SET(NACO_PARAM_CHK_IMG, "check_im", CPL_TYPE_BOOL,
                       "Create the check image", FALSE, "check_im");


    /* --off */
    NACO_PARAMETER_SET(NACO_PARAM_OFFSETS, "offsets", CPL_TYPE_STRING,
                       "An optional ASCII specification of the offsets "
                       "in case those in FITS-headers are missing or wrong. "
                       "The file must consist of one line per object FITS-"
                       "file and each line must consist of two "
                       "numbers which represent the shift in pixels of that "
                       "image relative to the first image. The first line "
                       "should thus comprise two zeros. Correct FITS-header "
                       "offsets mean that the i'th X offset can be gotten "
                       "from Xoffset_0 - Xoffset_i, where Xoffset_i is the "
                       "value of " NACO_PFITS_DOUBLE_CUMOFFSETX " and "
                       "likewise for Y.", NULL, "off");

    /* --objs */
    NACO_PARAMETER_SET(NACO_PARAM_OBJECTS, "objects", CPL_TYPE_STRING,
                       "objects file", NULL, "objs");

    /* --oddeven */
    NACO_PARAMETER_SET(NACO_PARAM_ODDEVEN, "oddeven", CPL_TYPE_BOOL,
                       "Apply the odd-even correction. Warning: This flag "
                       "currently has no effect", CPL_FALSE, "oddeven");

    /* --xcorr */
    NACO_PARAMETER_SET(NACO_PARAM_XCORR, "xcorr", CPL_TYPE_STRING,
                       "Cross correlation search and measure sizes",
                       "40 40 65 65", "xcorr");

    /* --union */
    NACO_PARAMETER_SET(NACO_PARAM_UNION, "union", CPL_TYPE_BOOL,
                       "Combine images using their union, as opposed to their "
                       "intersection (deprecated and ignored, "
                       "see --combine_method)", TRUE, "union");

    /* --rej */
    NACO_PARAMETER_SET(NACO_PARAM_REJ_HILO, "rej", CPL_TYPE_STRING,
                       "Low and high number of rejected values", "2 2", "rej");

    /* --comb_meth */
    /* Copied from visir */
    /* FIXME: Use cpl_parameter_new_enum() */
    NACO_PARAMETER_SET(NACO_PARAM_COMBINE, "comb_meth", CPL_TYPE_STRING,
                       "Combine images using one of: 1) Onto the first image "
                       "(first); 2) Their union (union); 3) Their intersection"
                       " (inter). NB: Only the 'first'-method produces an "
                       "image product with WCS coordinates. A successful "
                       "'first'-method always produces a combined image with "
                       "dimensions equal to those of the input images. "
                       "For the 'union'-method the result image is at least "
                       "as large as the input images while for the 'inter'-"
                       "method the result image is at most as large as the "
                       "input images", "union", "combine_method");

    /* --sky_planes */
    NACO_PARAMETER_SET(NACO_PARAM_SKYPLANE, "sky_planes", CPL_TYPE_INT,
                       "Estimate the sky using the median of the last n planes "
                       "in the previous cube and the first n planes in the "
                       "following cube. If the cube has less than n planes "
                       "then use all planes. Zero means all. (Ignored for non-"
                       "cube data)", 25, "sky_planes");

    /* --cube_mode */
    NACO_PARAMETER_SET(NACO_PARAM_CUBEMODE, "cube_mode", CPL_TYPE_STRING,
                       "Collapse cube data using one of: 1) No recentering "
                       "(add); 2) Shift-and-Add (saa). (Ignored for non-"
                       "cube data)", "saa", "cube_mode");

    /* --lucky_strehl */
    NACO_PARAMETER_SET(NACO_PARAM_LUCK_STR, "lucky_strehl", CPL_TYPE_DOUBLE,
                       "In cube mode use only the frames with a strehl ratio "
                       "in the given top fraction. (Ignored for non-"
                       "cube data)", 1.0, "lucky");

    /* --save_cube */
    NACO_PARAMETER_SET(NACO_PARAM_SAVECUBE, "save_cube", CPL_TYPE_BOOL,
                       "Append the cube of corrected object images that are "
                       "shifted added together to the product", FALSE,
                       "save_cube");

    cpl_free(context);

    cpl_ensure_code(bitmask == 0, CPL_ERROR_UNSUPPORTED_MODE);

    /* Propagate error, if any */
    return cpl_error_set_where(cpl_func);
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Retrieve the value of a NACO boolean parameter 
  @param    self     The parameterlist to get from
  @param    recipe   The recipe name
  @param    bitmask  parameter specification
  @return   The boolean value, or CPL_FALSE on error
  @note     If called with a pre-existing error, the function will do nothing.

 */
/*----------------------------------------------------------------------------*/
cpl_boolean naco_parameterlist_get_bool(const cpl_parameterlist * self,
                                        const char * recipe,
                                        naco_parameter bitmask)
{

    int nbits = 0;
    cpl_boolean value = CPL_FALSE; /* Avoid (false) uninit warning */


    cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), CPL_FALSE);
    cpl_ensure(self,   CPL_ERROR_NULL_INPUT, CPL_FALSE);
    cpl_ensure(recipe, CPL_ERROR_NULL_INPUT, CPL_FALSE);

    /* --force */
    NACO_PARAMETER_GET_BOOL(NACO_PARAM_FORCE, "force");

    /* --prop */
    NACO_PARAMETER_GET_BOOL(NACO_PARAM_PROPFIT, "proport");

    /* --bpm */
    NACO_PARAMETER_GET_BOOL(NACO_PARAM_BPM, "bpm");

    /* --errmap */
    NACO_PARAMETER_GET_BOOL(NACO_PARAM_ERRORMAP, "errmap");

    /* --intercept */
    NACO_PARAMETER_GET_BOOL(NACO_PARAM_INTCEPT, "intercept");

    /* --check_im */
    NACO_PARAMETER_GET_BOOL(NACO_PARAM_CHK_IMG, "check_im");

    /* --oddeven */
    NACO_PARAMETER_GET_BOOL(NACO_PARAM_ODDEVEN, "oddeven");

    /* --save_cube */
    NACO_PARAMETER_GET_BOOL(NACO_PARAM_SAVECUBE, "save_cube");

    cpl_ensure(bitmask == 0, CPL_ERROR_UNSUPPORTED_MODE, CPL_FALSE);
    cpl_ensure(nbits == 1,   CPL_ERROR_ILLEGAL_INPUT, CPL_FALSE);

    return value;

}

/*----------------------------------------------------------------------------*/
/**
  @brief    Retrieve the value of a NACO integer parameter 
  @param    self     The parameterlist to get from
  @param    recipe   The recipe name
  @param    bitmask  parameter specification
  @return   The integer value, or zero on error
  @note     If called with a pre-existing error, the function will do nothing.

 */
/*----------------------------------------------------------------------------*/
int naco_parameterlist_get_int(const cpl_parameterlist * self,
                               const char * recipe,
                               naco_parameter bitmask)
{

    int nbits = 0;
    int value = 0; /* Avoid (false) uninit warning */


    cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), 0);
    cpl_ensure(self,   CPL_ERROR_NULL_INPUT, 0);
    cpl_ensure(recipe, CPL_ERROR_NULL_INPUT, 0);


    /* Must give the long name here */

    /* --xtmax */
    NACO_PARAMETER_GET_INT(NACO_PARAM_XTMAX, "extract_max");

    /* --xtmin */
    NACO_PARAMETER_GET_INT(NACO_PARAM_XTMIN, "extract_min");

    /* --save */
    NACO_PARAMETER_GET_INT(NACO_PARAM_SAVE, "save");

    /* --plot */
    NACO_PARAMETER_GET_INT(NACO_PARAM_PLOT, "plot");

    /* --nsamples */
    NACO_PARAMETER_GET_INT(NACO_PARAM_NSAMPLES, "nsamples");

    /* --hsize */
    NACO_PARAMETER_GET_INT(NACO_PARAM_HALFSIZE, "hsize");

    /* --sx */
    NACO_PARAMETER_GET_INT(NACO_PARAM_SX, "sx");

    /* --sy */
    NACO_PARAMETER_GET_INT(NACO_PARAM_SY, "sy");

    /* --slit_w */
    NACO_PARAMETER_GET_INT(NACO_PARAM_SLIT_W, "slit_width");

    /* --sky_planes */
    NACO_PARAMETER_GET_INT(NACO_PARAM_SKYPLANE, "sky_planes");

    cpl_ensure(bitmask == 0, CPL_ERROR_UNSUPPORTED_MODE, 0);
    cpl_ensure(nbits == 1,   CPL_ERROR_ILLEGAL_INPUT, 0);

    return value;

}

/*----------------------------------------------------------------------------*/
/**
  @brief    Retrieve the value of a NACO parameter of type double
  @param    self     The parameterlist to get from
  @param    recipe   The recipe name
  @param    bitmask  parameter specification
  @return   The value, or undefined on error
  @note     If called with a pre-existing error, the function will do nothing.

 */
/*----------------------------------------------------------------------------*/
double naco_parameterlist_get_double(const cpl_parameterlist * self,
                                     const char * recipe,
                                     naco_parameter bitmask)
{

    int nbits = 0;
    double value = DBL_MAX; /* Avoid (false) uninit warning */


    cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), 0.0);
    cpl_ensure(self,   CPL_ERROR_NULL_INPUT, 0.0);
    cpl_ensure(recipe, CPL_ERROR_NULL_INPUT, 0.0);


    /* --star_r */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_STAR_R, "star_r");

    /* --bg_r1 */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_BG_RINT, "bg_r1");

    /* --bg_r2 */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_BG_REXT, "bg_r2");


    /* --hot_t */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_HOT_LIM, "hot_threshold");

    /* --cold_t */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_COLD_LIM, "cold_threshold");

    /* --dev_t */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_DEV_LIM, "dev_threshold");

    /* --ra */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_RA, "ra");

    /* --dec */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_DEC, "dec");

    /* --pscale */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_PIXSCALE, "pscale");

    /* --mag */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_MAGNITD, "mag");

    /* --lucky_strehl */
    NACO_PARAMETER_GET_DOUBLE(NACO_PARAM_LUCK_STR, "lucky_strehl");


    cpl_ensure(bitmask == 0, CPL_ERROR_UNSUPPORTED_MODE, 0.0);
    cpl_ensure(nbits == 1,   CPL_ERROR_ILLEGAL_INPUT, 0.0);

    return value;

}

/*----------------------------------------------------------------------------*/
/**
  @brief    Retrieve the value of a NACO string parameter 
  @param    self     The parameterlist to get from
  @param    recipe   The recipe name
  @param    bitmask  parameter specification
  @return   The string, or NULL on error

 */
/*----------------------------------------------------------------------------*/
const char * naco_parameterlist_get_string(const cpl_parameterlist * self,
                                           const char * recipe,
                                           naco_parameter bitmask)
{

    int nbits = 0;
    const char * value = NULL; /* Avoid (false) uninit warning */
    const cpl_boolean is_combine
        = bitmask & NACO_PARAM_COMBINE ? CPL_TRUE : CPL_FALSE;

    cpl_ensure(self,   CPL_ERROR_NULL_INPUT, NULL);
    cpl_ensure(recipe, CPL_ERROR_NULL_INPUT, NULL);


    /* --r */
    NACO_PARAMETER_GET_STRING(NACO_PARAM_REJBORD, "rej_bord");

    /* --t */
    NACO_PARAMETER_GET_STRING(NACO_PARAM_BPMTHRES, "thresholds");

    /* --off */
    NACO_PARAMETER_GET_STRING(NACO_PARAM_OFFSETS, "offsets");

    /* --objs */
    NACO_PARAMETER_GET_STRING(NACO_PARAM_OBJECTS, "objects");

    /* --xcorr */
    NACO_PARAMETER_GET_STRING(NACO_PARAM_XCORR, "xcorr");

    /* --rej */
    NACO_PARAMETER_GET_STRING(NACO_PARAM_REJ_HILO, "rej");

    /* --combine */
    NACO_PARAMETER_GET_STRING(NACO_PARAM_COMBINE, "comb_meth");

    /* --cube_mode */
    NACO_PARAMETER_GET_STRING(NACO_PARAM_CUBEMODE, "cube_mode");


    cpl_ensure(bitmask == 0, CPL_ERROR_UNSUPPORTED_MODE, NULL);
    cpl_ensure(nbits == 1,   CPL_ERROR_ILLEGAL_INPUT, NULL);

    assert(value != NULL);

    /* FIXME: This should be handled by the enum */
    if (is_combine)
        cpl_ensure(strcmp(value, "first") == 0 || strcmp(value, "union") == 0 ||
                   strcmp(value, "intersect") == 0, CPL_ERROR_UNSUPPORTED_MODE,
                   NULL);

    return value;
}

/**@}*/
