/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004,2005 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, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */
/*----------------------------------------------------------------------------
   
   File name    :   sinfo_finddist_ini_by_cpl.c
   Author       :   Andrea Modigliani
   Created on   :   Aug 12, 2004
   Description  :   distortion, slitlet distances, first column CPL input 
                    handling for SINFONI
 ---------------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
/*---------------------------------------------------------------------------
                                Includes
 ---------------------------------------------------------------------------*/
#include <string.h>
#include "sinfo_finddist_ini_by_cpl.h"
#include "sinfo_pro_types.h"
#include "sinfo_hidden.h"
#include "sinfo_raw_types.h"
#include "sinfo_ref_types.h"
/*---------------------------------------------------------------------------
                    Functions private to this module
 ---------------------------------------------------------------------------*/
static void     
parse_section_frames(finddist_config *, cpl_parameterlist* cpl_cfg, 
                     cpl_frameset* sof, cpl_frameset** raw, int* status);
static void     
parse_section_findlines(finddist_config *, cpl_parameterlist* cpl_cfg);
static void     
parse_section_wavecalib(finddist_config *, cpl_parameterlist* cpl_cfg);
static void     
parse_section_wavemap(finddist_config *, cpl_parameterlist* cpl_cfg);
static void     
parse_section_fitslits(finddist_config *, cpl_parameterlist* cpl_cfg);
static void     
parse_section_northsouthtest(finddist_config *, cpl_parameterlist* cpl_cfg);
static void     
parse_section_qclog      (finddist_config * cfg, cpl_parameterlist* cpl_cfg);

/**@{*/
/**
 * @addtogroup sinfo_finddist_cfg functions to determine slitlets distances
 *
 * TBD
 */


/**
  @name     sinfo_parse_cpl_input_finddist
  @memo     Parse CPL input.
  @param    cpl_cfg   pointer to parameter list
  @param    sof pointer to input set of frames
  @param    raw pointer to input set of raw frames
  @return   1 newly allocated wave_config blackboard structure.
  @doc      The requested ini file is parsed and a blackboard object is 
            created, then updated accordingly. Returns NULL in case of error.
 */

finddist_config * 
sinfo_parse_cpl_input_finddist(cpl_parameterlist * cpl_cfg, 
                               cpl_frameset* sof, 
                               cpl_frameset** raw)
{
        finddist_config   *       cfg ;
        int                   status =0;

        cfg = sinfo_finddist_cfg_create();

        parse_section_findlines (cfg, cpl_cfg);
        parse_section_wavecalib (cfg, cpl_cfg);
        parse_section_wavemap   (cfg, cpl_cfg); 
        parse_section_fitslits  (cfg, cpl_cfg); 
        parse_section_northsouthtest (cfg, cpl_cfg);
        parse_section_qclog(cfg,cpl_cfg);
        parse_section_frames   (cfg, cpl_cfg, sof, raw, &status);

        if (status > 0) {
                sinfo_msg_error("parsing cpl input");
                sinfo_finddist_cfg_destroy(cfg);
                cfg = NULL ;
                return NULL ;
        }
        return cfg ;
}


/**
  @name     parse_section_frames
  @memo     Parse input frames
  @param    cfg pointer to finddist_config structure
  @param    cpl_cfg   pointer to parameter list
  @param    sof pointer to input set of frames
  @param    raw pointer to input set of raw frames
  @param    status status of function
  @return   1 newly allocated wave_config blackboard structure.
 */

static void     
parse_section_frames(finddist_config * cfg,
             cpl_parameterlist * cpl_cfg,
             cpl_frameset * sof,
                     cpl_frameset** raw,
                     int* status)
{



   int nframes=0;
   int nraw=0;
   cpl_frame* frame   = NULL;
   cpl_parameter *p; 


   char spat_res[FILE_NAME_SZ];
   char lamp_status[FILE_NAME_SZ];
   char band[FILE_NAME_SZ];
   int ins_set=0;
   cpl_table* drs_tab=NULL;
   wcal* w=NULL;
   int check=0;
   nstpar* nstp=NULL;
   distpar* d=NULL;

   d=sinfo_distpar_new();
   w=sinfo_wcal_new();

   nframes = cpl_frameset_get_size(sof);

    /* Get the raw and the calibration files */


   sinfo_extract_raw_frames_type(sof,raw,PRO_FIBRE_NS_STACKED);
   

   nraw=cpl_frameset_get_size(*raw);
   if (nraw < 1) {
      sinfo_msg_error("Too few (%d) raw frames (%s) present "
                      "in frameset!Aborting...",nraw,PRO_FIBRE_NS_STACKED);
        sinfo_distpar_delete(d);
    sinfo_wcal_delete(w);
          (*status)++;
          return;
   }


   if(NULL != cpl_frameset_find(sof,PRO_WAVE_LAMP_STACKED)) {
      frame = cpl_frameset_find(sof,PRO_WAVE_LAMP_STACKED);
      strcpy(cfg -> inFrame,cpl_frame_get_filename(frame));
   } else {
      sinfo_msg_error("Frame %s not found! Exit!", PRO_WAVE_LAMP_STACKED);
        sinfo_distpar_delete(d);
    sinfo_wcal_delete(w);
        (*status)++;
      return;
   }

   strcpy(cfg -> outName, DISTORTION_OUT_FILENAME);


   if(NULL != cpl_frameset_find(sof,REF_LINE_ARC)) {
      frame = cpl_frameset_find(sof,REF_LINE_ARC);
      strcpy(cfg -> lineList,cpl_frame_get_filename(frame));
   } else {
      sinfo_msg_error("Frame %s not found! Exit!", REF_LINE_ARC);
        sinfo_distpar_delete(d);
    sinfo_wcal_delete(w);
        (*status)++;
      return;
   }

   if(NULL != cpl_frameset_find(sof,PRO_FIBRE_NS_STACKED)) {
      frame = cpl_frameset_find(sof,PRO_FIBRE_NS_STACKED);
      strcpy(cfg -> nsFrame,cpl_frame_get_filename(frame));
   } else {
      sinfo_msg_error("Frame %s not found! Exit!", PRO_FIBRE_NS_STACKED);
        sinfo_distpar_delete(d);
    sinfo_wcal_delete(w);
        (*status)++;
      return;
   }


   if(NULL != cpl_frameset_find(sof,PRO_BP_MAP_DI)) {
      frame = cpl_frameset_find(sof,PRO_BP_MAP_DI);
      strcpy(cfg -> mask,cpl_frame_get_filename(frame));
   } else {
      sinfo_msg_error("Frame %s not found! Exit!", PRO_BP_MAP_DI);
        sinfo_distpar_delete(d);
    sinfo_wcal_delete(w);
        (*status)++;
      return;
   }


  
   frame = cpl_frameset_get_frame(*raw,0);
   sinfo_get_spatial_res(frame,spat_res);
 
   switch(sinfo_frame_is_on(frame)) 
     {
   case 0: 
      strcpy(lamp_status,"on");
      break;
    case 1: 
      strcpy(lamp_status,"off");
      break;
    case -1:
      strcpy(lamp_status,"undefined");
      break;
    default: 
      strcpy(lamp_status,"undefined");
      break;
     }

   sinfo_get_band(frame,band);
   sinfo_msg("Spatial resolution: %s lamp_status: %s band: %s \n",
                     spat_res,    lamp_status,    band);


   sinfo_get_ins_set(band,&ins_set);
    if(NULL != cpl_frameset_find(sof,DRS_SETUP_WAVE)) {
     frame = cpl_frameset_find(sof,DRS_SETUP_WAVE);
        strcpy(cfg -> drs_setup,cpl_frame_get_filename(frame));
        drs_tab = cpl_table_load(cfg->drs_setup,1,0);
        w->wstart=cpl_table_get_double(drs_tab,"W_START",ins_set,&check);
        w->wgdisp1=cpl_table_get_double(drs_tab,"W_DISP1",ins_set,&check);
        w->wgdisp2=cpl_table_get_double(drs_tab,"W_DISP2",ins_set,&check);
        w->hw=cpl_table_get_int(drs_tab,"W_HW",ins_set,&check);
        w->fwhm=cpl_table_get_double(drs_tab,"W_FWHM",ins_set,&check);
        w->min_amp=cpl_table_get_double(drs_tab,"W_MIN_AMP",ins_set,&check);
    /*
        w->min_dif=cpl_table_get_double(drs_tab,"W_MIN_DIF",ins_set,&check);
        w->na_coef=cpl_table_get_int(drs_tab,"W_NA_COEFF",ins_set,&check);
        w->nb_coef=cpl_table_get_int(drs_tab,"W_NB_COEFF",ins_set,&check);
        w->pixel_tol=cpl_table_get_double(drs_tab,"W_PIX_TOL",ins_set,&check);
        w->y_box=cpl_table_get_double(drs_tab,"W_Y_BOX",ins_set,&check);
    */
        w->low_pos=cpl_table_get_int(drs_tab,"W_LOW_POS",ins_set,&check);
        w->hig_pos=cpl_table_get_int(drs_tab,"W_HI_POS",ins_set,&check);

    cfg -> guessBeginWavelength = w->wstart;
    cfg -> guessDispersion1 =  w->wgdisp1;
    cfg -> guessDispersion2 =  w->wgdisp2;
    cfg -> halfWidth =         w->hw;
    cfg -> fwhm =              w->fwhm;
    cfg -> minAmplitude =      w->min_amp;
    /*
    cfg -> mindiff =           w->min_dif;
    cfg -> nrDispCoefficients = w->na_coef;
    cfg -> nrCoefCoefficients = w->nb_coef;
    cfg -> pixel_tolerance =    w->pixel_tol;
    cfg -> yBox =               w->y_box;
    */
    cfg -> loPos =              DISTORTION_LOPOS;
    cfg -> hiPos =              DISTORTION_HIPOS;
    cfg -> pixel_tolerance =    w->pixel_tol;
        cfg-> diffTol = d->diff_tol[ins_set];
	/*
        sinfo_msg("cfg->guessBeginWavelength %g",cfg -> guessBeginWavelength);
        sinfo_msg("cfg->guessDispersion1 %g",cfg -> guessDispersion1);
        sinfo_msg("cfg->guessDispersion2 %g",cfg -> guessDispersion2);
        sinfo_msg("cfg->mindiff %g",cfg -> mindiff);
        sinfo_msg("cfg->halfWidth %d",cfg ->  halfWidth);
        sinfo_msg("cfg->fwhm %g",cfg -> fwhm);
        sinfo_msg("cfg->minAmplitude %g",cfg -> minAmplitude);
        sinfo_msg("cfg->nrDispCoefficients %d",cfg -> nrDispCoefficients);
        sinfo_msg("cfg->nrCoefCoefficients %d",cfg -> nrCoefCoefficients);
        sinfo_msg("cfg->pixel_tolerance  %g",cfg -> pixel_tolerance);
        sinfo_msg("cfg->loPos %d",cfg -> loPos);
        sinfo_msg("cfg->hiPos %d",cfg -> hiPos);
        sinfo_msg("cfg->yBox  %f",cfg -> yBox);
	*/
        sinfo_distpar_delete(d);
    sinfo_wcal_delete(w);
        cpl_table_delete(drs_tab);
        if(-1 == sinfo_check_rec_status(0)) {
      (*status)++;
      return;
    }

   } else {
    sinfo_msg_error("Frame %s not found! Exit!", DRS_SETUP_WAVE);
        sinfo_distpar_delete(d);
    sinfo_wcal_delete(w);
        (*status)++;
        return;
   }


   nstp=sinfo_nstpar_new();  
   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.ns_fwhm");
   if(cpl_parameter_get_default_flag(p) == 0) {
      cfg->nsfwhm=nstp->fwhm[ins_set];
   } else {
      cfg->nsfwhm=cpl_parameter_get_double(p);
   }

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.min_diff");
   if(cpl_parameter_get_default_flag(p) == 0) {
     cfg->minDiff=nstp->min_dif[ins_set];
   } else {
     cfg->minDiff=cpl_parameter_get_double(p);
   }
   sinfo_nstpar_delete(nstp);
   //sinfo_msg("cfg -> nsfwhm  %f",cfg -> nsfwhm);
   //sinfo_msg("cfg -> minDiff  %f",cfg -> minDiff);


   return;

}


/**
  @name     parse_section_findlines
  @memo     Parse input findlines parameters
  @param    cfg pointer to finddist_config structure
  @param    cpl_cfg   pointer to parameter list
  @return   void
 */

static void     
parse_section_findlines(finddist_config * cfg,cpl_parameterlist * cpl_cfg)
{

   cpl_parameter* p;

   p = cpl_parameterlist_find(cpl_cfg, 
                              "sinfoni.distortion.min_diff_mean_med_col_int");
   cfg -> mindiff =  cpl_parameter_get_double(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.half_width");
   cfg -> halfWidth = cpl_parameter_get_int(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.sigma");
   cfg -> sigma =  cpl_parameter_get_double(p);

   return ;

}

/**
  @name     parse_section_wavecalib
  @memo     Parse input wavecalib parameters
  @param    cfg pointer to finddist_config structure
  @param    cpl_cfg   pointer to parameter list
  @return   void
 */
static void     
parse_section_wavecalib(finddist_config * cfg,cpl_parameterlist * cpl_cfg)
{


   cpl_parameter* p;

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.fwhm");
   cfg -> fwhm =  cpl_parameter_get_double(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.min_amplitude");
   cfg -> minAmplitude =  cpl_parameter_get_double(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.max_residual");
   cfg -> maxResidual =  cpl_parameter_get_double(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.n_a_coefficients");
   cfg -> nrDispCoefficients = cpl_parameter_get_int(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.n_b_coefficients");
   cfg -> nrCoefCoefficients = cpl_parameter_get_int(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.sigma_factor");
   cfg -> sigmaFactor =  cpl_parameter_get_double(p);


   cfg -> nslitlets = NSLITLETS;

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.pixel_dist");
   cfg -> pixeldist = cpl_parameter_get_int(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.pixel_tol");
   cfg -> pixel_tolerance = cpl_parameter_get_double(p);



}

/**
  @name     parse_section_wavemap
  @memo     Parse input wavemap parameters
  @param    cfg pointer to finddist_config structure
  @param    cpl_cfg   pointer to parameter list
  @return   void
 */
static void     
parse_section_wavemap(finddist_config * cfg,cpl_parameterlist * cpl_cfg)
{
   cpl_parameter* p;

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.mag_factor");
   cfg -> magFactor = cpl_parameter_get_int(p);

}

/**
  @name     parse_section_findslits
  @memo     Parse input findlists parameters
  @param    cfg pointer to finddist_config structure
  @param    cpl_cfg   pointer to parameter list
  @return   void
 */
static void     
parse_section_fitslits(finddist_config * cfg,cpl_parameterlist * cpl_cfg)
{

   cpl_parameter* p;

   cfg -> loPos =  DISTORTION_LOPOS;
   cfg -> hiPos =  DISTORTION_HIPOS;

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.box_length");
   cfg -> boxLength = cpl_parameter_get_int(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.y_box");
   cfg -> yBox = cpl_parameter_get_double(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.diff_tol");
   cfg -> diffTol =  cpl_parameter_get_double(p);

}

/**
  @name     parse_section_qclog
  @memo     Parse input qclog parameters
  @param    cfg pointer to finddist_config structure
  @param    cpl_cfg   pointer to parameter list
  @return   void
 */
static void     
parse_section_qclog      (finddist_config * cfg, cpl_parameterlist* cpl_cfg)
{
   cpl_parameter* p;

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.qc_thresh_min");
   cfg ->  qc_thresh_min = cpl_parameter_get_int(p);


   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.qc_thresh_max");
   cfg ->  qc_thresh_max = cpl_parameter_get_int(p);


}


/**
  @name     parse_section_northsouthtest
  @memo     Parse input northsouthtest parameters
  @param    cfg pointer to finddist_config structure
  @param    cpl_cfg   pointer to parameter list
  @return   void
 */
static void     
parse_section_northsouthtest(finddist_config * cfg,cpl_parameterlist * cpl_cfg)
{

   cpl_parameter *p;   
   strcat(cfg -> fitsname, DISTORTION_NS_OUT_FILENAME);

   cfg -> nslits = NSLITLETS;

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.ns_half_width");
   cfg -> nshalfWidth = cpl_parameter_get_int(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.ns_fwhm");
   cfg -> nsfwhm = cpl_parameter_get_double(p);

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.min_diff");
   cfg -> minDiff = cpl_parameter_get_double(p);

   cfg -> estimated_dist = ESTIMATED_SLITLETS_DISTANCE;

   p = cpl_parameterlist_find(cpl_cfg, "sinfoni.distortion.dev_tol");
   cfg -> devtol = cpl_parameter_get_double(p);

   return ;

}

/**
 @name sinfo_finddist_free
 @memo deallocate finddist_config structure
 @param cfg pointer to finddist_config structure
 @return void
*/

void
sinfo_finddist_free(finddist_config ** cfg)
{  

  if(*cfg!=NULL) {
    sinfo_finddist_cfg_destroy(*cfg);
    *cfg=NULL;
  }
  return;

}
