/*
 * This file is part of the KMOS 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

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

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

#include <cpl.h>

#include "kmo_utils.h"
#include "kmo_dfs.h"
#include "kmo_priv_fits_stack.h"
#include "kmo_error.h"

/*-----------------------------------------------------------------------------
 *                          Functions prototypes
 *----------------------------------------------------------------------------*/

static int kmo_fits_stack_create(cpl_plugin *);
static int kmo_fits_stack_exec(cpl_plugin *);
static int kmo_fits_stack_destroy(cpl_plugin *);
static int kmo_fits_stack(cpl_parameterlist *, cpl_frameset *);

/*-----------------------------------------------------------------------------
 *                          Static variables
 *----------------------------------------------------------------------------*/

static char kmo_fits_stack_description[] =
"     #############################################\n"
"     ### INTENDED FOR PIPELINE DEVELOPERS ONLY ###\n"
"     #############################################\n"
"\n"
"FITS files to be processed by the KMOS pipeline have to meet certain condi-\n"
"tions. This recipe is intended to provide to the user a simple way to test the\n"
"pipeline with own data, which wasn't produced by KMOS itself.\n"
"\n"
"The input set of frame is checked for integrity (do all the frames have the\n"
"same size, do they correspond to the desired output type, is there the correct\n"
"number of files). Then an empty main header is written with desired keywords.\n"
"A keyword consists of the name, data type and value.\n"
"Additional keywords can be added either to the empty primary header or to all\n"
"sub headers. \n"
"\n"
"BASIC PARAMETERS:\n"
"-----------------\n"
"--type\n"
"Depending on the type of the FITS file to create different combinations of\n"
"frames have to be provided:\n"
"   * RAW\n"
"     exactly 3 files tagged as STACK_DATA\n"
"   * F2D\n"
"     exactly 3 files tagged as STACK_DATA or\n"
"     exactly 6 files tagged alternating as STACK_DATA and STACK_NOISE\n"
"     (beginning with DATA)\n"
"   * B2D\n"
"     exactly 3 files tagged as STACK_BADPIX\n"
"   * F1I, F2I, F3I\n"
"     as many DATA frames as wanted (at least one) or\n"
"     as many DATA and NOISE frames as wanted (at least one of each, the number\n"
"     of STACK_DATA frames has to match the one of STACK_NOISE frames)\n"
"   * F1S\n"
"     exactly 1 file tagged as STACK_DATA\n"
"   * F1L\n"
"     exactly 1 file tagged as STACK_DATA (either plain text or binary fits\n"
"     table)\n"
"   * F2L\n"
"     exactly 1 file tagged as STACK_DATA (either plain text or binary fits)\n"
"     table)\n"
"\n"
"--mainkey\n"
"--subkey\n"
"Additional keywords can be added either to the empty primary header or to all\n"
"sub headers. Provided keywords must have following form:\n"
"   \"keyword;type;value;keyword;type;value\" (no spaces inbetween!)\n"
"Allowed values for type are: string, int, float, double, bool\n"
"\n"
"--valid\n"
"With the –valid parameter one can specifiy which values should be handled as\n"
"invalid by the pipeline. The keyword ESO OCS ARMi NOTUSED will be set accor-\n"
"dingly. When it is set to \"none\" nothing will be added.\n"
"\n"
"-------------------------------------------------------------------------------\n"
"  Input files:\n"
"\n"
"   DO                    KMOS                                                  \n"
"   category              Type   Explanation                    Required #Frames\n"
"   --------              -----  -----------                    -------- -------\n"
"   STACK_DATA            <none> >= 1 plain FITS files             Y       1-n  \n"
"   STACK_NOISE                  >= 1 plain FITS files             N       0,1-n\n"
"   or                                                                          \n"
"   STACK_BADPIXEL               3 plain FITS files                Y        3   \n"
"\n"
"  Output files:\n"
"\n"
"   DO                     KMOS\n"
"   category               Type    Explanation\n"
"   --------               -----   -----------\n"
"   FITS_STACK             RAW or  Stacked KMOS FITS file             \n"
"                          F1D or                                     \n"
"                          F2D or                                     \n"
"                          B2D or                                     \n"
"                          F1I or                                     \n"
"                          F2I or                                     \n"
"                          F3I or                                     \n"
"                          F1S or                                     \n"
"                          F1L or                                     \n"
"                          F2L                                        \n"
"-------------------------------------------------------------------------------\n"
"\n";

/*-----------------------------------------------------------------------------
 *                              Functions code
 *----------------------------------------------------------------------------*/

/**
 * @defgroup kmo_fits_stack kmo_fits_stack Creates KMOS conform fits-files
 *
 * See recipe description for details.
 */

/**@{*/

/**
  @brief    Build the list of available plugins, for this module. 
  @param    list    the plugin list
  @return   0 if everything is ok, -1 otherwise

  Create the recipe instance and make it available to the application using the 
  interface. This function is exported.
 */
int cpl_plugin_get_info(cpl_pluginlist *list)
{
    cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
    cpl_plugin *plugin = &recipe->interface;

    cpl_plugin_init(plugin,
                        CPL_PLUGIN_API,
                        KMOS_BINARY_VERSION,
                        CPL_PLUGIN_TYPE_RECIPE,
                        "kmo_fits_stack",
                        "Creates KMOS conform fits-files",
                        kmo_fits_stack_description,
                        "Alex Agudo Berbel",
                        "usd-help@eso.org",
                        kmos_get_license(),
                        kmo_fits_stack_create,
                        kmo_fits_stack_exec,
                        kmo_fits_stack_destroy);

    cpl_pluginlist_append(list, plugin);

    return 0;
}

/**
  @brief    Setup the recipe options    
  @param    plugin  the plugin
  @return   0 if everything is ok

  Defining the command-line/configuration parameters for the recipe.
 */
static int kmo_fits_stack_create(cpl_plugin *plugin)
{
    cpl_recipe *recipe;
    cpl_parameter *p;

    /* Check that the plugin is part of a valid recipe */
    if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
        recipe = (cpl_recipe *)plugin;
    else
        return -1;

    /* Create the parameters list in the cpl_recipe object */
    recipe->parameters = cpl_parameterlist_new();

    /* Fill the parameters list */
    /* --type */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.type",
                                CPL_TYPE_STRING,
                                "The KMOS data format type (either \"RAW\", "
                                "\"F1D\", \"F2D\", \"F1I\", \"F2I\", \"F3I\", "
                                "\"F1S\", \"F1L\", \"F2L\")",
                                "kmos.kmo_fits_stack",
                                "");
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "type");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --format */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.format",
                                CPL_TYPE_STRING,
                                "The format of the columns for \"F1L\" and "
                                "\"F2L\" frames: e.g. \"%f;%f;%s\"",
                                "kmos.kmo_fits_stack",
                                "");
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "format");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --title */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.title",
                                CPL_TYPE_STRING,
                                "The titles of the columns for \"F1L\" and "
                                "\"F2L\" frames: e.g. \"wavelength;strength\"",
                                "kmos.kmo_fits_stack",
                                "");
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "title");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --filename */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.filename",
                                CPL_TYPE_STRING,
                                "Optional: The output filename (.fits will be "
                                                            "added as postfix)",
                                "kmos.kmo_fits_stack",
                                FITS_STACK);
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --mainkey */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.mainkey",
                             CPL_TYPE_STRING,
                             "Optional: Additional keywords for primary header",
                             "kmos.kmo_fits_stack",
                             "");
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "mainkey");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --subkey */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.subkey",
                                CPL_TYPE_STRING,
                                "Optional: Additional keywords for sub headers"
                                "(This is ignored when category=TRUE)",
                                "kmos.kmo_fits_stack",
                                "");
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "subkey");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --valid */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.valid",
                                CPL_TYPE_STRING,
                                "Optional: Specify which IFUs are active. "
                                "Either empty string or string with 24 elements"
                                " (ones or zeros) e.g: [1;0;1;0;0;...;1]",
                                "kmos.kmo_fits_stack",
                                "");
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "valid");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --category */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.category",
                                CPL_TYPE_BOOL,
                                "Optional: IF a PRO.CATG should be added.",
                                "kmos.kmo_fits_stack",
                                0);
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "category");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --input */
    p = cpl_parameter_new_value("kmos.kmo_fits_stack.input",
                                CPL_TYPE_STRING,
                                "Optional: input file",
                                "kmos.kmo_fits_stack",
                                "");
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "input");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    return 0;
}

/**
  @brief    Execute the plugin instance given by the interface
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
static int kmo_fits_stack_exec(cpl_plugin *plugin)
{
    cpl_recipe  *recipe;

    /* Get the recipe out of the plugin */
    if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
        recipe = (cpl_recipe *)plugin;
    else return -1;

    return kmo_fits_stack(recipe->parameters, recipe->frames);
}

/**
  @brief    Destroy what has been created by the 'create' function
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
static int kmo_fits_stack_destroy(cpl_plugin *plugin)
{
    cpl_recipe *recipe;

    /* Get the recipe out of the plugin */
    if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
        recipe = (cpl_recipe *)plugin;
    else return -1 ;

    cpl_parameterlist_delete(recipe->parameters);
    return 0 ;
}

/**
  @brief    Interpret the command line options and execute the data processing
  @param    parlist     the parameters list
  @param    frameset   the frames list
  @return   0 if everything is ok

  Possible _cpl_error_code_ set in this function:

    @li CPL_ERROR_ILLEGAL_INPUT      if operator not valid,
                                     if first operand not 3d or
                                     if second operand not valid
    @li CPL_ERROR_INCOMPATIBLE_INPUT if the dimensions of the two operands
                                     do not match
 */
static int kmo_fits_stack(cpl_parameterlist *parlist, cpl_frameset *frameset)
{
    int ret_val = 0;

    KMO_TRY
    {
        ret_val = kmo_priv_fits_stack(parlist, frameset);
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();

        ret_val = -1;
    }

    return ret_val;
}

/**@}*/
