/* $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: sinfo-2_4_0 $
 */

 /****************************************************************
  *          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"
"Information on relevant parameters may be found with\n"
"esorex --params sinfo_rec_mdark\n"
"esorex --help sinfo_rec_mdark\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)
{
  cpl_frame* tmp_frm=NULL;
  cpl_frame* dup_frm=NULL;


  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++) {
     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);
  cpl_frame_delete(dup_frm);

  return ndit;
}

/**@}*/
