/* $Id: sinfo_rec_mdark.c,v 1.22 2008-02-28 10:36:10 amodigli Exp $
 *
 * This file is part of the SINFONI 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: amodigli $
 * $Date: 2008-02-28 10:36:10 $
 * $Revision: 1.22 $
 * $Name: not supported by cvs2svn $
 */

/****************************************************************
 *          Dark Frames Data Reduction                          *
 ****************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>          /* allows the program compilation */
#endif

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

/* std */
#include <strings.h>
#include <string.h>
#include <stdio.h>

/* cpl */
#include <cpl.h>    

/* irplib */
#include <irplib_utils.h>

/* sinfoni */
#include <sinfo_bp_noise.h> /* */
#include <sinfo_new_dark.h>     /*  */ 
#include <sinfo_utilities.h>
#include <sinfo_general_config.h>
#include <sinfo_bp_config.h>
#include <sinfo_bp_noise_config.h>
#include <sinfo_dark_config.h> 
#include <sinfo_tpl_utils.h>
#include <sinfo_tpl_dfs.h>
#include <sinfo_pfits.h>
#include <sinfo_functions.h>
#include <sinfo_pfits.h>
#include <sinfo_msg.h>
#include <sinfo_error.h>
#include <sinfo_utils_wrappers.h>
/*-----------------------------------------------------------------------------
                            Functions prototypes
 ----------------------------------------------------------------------------*/

static int sinfo_rec_mdark_create(cpl_plugin *plugin);
static int sinfo_rec_mdark_exec(cpl_plugin *plugin);
static int sinfo_rec_mdark_destroy(cpl_plugin *plugin);
static int sinfo_rec_mdark(cpl_parameterlist *config, cpl_frameset *set);
static int count_diff_ndit(cpl_frameset *set, cpl_vector** dit_val);

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

static char sinfo_rec_mdark_description[] =
                "This recipe perform raw sinfo_dark data reduction.\n"
                "The input files are raw sinfo_dark images\n"
                "Their associated tags should be DARK.\n"
                "The output are a master sinfo_dark (PRO.CATG=MASTER_DARK) and\n"
                "a hot pixels bad pixel map (PRO.CATG=BP_MAP_HP)\n"
                "\n";


/*-----------------------------------------------------------------------------
                                Functions code
 ----------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
 * @defgroup sinfo_rec_mdark   Recipe to compute master dark
 */
/*---------------------------------------------------------------------------*/
/**@{*/
/*---------------------------------------------------------------------------*/
/**
  @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,
                    SINFONI_BINARY_VERSION,
                    CPL_PLUGIN_TYPE_RECIPE,
                    "sinfo_rec_mdark",
                    "Master dark and hot pixels mask generation.",
                    sinfo_rec_mdark_description,
                    "Andrea Modigliani",
                    "Andrea.Modigliani@eso.org",
                    sinfo_get_license(),
                    sinfo_rec_mdark_create,
                    sinfo_rec_mdark_exec,
                    sinfo_rec_mdark_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 sinfo_rec_mdark_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 ;
    cpl_error_reset();
    irplib_reset();

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


    /*
     * Fill the parameter list.
     */
    sinfo_general_config_add(recipe->parameters);
    sinfo_bp_noise_config_add(recipe->parameters);
    sinfo_dark_config_add(recipe->parameters);
    return 0;

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

    cpl_errorstate initial_errorstate = cpl_errorstate_get();

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

    if (!cpl_errorstate_is_equal(initial_errorstate)) {                      
        /* Dump the error history since recipe execution start.                
           At this point the recipe cannot recover from the error */           
        cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);              
    } 

    return sinfo_rec_mdark(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 sinfo_rec_mdark_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
 */
/*---------------------------------------------------------------------------*/
/*
 * The actual recipe actually start here.
 */

static int
sinfo_rec_mdark(cpl_parameterlist *config, cpl_frameset *set)
{

    cpl_parameter* p=NULL;
    int nset=0;
    cpl_frameset  * wrk_set=NULL;
    cpl_frameset  * cdb_set=NULL;
    cpl_frameset  * tot_set=NULL;

    cpl_frame* tmp_frm=NULL;
    cpl_frame* dup_frm=NULL;
    cpl_frame* cdb_frm=NULL;

    char tmp_name[FILE_NAME_SZ];
    char out_bpmap_name[FILE_NAME_SZ];
    char out_dark_name[FILE_NAME_SZ];
    double tmp_dit=0;
    double ref_dit=0;

    cpl_vector* dit_val=NULL;
    cpl_propertylist* plist=NULL;

    int i=0;
    int j=0;
    int line_cor=0;


    int nraw=0;
    int ncdb=0;
    int nred=0;
    int ntot=0;
    sinfo_msg("Welcome to SINFONI Pipeline release %d.%d.%d",
              SINFONI_MAJOR_VERSION,SINFONI_MINOR_VERSION,SINFONI_MICRO_VERSION);
    ck0(sinfo_dfs_set_groups(set),"Cannot indentify RAW and CALIB frames");

    check_nomsg(p=cpl_parameterlist_find(config, "sinfoni.general.lc_sw"));
    check_nomsg(line_cor=cpl_parameter_get_bool(p));
    if(line_cor==1) {
        check_nomsg(sinfo_ima_line_cor(config,set));
    }


    check_nomsg(cdb_set=cpl_frameset_new());
    check_nomsg(tot_set=cpl_frameset_new());


    sinfo_extract_mst_frames(set,cdb_set);
    sinfo_bp_config_add(config);
    nset=count_diff_ndit(set,&dit_val);

    check_nomsg(nraw=cpl_frameset_get_size(set));
    check_nomsg(ncdb=cpl_frameset_get_size(cdb_set));

    for(i=0;i<nset;i++) {
        check_nomsg(wrk_set=cpl_frameset_new());
        check_nomsg(ref_dit=cpl_vector_get(dit_val,i));


        for(j=0;j<nraw;j++) {
            check_nomsg(tmp_frm=cpl_frameset_get_frame(set,j));
            check_nomsg(strcpy(tmp_name,cpl_frame_get_filename(tmp_frm)));
            plist=cpl_propertylist_load(tmp_name,0);
            tmp_dit=sinfo_pfits_get_dit(plist);
            sinfo_free_propertylist(&plist);

            if(tmp_dit==ref_dit) {
                check_nomsg(cpl_frameset_insert(wrk_set,cpl_frame_duplicate(tmp_frm)));
            }
        }

        for(j=0;j<ncdb;j++) {
            check_nomsg(cdb_frm=cpl_frameset_get_frame(cdb_set,j));
            check_nomsg(cpl_frameset_insert(wrk_set,cpl_frame_duplicate(cdb_frm)));
        }

        /* reduce data */
        ck0(sinfo_dfs_set_groups(wrk_set),"Cannot indentify RAW and CALIB frames");

        /* Hidden parameters */
        check_nomsg(p = cpl_parameterlist_find(config,"sinfoni.bp.method"));
        check_nomsg(cpl_parameter_set_string(p,"Noise"));
        ck0(sinfo_dfs_set_groups(set),"Cannot indentify RAW and CALIB frames") ;

        if (nset>1) {
            sprintf(out_bpmap_name,"%s%d%s","out_bp_noise",i,".fits");
        } else {
            strcpy(out_bpmap_name,"out_bp_noise.fits");
        }

        sinfo_msg("-----------------------------------------------");
        sinfo_msg("BP_MAP_HP BAD PIXEL MAP DETERMINATION          ");
        sinfo_msg("-----------------------------------------------");

        ck0(sinfo_new_bp_search_noise(cpl_func,config,wrk_set,out_bpmap_name),
            "computing BP_MAP_HP") ;
        sinfo_msg("BP_MAP_HP BAD PIXEL MAP DETERMINATION SUCCESS") ;

        sinfo_msg("-----------------------------------------------");
        sinfo_msg("MASTER DARK DETERMINATION                      ");
        sinfo_msg("-----------------------------------------------");

        if (nset>1) {
            sprintf(out_dark_name,"%s%d%s","out_dark",i,".fits");
        } else {
            strcpy(out_dark_name,"out_dark.fits");
        }

        ck0(sinfo_new_dark(cpl_func,config, wrk_set, out_dark_name),
            "Computing master dark") ;
        sinfo_msg("MASTER DARK DETERMINATION SUCCESS") ;

        nred=cpl_frameset_get_size(wrk_set);
        for(j=0;j<nred;j++) {
            check_nomsg(tmp_frm=cpl_frameset_get_frame(wrk_set,j));
            check_nomsg(cpl_frameset_insert(tot_set,cpl_frame_duplicate(tmp_frm)));
        }
        sinfo_free_frameset(&wrk_set);

    }

    check_nomsg(ntot=cpl_frameset_get_size(tot_set));
    for(j=0;j<ntot;j++) {
        check_nomsg(tmp_frm=cpl_frameset_get_frame(tot_set,j));
        check_nomsg(cpl_frameset_insert(set,cpl_frame_duplicate(tmp_frm)));
    }

    sinfo_free_frameset(&tot_set);
    sinfo_free_my_vector(&dit_val);
    sinfo_free_frameset(&cdb_set);






    cleanup:

    sinfo_free_propertylist(&plist);
    sinfo_free_frame(&dup_frm);
    sinfo_free_frameset(&wrk_set);
    sinfo_free_frameset(&tot_set);
    sinfo_free_my_vector(&dit_val);
    sinfo_free_frameset(&cdb_set);


    if (cpl_error_get_code() != CPL_ERROR_NONE) {
        return -1;
    } else {
        return 0;
    }



}

static int count_diff_ndit(cpl_frameset *set, cpl_vector** dit_val)
{




    char  tmp_name[FILE_NAME_SZ];
    int nraw=0;
    int i=0;
    int ndit=1;
    double ref_dit=0;
    cpl_vector* dit=NULL;
    cpl_propertylist* plist=NULL;

    nraw=cpl_frameset_get_size(set);
    dit=cpl_vector_new(nraw);
    for(i=0;i<nraw;i++) {
        cpl_frame* tmp_frm = cpl_frameset_get_frame(set, i);
        strcpy(tmp_name,cpl_frame_get_filename(tmp_frm));
        plist= cpl_propertylist_load(tmp_name,0);
        cpl_vector_set(dit,i,sinfo_pfits_get_dit(plist));
        sinfo_free_propertylist(&plist);
    }


    cpl_vector_sort(dit,1);
    ref_dit=cpl_vector_get(dit,0);


    for(i=1;i<nraw;i++) {
        if(ref_dit != cpl_vector_get(dit,i)) {
            ref_dit=cpl_vector_get(dit,i);
            ndit++;
        }
    }
    *dit_val=cpl_vector_new(ndit);
    ref_dit=cpl_vector_get(dit,0);
    cpl_vector_set(*dit_val,0,cpl_vector_get(dit,0));
    ndit=1;

    for(i=1;i<nraw;i++) {
        if(ref_dit != cpl_vector_get(dit,i)) {
            cpl_vector_set(*dit_val,ndit,cpl_vector_get(dit,i));
            ref_dit=cpl_vector_get(dit,i);
            ndit++;
        }
    }

    cpl_vector_delete(dit);


    return ndit;
}

/**@}*/
