/* $Id: kmo_sky_tweak.c,v 1.4 2013-09-13 09:10:28 erw Exp $
 *
 * 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
 */

/*
 * $Author: erw $
 * $Date: 2013-09-13 09:10:28 $
 * $Revision: 1.4 $
 * $Name: not supported by cvs2svn $
 */

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

#include <cpl.h>
#include <cpl_wcs.h>

#include "kmo_dfs.h"
#include "kmo_error.h"
#include "kmo_constants.h"
#include "kmo_priv_sky_tweak.h"

static int kmo_sky_tweak_create(cpl_plugin *);
static int kmo_sky_tweak_exec(cpl_plugin *);
static int kmo_sky_tweak_destroy(cpl_plugin *);
static int kmo_sky_tweak(cpl_parameterlist *, cpl_frameset *);

static char kmo_sky_tweak_description[] =
" This recipes is an advanced tool to remove OH sky lines.\n"
"\n"
"BASIC PARAMETERS:\n"
"-----------------\n"
"--tbsub\n"
"If set to TRUE subtract the thermal background from the input cube.\n"
"Default value is TRUE.\n"
"\n"
"-------------------------------------------------------------------------------\n"
"  Input files:\n"
"\n"
"   DO                    KMOS                                                  \n"
"   category              Type   Explanation                    Required #Frames\n"
"   --------              -----  -----------                    -------- -------\n"
"   CUBE_OBJECT           F3I    object cubes                       Y      >=1  \n"
"   CUBE_SKY              F3I    sky cube                           Y       1   \n"
"\n"
"  Output files:\n"
"\n"
"   DO                    KMOS\n"
"   category              Type   Explanation\n"
"   --------              -----  -----------\n"
"   OBJECT_S              F3I    Corrected object cubes\n"
"-------------------------------------------------------------------------------\n"
"\n";

/**
 * @defgroup kmo_sky_tweak kmo_sky_tweak OH line removal
 *
 * 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_sky_tweak",
                        "Removal of OH sky lines",
                        kmo_sky_tweak_description,
                        "Erich Wiezorrek",
                        "kmos-spark@mpe.mpg.de",
                        kmos_get_license(),
                        kmo_sky_tweak_create,
                        kmo_sky_tweak_exec,
                        kmo_sky_tweak_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_sky_tweak_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 */

    /* --tbsub */
    p = cpl_parameter_new_value("kmos.kmo_sky_tweak.tbsub",
                                CPL_TYPE_BOOL,
                                "Subtract thermal background from input cube."
                                "(TRUE (apply) or "
                                "FALSE (don't apply)",
                                "kmos.kmo_sky_tweak",
                                TRUE);
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "tbsub");
    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_sky_tweak_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_sky_tweak(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_sky_tweak_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_sky_tweak(cpl_parameterlist *parlist, cpl_frameset *frameset)
{
    int              ret_val                = 0;

    int              ox                     = 0,
                     nr_object_frames       = 0,
                     nr_obj_devices         = 0,
                     nr_sky_devices         = 0,
                     ifu_nr                 = 0,
                     index                  = 0,
                     tbsub                  = TRUE;
    const char       *obj_fn                = NULL,
                     *sky_fn                = NULL;

    cpl_frame        **object_frames        = NULL,
                     *object_frame          = NULL,
                     *sky_frame             = NULL;
    cpl_imagelist    *obj_data              = NULL/*,
                     *obj_noise             = NULL*/,
                     *sky_data              = NULL,
                     *tweaked_data          = NULL/*,
                     *tweaked_noise         = NULL*/;
    cpl_propertylist *main_header           = NULL,
                     *sub_header            = NULL;
    main_fits_desc   obj_fits_desc,
                     sky_fits_desc;

    KMO_TRY
    {
        //
        // check frameset
        //
        KMO_TRY_ASSURE((parlist != NULL) &&
                       (frameset != NULL),
                       CPL_ERROR_NULL_INPUT,
                       "Not all input data is provided!");

        KMO_TRY_ASSURE(! ((cpl_frameset_count_tags(frameset, CUBE_OBJECT) == 0) &&
                          (cpl_frameset_count_tags(frameset, CUBE_SKY) == 0)    ),
                          CPL_ERROR_FILE_NOT_FOUND,
                          "CUBE_OBJECT or  CUBE_SKY frames missing in "
                          "frameset!!");

        KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, CUBE_SKY) == 1,
                       CPL_ERROR_FILE_NOT_FOUND,
                       "Exactly one CUBE_SKY frame is expected in frameset!");

        KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_sky_tweak") == 1,
                       CPL_ERROR_ILLEGAL_INPUT,
                       "Cannot identify RAW and CALIB frames!");

        tbsub = kmo_dfs_get_parameter_bool(parlist, "kmos.kmo_sky_tweak.tbsub");
        KMO_TRY_CHECK_ERROR_STATE();

        nr_object_frames = cpl_frameset_count_tags(frameset, CUBE_OBJECT);
        KMO_TRY_CHECK_ERROR_STATE();

        KMO_TRY_EXIT_IF_NULL(
                object_frames = cpl_malloc(nr_object_frames * sizeof(cpl_frame*)));

        for (ox=0; ox<nr_object_frames; ox++) {
            if (ox == 0) {
                KMO_TRY_EXIT_IF_NULL(
                        object_frames[ox] = cpl_frameset_find(frameset, CUBE_OBJECT));
            } else {
                KMO_TRY_EXIT_IF_NULL(
                        object_frames[ox] =  cpl_frameset_find(frameset, NULL));
            }
            obj_fits_desc = kmo_identify_fits_header(
                        cpl_frame_get_filename(object_frames[ox]));
            KMO_TRY_CHECK_ERROR_STATE_MSG("Provided object fits file doesn't seem to be "
                                          "in KMOS-format!");
            KMO_TRY_ASSURE(obj_fits_desc.fits_type == f3i_fits,
                           CPL_ERROR_ILLEGAL_INPUT,
                           "Provided object fits file hasn't correct data type "
                           "(KMOSTYPE must be F3I)!");
            kmo_free_fits_desc(&obj_fits_desc);

        }

        KMO_TRY_EXIT_IF_NULL(
                sky_frame = cpl_frameset_find(frameset, CUBE_SKY));
        sky_fits_desc = kmo_identify_fits_header(
                    cpl_frame_get_filename(sky_frame));
        KMO_TRY_CHECK_ERROR_STATE_MSG("Provided sky fits file doesn't seem to be "
                                      "in KMOS-format!");
        KMO_TRY_ASSURE(sky_fits_desc.fits_type == f3i_fits,
                       CPL_ERROR_ILLEGAL_INPUT,
                       "Provided sky fits file hasn't correct data type "
                       "(KMOSTYPE must be F3I)!");
        if (sky_fits_desc.ex_noise == TRUE) {
            nr_sky_devices = sky_fits_desc.nr_ext / 2;
        } else {
            nr_sky_devices = sky_fits_desc.nr_ext;
        }
        KMO_TRY_EXIT_IF_NULL(
            sky_fn = cpl_frame_get_filename(sky_frame));

        for (ox=0; ox<nr_object_frames; ox++) {
            printf("ox: %d\n",ox);
            object_frame = object_frames[ox];
            obj_fits_desc = kmo_identify_fits_header(cpl_frame_get_filename(object_frame));
            KMO_TRY_CHECK_ERROR_STATE_MSG("Provided object fits file doesn't seem to be "
                                          "in KMOS-format!");
            if (obj_fits_desc.ex_noise == TRUE) {
                nr_obj_devices = obj_fits_desc.nr_ext / 2;
            } else {
                nr_obj_devices = obj_fits_desc.nr_ext;
            }
            KMO_TRY_ASSURE((nr_sky_devices == nr_obj_devices) || (nr_sky_devices == 1),
                    CPL_ERROR_ILLEGAL_INPUT,
                    "Number of extensions for the SKY frame must be either 1"
                    " or the same as for OBJECT frame");

            KMO_TRY_EXIT_IF_NULL(
                obj_fn = cpl_frame_get_filename(object_frame));

            KMO_TRY_EXIT_IF_NULL(
                main_header = kmclipm_propertylist_load(obj_fn, 0));

            KMO_TRY_EXIT_IF_ERROR(
                kmo_dfs_save_main_header(frameset, SKY_TWEAK, "",
                                         object_frame,
                                         main_header, parlist, cpl_func));


            for (ifu_nr = 1; ifu_nr <= nr_obj_devices; ifu_nr++) {
                printf("ifu_nr: %d\n", ifu_nr);
                if (nr_sky_devices == nr_obj_devices) {
                    index = kmo_identify_index(sky_fn, ifu_nr, FALSE);
                } else {
                    index = kmo_identify_index(sky_fn, 1, FALSE);
                }
                KMO_TRY_CHECK_ERROR_STATE();
                KMO_TRY_EXIT_IF_NULL(
                    sky_data = kmclipm_imagelist_load(sky_fn, CPL_TYPE_FLOAT, index));

                index = kmo_identify_index(obj_fn, ifu_nr, FALSE);
                KMO_TRY_CHECK_ERROR_STATE();
                KMO_TRY_EXIT_IF_NULL(
                    sub_header = kmclipm_propertylist_load(obj_fn, index));
                KMO_TRY_EXIT_IF_NULL(
                    obj_data = kmclipm_imagelist_load(obj_fn, CPL_TYPE_FLOAT, index));
//                index = kmo_identify_index(obj_fn, ifu_nr, TRUE);
//                KMO_TRY_CHECK_ERROR_STATE();
//                KMO_TRY_EXIT_IF_NULL(
//                    obj_noise = kmclipm_imagelist_load(obj_fn, CPL_TYPE_FLOAT, index));

                KMO_TRY_EXIT_IF_NULL(
                        tweaked_data = kmo_priv_sky_tweak (obj_data, sky_data,
                                sub_header, .3, tbsub));

                KMO_TRY_EXIT_IF_ERROR(
                    kmo_dfs_save_cube(tweaked_data, SKY_TWEAK, "", sub_header, 0./0.));
            }

            kmo_free_fits_desc(&obj_fits_desc);

        }
        kmo_free_fits_desc(&sky_fits_desc);
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_val = -1;
    }


    return ret_val;
}

/**@}*/
