/* $Id: visir_img_combine.c,v 1.107 2010-10-21 11:51:32 llundin Exp $
 *
 * This file is part of the VISIR 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: 2010-10-21 11:51:32 $
 * $Revision: 1.107 $
 * $Name: not supported by cvs2svn $
 */

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

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

#include "visir_recipe.h"

/*-----------------------------------------------------------------------------
                                Defines
 -----------------------------------------------------------------------------*/

#define RECIPE_STRING   "visir_old_img_combine"

/* FITS keys to be loaded for all raw files */
#define RECIPE_KEYS_REGEXP_ALL \
        VISIR_PFITS_REGEXP_IMG_RECOMBINE

/* FITS keys to be loaded for first raw file */
#define RECIPE_KEYS_REGEXP               \
        RECIPE_KEYS_REGEXP_ALL           \
    "|" VISIR_PFITS_REGEXP_COMBINE_PAF   \
    "|" VISIR_PFITS_INT_NDIT             \
    "|" VISIR_PFITS_INT_CHOP_NCYCLES     \
    "|" VISIR_PFITS_STRING_FILTER1       \
    "|" VISIR_PFITS_STRING_FILTER2

/* FITS keys to be loaded for first raw file, in case WCS is used */
#define RECIPE_KEYS_REGEXP_WCS \
        RECIPE_KEYS_REGEXP \
    "|" IRPLIB_PFITS_WCS_REGEXP

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

static cpl_error_code visir_img_combine_qc(cpl_propertylist *,
                                           cpl_boolean,
                                           const irplib_framelist *,
                                           const cpl_image *);

static cpl_error_code visir_img_combine_save(cpl_frameset *,
                                             const cpl_parameterlist *,
                                             const cpl_propertylist *,
                                             const cpl_image *,
                                             const cpl_image *,
                                             const cpl_image *,
                                             const cpl_image *,
                                             const char      *,
                                             const char      *);

VISIR_RECIPE_DEFINE(visir_old_img_combine,
                    VISIR_PARAM_REFINE | VISIR_PARAM_XCORR |    
                    VISIR_PARAM_OFFSETS | VISIR_PARAM_OBJECTS | 
                    VISIR_PARAM_NODPOS |  VISIR_PARAM_AUTOBPM | 
                    VISIR_PARAM_GLITCH | VISIR_PARAM_PURGE |    
                    VISIR_PARAM_UNION  | VISIR_PARAM_REJECT |   
                    VISIR_PARAM_COMBINE | VISIR_PARAM_ECCMAX |
                    VISIR_PARAM_STRIPITE | VISIR_PARAM_STRIPMOR |
                    VISIR_PARAM_PLOT,
                    "Old DRS detector: Images combination recipe",
                    "This recipe recombines the data observed in "
                    "chopping/nodding or\n"
                    "chopping or nodding modes into one combined image using "
                    "optionally\n"
                    "cross-correlation methods.\n"
                    "The files listed in the Set Of Frames (sof-file) "
                    "must be tagged:\n"
                    "VISIR-observation-file.fits " VISIR_IMG_COMBINE_CNJ " or\n"
                    "VISIR-observation-file.fits " VISIR_IMG_COMBINE_CJ " or\n"
                    "VISIR-observation-file.fits " VISIR_IMG_COMBINE_NJ " or\n"
                    "VISIR-observation-file.fits " VISIR_IMG_COMBINE_DJ "\n"
                    "\n"
                    "The corresponding primary product will have a FITS card\n"
                    "'HIERARCH ESO PRO CATG' with a value of\n"
                    VISIR_IMG_COMBINE_COMBINED_PROCATG_CNJ " or\n"
                    VISIR_IMG_COMBINE_COMBINED_PROCATG_CJ " or\n"
                    VISIR_IMG_COMBINE_COMBINED_PROCATG_NJ " or\n"
                    VISIR_IMG_COMBINE_COMBINED_PROCATG_DJ
                    " and the corresponding beam-collapsed product will "
                    "have a FITS card\n"
                    "'HIERARCH ESO PRO CATG' with a value of\n"
                    VISIR_IMG_COMBINE_ONEBEAM_PROCATG_CNJ " or\n"
                    VISIR_IMG_COMBINE_ONEBEAM_PROCATG_CJ " or\n"
                    VISIR_IMG_COMBINE_ONEBEAM_PROCATG_NJ " or\n"
                    VISIR_IMG_COMBINE_ONEBEAM_PROCATG_DJ
                    "\n"
                    MAN_VISIR_CALIB_BPM_IMG);

/*----------------------------------------------------------------------------*/
/**
 * @defgroup visir_img_combine   Images combination
 */
/*----------------------------------------------------------------------------*/

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

/*----------------------------------------------------------------------------*/
/**
  @brief    The recipe data reduction part is implemented here 
  @param    parlist     the parameters list
  @param    framelist   the frames list
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static int visir_old_img_combine(cpl_frameset            * framelist,
                             const cpl_parameterlist * parlist)
{
    cpl_errorstate  cleanstate = cpl_errorstate_get();
    irplib_framelist * allframes = NULL;
    irplib_framelist * rawframes = NULL;
    cpl_propertylist * qclist    = cpl_propertylist_new();
    const char       * badpix;
    const char       * flat;
    cpl_image       ** combined        = NULL;
    cpl_image       ** beam1           = NULL;
    const char       * procatg_combine = NULL;
    const char       * procatg_onebeam = NULL;
    cpl_boolean        drop_wcs;
    const char       * keys_regexp = "^(" RECIPE_KEYS_REGEXP_WCS ")$";

    const char * combine_string;
    cpl_geom_combine combine_mode;

    /* Retrieve input parameters */
    combine_string = visir_parameterlist_get_string(parlist, RECIPE_STRING,
                                                    VISIR_PARAM_COMBINE);

    bug_if (combine_string == NULL);

    if (combine_string[0] == 'u')
        combine_mode = CPL_GEOM_UNION;
    else if (combine_string[0] == 'f')
        combine_mode = CPL_GEOM_FIRST;
    else if (combine_string[0] == 'i')
        combine_mode = CPL_GEOM_INTERSECT;
    else
        skip_if(1);

    /* Identify the RAW and CALIB frames in the input frameset */
    skip_if (visir_dfs_set_groups(framelist));

    /* Objects observation */
    allframes = irplib_framelist_cast(framelist);
    skip_if(allframes == NULL);
    rawframes = irplib_framelist_extract_regexp(allframes, "^("
                                                VISIR_IMG_COMBINE_CNJ "|"
                                                VISIR_IMG_COMBINE_CJ  "|"
                                                VISIR_IMG_COMBINE_NJ  "|"
                                                VISIR_IMG_COMBINE_DJ ")$",
                                                CPL_FALSE);
    skip_if (rawframes == NULL);
    irplib_framelist_empty(allframes);

    skip_if( irplib_framelist_load_propertylist(rawframes, 0, 0, keys_regexp,
                                                CPL_FALSE));

    skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
                                                   RECIPE_KEYS_REGEXP_ALL
                                                   ")$", CPL_FALSE));

    skip_if(visir_dfs_check_framelist_tag(rawframes));
    
    /* Set PRO.CATG - and verify uniqueness of frame type */
    if (cpl_frameset_find(framelist, VISIR_IMG_COMBINE_DJ)) {
        procatg_combine = VISIR_IMG_COMBINE_COMBINED_PROCATG_DJ;
        procatg_onebeam = VISIR_IMG_COMBINE_ONEBEAM_PROCATG_DJ;
    }
    if (cpl_frameset_find(framelist, VISIR_IMG_COMBINE_NJ)) {
        skip_if (procatg_combine != NULL);
        procatg_combine = VISIR_IMG_COMBINE_COMBINED_PROCATG_NJ;
        procatg_onebeam = VISIR_IMG_COMBINE_ONEBEAM_PROCATG_NJ;
    }
    if (cpl_frameset_find(framelist, VISIR_IMG_COMBINE_CJ)) {
        skip_if (procatg_combine != NULL);
        procatg_combine = VISIR_IMG_COMBINE_COMBINED_PROCATG_CJ;
        procatg_onebeam = VISIR_IMG_COMBINE_ONEBEAM_PROCATG_CJ;
    }
    if (cpl_frameset_find(framelist, VISIR_IMG_COMBINE_CNJ)) {
        skip_if (procatg_combine != NULL);
        procatg_combine = VISIR_IMG_COMBINE_COMBINED_PROCATG_CNJ;
        procatg_onebeam = VISIR_IMG_COMBINE_ONEBEAM_PROCATG_CNJ;
    }
    bug_if (procatg_combine == NULL);

    /* Bad pixels calibration file */
    badpix = irplib_frameset_find_file(framelist, VISIR_CALIB_BPM);

    /* Flatfield calibration file */
    flat = irplib_frameset_find_file(framelist, VISIR_CALIB_FLAT);

    /* Combine the frames */
    combined = visir_img_recombine(RECIPE_STRING, parlist, rawframes, badpix,
                                   flat, combine_mode, &drop_wcs,
                                   CPL_FALSE, 0.0, 0);

    if (combined == NULL) {
        cpl_msg_error(cpl_func, "Could not combine the input frames");
        skip_if(1);
    }

    beam1 = visir_img_collapse_beam(qclist, combined[0], parlist, RECIPE_STRING,
                                    VISIR_CHOPNOD_AUTO,
                                    irplib_framelist_get_propertylist_const
                                    (rawframes, 0));

    if (beam1 == NULL) {
        irplib_error_recover(cleanstate, "Could not collapse the beams of "
                             "the combined image");
    }

    /* Add QC parameters */
    skip_if(visir_img_combine_qc(qclist, drop_wcs, rawframes, combined[0]));

    /* Reduce maximum number of pointers used */
    irplib_framelist_empty(rawframes);

    /* Save the combined image and contribution map */
    cpl_msg_info(cpl_func, "Save the combined image and contribution map");

    if (beam1 == NULL) {
        skip_if(visir_img_combine_save(framelist, parlist, qclist,
                                       combined[0], combined[1], NULL,
                                       NULL, procatg_combine, procatg_onebeam));
    } else {
        skip_if(visir_img_combine_save(framelist, parlist, qclist,
                                       combined[0], combined[1], beam1[0],
                                       beam1[1], procatg_combine,
                                       procatg_onebeam));
    }

    end_skip;

    if (combined) {
        cpl_image_delete(combined[0]);
        cpl_image_delete(combined[1]);
        cpl_free(combined);
    }

    if (beam1) {
        cpl_image_delete(beam1[0]);
        cpl_image_delete(beam1[1]);
        cpl_free(beam1);
    }

    irplib_framelist_delete(allframes);
    irplib_framelist_delete(rawframes);
    cpl_propertylist_delete(qclist);

    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Append the QC parameters to the propertylist
  @param    qclist      List of QC parameters
  @param    drop_wcs    True iff WCS is to be dropped
  @param    rawframes   List of rawframes and their propertylists
  @param    combined    The combined image
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code visir_img_combine_qc(cpl_propertylist       * qclist,
                                           cpl_boolean              drop_wcs,
                                           const irplib_framelist * rawframes,
                                           const cpl_image        * combined)
{

    const cpl_propertylist * reflist
        = irplib_framelist_get_propertylist_const(rawframes, 0);
    double bg_sigma;


    bug_if (0);

    /* QC.EXPTIME */
    skip_if (visir_qc_append_exptime(qclist, rawframes));

    /* Copy the filter name */
    skip_if (visir_qc_append_filter(qclist, rawframes));


    /* QC.BACKGD.MEAN */
    /* Compute the background values of the HCYCLE frames */
    skip_if(visir_qc_append_background(qclist, rawframes, 0, 0));

    /* Compute the background sigma */
    bg_sigma = visir_img_phot_sigma_clip(combined);

    skip_if (0);

    /* QC.BACKGD.SIGMA */
    bug_if (cpl_propertylist_append_double(qclist, "ESO QC BACKGD SIGMA",
                                           bg_sigma));

    /* QC.CAPA */
    skip_if (visir_qc_append_capa(qclist, rawframes));

    if (drop_wcs) {
        cpl_propertylist * pcopy = cpl_propertylist_new();
        const cpl_error_code error
            = cpl_propertylist_copy_property_regexp(pcopy, reflist, "^("
                                                    IRPLIB_PFITS_WCS_REGEXP
                                                    ")$", 0);
        if (!error && cpl_propertylist_get_size(pcopy) > 0) {
            cpl_msg_warning(cpl_func, "Combined image will have no WCS "
                            "coordinates");
        }
        cpl_propertylist_delete(pcopy);
        bug_if(0);
    } else {
        bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
                                                     IRPLIB_PFITS_WCS_REGEXP
                                                     ")$", 0));
    }

    end_skip;

    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Save the visir_img_combine recipe products on disk
  @param    self        The set of input frames to append product frames to
  @param    parlist     The input list of parameters
  @param    qclist      List of QC parameters
  @param    combined    The combined image
  @param    contrib     The contribution map of the combined image
  @param    beam1       The beam-collapsed combined image
  @param    beam1i      The contribution map of the beam-collapsed image
  @param    procat_c    The procatg of the combined image
  @param    procat_b    The procatg of the beam combined image
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static
cpl_error_code visir_img_combine_save(cpl_frameset            * self,
                                      const cpl_parameterlist * parlist,
                                      const cpl_propertylist  * qclist,
                                      const cpl_image         * combined,
                                      const cpl_image         * contrib,
                                      const cpl_image         * beam1,
                                      const cpl_image         * beam1i,
                                      const char              * procat_c,
                                      const char              * procat_b)
{
    cpl_propertylist * xtlist = cpl_propertylist_new();


    bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
                                          "Contribution Map"));

    /* THE COMBINED IMAGE */
    skip_if (irplib_dfs_save_image(self, parlist, self, combined,
                                   CPL_BPP_IEEE_FLOAT, RECIPE_STRING, procat_c,
                                   qclist, NULL, visir_pipe_id,
                                   RECIPE_STRING CPL_DFS_FITS));

    /* THE CONTRIBUTION MAP */
    skip_if (cpl_image_save(contrib, RECIPE_STRING CPL_DFS_FITS,
                            CPL_BPP_16_UNSIGNED, xtlist, CPL_IO_EXTEND));

    if (beam1 != NULL) {
        /* THE BEAM COLLAPSED IMAGE */
        skip_if (irplib_dfs_save_image(self, parlist, self, beam1,
                                       CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
                                       procat_b, qclist, NULL, visir_pipe_id,
                                       RECIPE_STRING "_onebeam" CPL_DFS_FITS));

        /* THE BEAM COLLAPSED CONTRIBUTION MAP */
        skip_if (cpl_image_save(beam1i, RECIPE_STRING "_onebeam" CPL_DFS_FITS,
                                CPL_BPP_8_UNSIGNED, xtlist, CPL_IO_EXTEND));
    }

    end_skip;

    cpl_propertylist_delete(xtlist);

    return cpl_error_get_code();

}
