/* 
 * This file is part of the HAWKI 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

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

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

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

#include <hawki_dfs.h>
#include <hawki_load.h>
#include <hawki_save.h>
#include <hawki_pfits.h>
#include <hawki_image_stats.h>
#include <hawki_utils.h>


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

#ifdef __cplusplus
extern "C"
#endif
int cpl_plugin_get_info(cpl_pluginlist * list);

static int hawki_tec_filtchk_create(cpl_plugin *) ;
static int hawki_tec_filtchk_exec(cpl_plugin *) ;
static int hawki_tec_filtchk_destroy(cpl_plugin *) ;
static int hawki_tec_filtchk(cpl_parameterlist *, cpl_frameset *) ;

static int hawki_tec_filtchk_frameset_stats
(cpl_table       **  target_stats,
 cpl_propertylist ** stats_stats,
 cpl_frameset     *  target_frames);

static int hawki_tec_filtchk_save
(cpl_table         ** target_stats,
 cpl_parameterlist *  recipe_parlist,
 cpl_frameset      *  recipe_frameset,
 cpl_propertylist  ** stats_stats,
 const char        *  calpro,
 const char        *  protype);

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

static char hawki_tec_filtchk_description[] =
"hawki_tec_filtchk -- Check pairs of flats taken with different filters.\n"
"The files listed in the Set Of Frames (sof-file) must be tagged:\n"
"raw-file.fits "HAWKI_TEC_FLAT_RAW"\n";

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

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

  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,
                    HAWKI_BINARY_VERSION,
                    CPL_PLUGIN_TYPE_RECIPE,
                    "hawki_tec_filtchk",
                    "Filter checking recipe",
                    hawki_tec_filtchk_description,
                    "Cesar Enrique Garcia Dabo",
                    PACKAGE_BUGREPORT,  
                    hawki_get_license(),
                    hawki_tec_filtchk_create,
                    hawki_tec_filtchk_exec,
                    hawki_tec_filtchk_destroy) ;

    cpl_pluginlist_append(list, plugin) ;
    
    return 0;
}

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

  Create the recipe instance and make it available to the application using the 
  interface. 
 */
/*----------------------------------------------------------------------------*/
static int hawki_tec_filtchk_create(cpl_plugin * plugin)
{
    cpl_recipe      * recipe ;
    /* cpl_parameter   * p ; */

    /* Get the recipe out of the plugin */
    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() ;
    if (recipe->parameters == NULL)
        return 1;

    /* Fill the parameters list */
    /* None.. */

    /* Return */
    return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Execute the plugin instance given by the interface
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int hawki_tec_filtchk_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 ;

    /* Issue a banner */
    hawki_print_banner();

    return hawki_tec_filtchk(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 hawki_tec_filtchk_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    Get the command line options and execute the data reduction
  @param    parlist     the parameters list
  @param    framelist   the frames list
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int hawki_tec_filtchk(
        cpl_parameterlist   *   parlist, 
        cpl_frameset        *   framelist)
{
    cpl_frameset     *  frames ;
    cpl_table        ** target_stats;
    cpl_propertylist ** stats_stats;  
    int                 idet;
    char                calpro[1024];
    char                protype[1024];

    /* Identify the RAW and CALIB frames in the input frameset */
    if (hawki_dfs_set_groups(framelist)) 
    {
        cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
        return -1;
    }

    /* Retrieve raw frames */
    cpl_msg_info(__func__, "Identifying input frames");
    frames = hawki_extract_frameset(framelist, HAWKI_TEC_FLAT_RAW) ;
    snprintf(calpro, 1024, HAWKI_CALPRO_FILTERPOSCHECK_STATS);
    snprintf(protype, 1024, HAWKI_PROTYPE_FILTERPOSCHECK_STATS);
    if (frames == NULL)
    {
        cpl_msg_error(__func__,"Input files should be tagged %s",
                      HAWKI_TEC_FLAT_RAW);
        return -1;
    }
    
    /* Create the statistics table */
    target_stats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *));
    stats_stats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist *));
    for( idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
    {
        target_stats[idet] = cpl_table_new(cpl_frameset_get_size(frames));
        stats_stats[idet] = cpl_propertylist_new();
    }
    hawki_image_stats_initialize(target_stats);

    /* Compute actually the statistics */
    hawki_tec_filtchk_frameset_stats(target_stats, stats_stats, frames);
    
    /* Saving the table product */
    hawki_tec_filtchk_save
        (target_stats, parlist, framelist, stats_stats, calpro, protype);

    /* Free and return */
    cpl_frameset_delete(frames);
    for( idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
    {
        cpl_table_delete(target_stats[idet]);
        cpl_propertylist_delete(stats_stats[idet]);
    }
    cpl_free(target_stats); 
    cpl_free(stats_stats); 

    /* Return */
    if (cpl_error_get_code())
    {
        cpl_msg_error(__func__,
                      "HAWK-I pipeline could not recover from previous errors");
        return -1 ;
    }
    else return 0 ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    The recipe data reduction part is implemented here 
  @param    obj         the objects frames
  @param    obj         the sky frames
  @param    flat        the flat field or NULL
  @param    bpm         the bad pixels map or NULL
  @param    skybg       the computed sky background values
  @return   the combined images of the chips or NULL in error case
 */
/*----------------------------------------------------------------------------*/
static int hawki_tec_filtchk_frameset_stats
(cpl_table       **  target_stats,
 cpl_propertylist ** stats_stats,
 cpl_frameset     *  target_frames)
{
    int iframe;
    int nframes;

    /* Loop on the number of frames */
    nframes = cpl_frameset_get_size(target_frames);
    cpl_msg_info(__func__, "Looping the target frames: %d frames", nframes);
    cpl_msg_indent_more();
    for( iframe = 0 ; iframe < nframes ; ++iframe)
    {
        /* Local storage variables */
        cpl_frame     * this_target_frame;

        /* Computing statistics for this frame */
        cpl_msg_info(__func__, "Computing stats for frame: %d", iframe +1);
        this_target_frame = cpl_frameset_get_position(target_frames, iframe);
        hawki_image_stats_fill_from_frame
            (target_stats, this_target_frame, iframe);
    }
    cpl_msg_indent_less();
    
    /* Compute stats of the stats */
    hawki_image_stats_stats(target_stats, stats_stats);

    /* Print info about the statistics */
    hawki_image_stats_print(target_stats);
    
    return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Save the jitter recipe products on disk
  @param    combined    the combined imagelist produced
  @param    objs_stats  the tables with the detected objects statistics or NULL
  @param    mean_sky_bg the vectors with the sky background values or NULL
  @param    parlist     the input list of parameters
  @param    set         the input frame set
  @return   0 if everything is ok, -1 otherwise
 */
/*----------------------------------------------------------------------------*/
static int hawki_tec_filtchk_save
(cpl_table         ** target_stats,
 cpl_parameterlist *  recipe_parlist,
 cpl_frameset      *  recipe_frameset,
 cpl_propertylist  ** stats_stats,
 const char        *  calpro,
 const char        *  protype)
{
    const cpl_frame  *  reference_frame;
    cpl_propertylist *  referencelist;
    cpl_propertylist ** extlists;
    int                 idet;
    int                 ext_nb;
    const char       *  recipe_name = "hawki_tec_filtchk";
    
    /* Get the reference frame (the first one) */
    reference_frame = cpl_frameset_get_position_const(recipe_frameset, 0);
    
    /* Create the prop lists */
    cpl_msg_info(__func__, "Creating the keywords list") ;
    referencelist = cpl_propertylist_load_regexp
        (cpl_frame_get_filename(reference_frame), 0,HAWKI_HEADER_EXT_FORWARD,0);
    extlists = 
        cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*));
    for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
    {
        /* Get the extension number */
        ext_nb=hawki_get_ext_from_detector
            (cpl_frame_get_filename(reference_frame), idet+1);

        /* Propagate the keywords from input frame extensions */
        extlists[idet] = cpl_propertylist_load_regexp(
                cpl_frame_get_filename(reference_frame), ext_nb,
                HAWKI_HEADER_EXT_FORWARD, 0);
        
        /* Add the stats of the stats */
        cpl_propertylist_append(extlists[idet],stats_stats[idet]);
    }
    
    /* Write the table with the statistics */
    hawki_tables_save(recipe_frameset,
                      recipe_parlist,
                      recipe_frameset,
                      (const cpl_table **)target_stats,
                      recipe_name,
                      calpro,
                      protype,
                      (const cpl_propertylist*)referencelist, 
                      (const cpl_propertylist**)extlists, 
                      "hawki_tec_filtchk_stats.fits");
    
    /* Free and return */
    cpl_propertylist_delete(referencelist) ;
    for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) 
    {
        cpl_propertylist_delete(extlists[idet]) ;
    }
    cpl_free(extlists) ;
    return  0;
}
