/* $Id: hawki_step_stitch.c,v 1.9 2013-03-25 11:36:35 cgarcia Exp $
 *
 * 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
 */

/*
 * $Author: cgarcia $
 * $Date: 2013-03-25 11:36:35 $
 * $Revision: 1.9 $
 * $Name: not supported by cvs2svn $
 */

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

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

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

#include "irplib_utils.h"

#include "hawki_utils.h"
#include "hawki_pfits.h"
#include "hawki_dfs.h"
#include "hawki_load.h"

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

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

static int hawki_step_stitch_create(cpl_plugin *) ;
static int hawki_step_stitch_exec(cpl_plugin *) ;
static int hawki_step_stitch_destroy(cpl_plugin *) ;
static int hawki_step_stitch(cpl_parameterlist *, cpl_frameset *) ;
static int hawki_step_stitch_save
(cpl_image           *   in,
 cpl_frame           *   combined,
 cpl_parameterlist   *   parlist,
 cpl_frameset        *   set);

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

static char hawki_step_stitch_description[] =
"hawki_step_stitch -- Stitching utility\n"
"This recipe accepts 1 parameter:\n"
"First parameter:   the HAWKI image to stitch "
"                   (PRO CATG = "HAWKI_CALPRO_COMBINED")\n"
"\n"
"This recipe produces 1 file:\n"
"First product:     the stitch image.\n"
"                   (PRO CATG = "HAWKI_CALPRO_STITCHED")\n" ;

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

/*----------------------------------------------------------------------------*/
/**
  @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,
                    HAWKI_BINARY_VERSION,
                    CPL_PLUGIN_TYPE_RECIPE,
                    "hawki_step_stitch",
                    "Stitching utility",
                    hawki_step_stitch_description,
                    "Cesar Enrique Garcia",
                    PACKAGE_BUGREPORT,  
                    hawki_get_license(),
                    hawki_step_stitch_create,
                    hawki_step_stitch_exec,
                    hawki_step_stitch_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 hawki_step_stitch_create(cpl_plugin * plugin)
{
    cpl_recipe      *   recipe ;
        
    /* 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() ; 
    if (recipe->parameters == NULL)
        return 1;

    /* 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_step_stitch_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_step_stitch(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_step_stitch_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
 */
/*----------------------------------------------------------------------------*/
static int hawki_step_stitch(
        cpl_parameterlist   *   parlist,
        cpl_frameset        *   frameset)
{
    const char          *   comb_filename ;
    cpl_frameset        *   combframes;
    cpl_frame           *   combframe;
    cpl_propertylist    *   plist ;
    cpl_image           *   stitched ;
    cpl_image           *   in[HAWKI_NB_DETECTORS] ;
    double                  posx[HAWKI_NB_DETECTORS] ;
    double                  posy[HAWKI_NB_DETECTORS] ;
    int                     i, j ;
    cpl_errorstate          error_prevstate;


    /* Retrieve input parameters */
 
    /* Identify the RAW and CALIB frames in the input frameset */
    if (hawki_dfs_set_groups(frameset)) {
        cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
        return -1 ;
    }
    
    /* Identifying the combined frame */
    cpl_msg_info(__func__, "Identifying the combined frame");
    combframes = hawki_extract_frameset
        (frameset, HAWKI_CALPRO_COMBINED);
    if (combframes == NULL)
    {
        cpl_msg_error(__func__, "No combined images found (%s)",
                HAWKI_CALPRO_COMBINED);
        cpl_frameset_delete(combframes);
        return -1 ;
    }

    /* Check that we have 1 files in input */
    if (cpl_frameset_get_size(combframes) != 1) {
        cpl_msg_error(__func__, "Expects one single combined images") ;
        cpl_frameset_delete(combframes);
        return -1 ;
    }

    /* Load the HAWKI images */
    cpl_msg_info(__func__,"Loading combined frame");
    for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
        if ((in[i] = hawki_load_image(combframes, 0, i+1, 
                        CPL_TYPE_FLOAT)) == NULL) {
            cpl_msg_error(__func__, "Cannot load chip nb %d", i+1) ;
            for (j=0 ; j<i ; i++) cpl_image_delete(in[j]) ;
            cpl_frameset_delete(combframes);
            return -1 ;
        }
    }

    /* Get the first input frame */
    combframe     = cpl_frameset_get_position(combframes, 0);
    comb_filename = cpl_frame_get_filename(combframe);

    /* Get the POSX / POSY informations */
    error_prevstate = cpl_errorstate_get();
    for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
        plist = cpl_propertylist_load_regexp(comb_filename, i+1, "QC", 0) ;
        posx[i] = hawki_pfits_get_comb_posx(plist); 
        posy[i] = hawki_pfits_get_comb_posy(plist);
        cpl_propertylist_delete(plist) ;
        if(!cpl_errorstate_is_equal(error_prevstate))
        {
            cpl_msg_error(__func__, "Cannot get POS infos for chip %d", i+1) ;
            return -1 ;
        }
    }

    /* Compute the stitched image */
    cpl_msg_info(__func__, "Computing the stiched image") ;
    if ((stitched = hawki_images_stitch(in, posx, posy)) == NULL) {
        cpl_msg_error(__func__, "Cannot stitch the images") ;
        for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) cpl_image_delete(in[i]) ;
        return -1 ;
    }
    for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) cpl_image_delete(in[i]) ;

    /* Save the corrected image */
    if (hawki_step_stitch_save(stitched, combframe, parlist, frameset) == -1) 
        cpl_msg_warning(__func__,"Some data could not be saved. "
                                 "Check permisions or disk space");

    /* Free and Return */
    cpl_frameset_delete(combframes);
    cpl_image_delete(stitched);

    /* 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    Save the products on disk
  @param    in          the image to save
  @param    parlist     the input list of parameters
  @param    set         the input frame set
  @return   0 if everything is ok, -1 otherwise
 */
/*----------------------------------------------------------------------------*/
static int hawki_step_stitch_save
(cpl_image           *   in,
 cpl_frame           *   combined,
 cpl_parameterlist   *   parlist,
 cpl_frameset        *   set)
{
    cpl_propertylist    *   plist;
    cpl_propertylist    *   wcslist;
    const char          *   recipe_name = "hawki_step_stitch" ;
    int                     ext_chip_1;
    cpl_errorstate          error_prevstate = cpl_errorstate_get();

    cpl_msg_indent_more();

    /* Create a propertylist for PRO.x */
    plist = cpl_propertylist_new();
    cpl_propertylist_append_string(plist, CPL_DFS_PRO_TYPE,
                                   HAWKI_PROTYPE_STITCHED) ;
    cpl_propertylist_append_string(plist, CPL_DFS_PRO_CATG,
                                   HAWKI_CALPRO_STITCHED) ;

    /* Handle WCS keys */
    ext_chip_1 = 1;
    wcslist = cpl_propertylist_load_regexp(
            cpl_frame_get_filename(combined), ext_chip_1, HAWKI_HEADER_WCS, 0);
    cpl_propertylist_append(plist, wcslist);

    /* Save the image */
    if(cpl_dfs_save_image(set,
                          NULL,
                          parlist,
                          set,
                          NULL,
                          in,
                          CPL_BPP_IEEE_FLOAT,
                          recipe_name,
                          plist,
                          NULL,
                          PACKAGE "/" PACKAGE_VERSION,
                          "hawki_step_stitch.fits") != CPL_ERROR_NONE)
        cpl_msg_error(__func__,"Could not save stitched image");

    cpl_propertylist_delete(plist) ;
    cpl_propertylist_delete(wcslist) ;
    cpl_msg_indent_less();
    if(!cpl_errorstate_is_equal(error_prevstate))
    {
        cpl_errorstate_set(CPL_ERROR_NONE);
        return -1;
    }
    return  0;
}

