/*
 * 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_wavecal_ini_by_cpl.c
   Author       :   Andrea Modigliani
   Created on   :   May 21, 2004
   Description  :   wavelength calibration cpl input handling for SPIFFI

 ---------------------------------------------------------------------------*/

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


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

#include <string.h>
#include "sinfo_wavecal_ini_by_cpl.h"
#include "sinfo_raw_types.h"
#include "sinfo_pro_types.h"
#include "sinfo_ref_types.h"
#include "sinfo_hidden.h"
#include "sinfo_functions.h"
#include "sinfo_utils.h"
/*---------------------------------------------------------------------------
                    Functions private to this module
 ---------------------------------------------------------------------------*/

static void
parse_section_frames ( wave_config *, cpl_parameterlist* cpl_cfg, cpl_frameset* sof,
                       cpl_frameset** raw, int* status );

static void
parse_section_findlines ( wave_config *, cpl_parameterlist* cpl_cfg );
static void
parse_section_wavecalib ( wave_config *, cpl_parameterlist* cpl_cfg );
static void
parse_section_wavemap ( wave_config *, cpl_parameterlist* cpl_cfg );
static void
parse_section_qclog ( wave_config *, cpl_parameterlist* cpl_cfg );
static void
parse_section_fitslits ( wave_config *, cpl_parameterlist* cpl_cfg );



/**@{*/
/**
 * @addtogroup sinfo_rec_wavecal wavecal structure initialization
 *
 * TBD
 */


/*-------------------------------------------------------------------------*/
/**
  @name     generateWave_ini_file
  @memo     Generate a default ini file for the SPIFFI wavelength calibration.
  @param    ini_name    Name of the file to generate.
  @param    name_i      Name of the input file, that means the name of the
                        interleaved or convolved emission line frame.
  @param    name_o      Name of the output file.
  @param    name_c      Name of the calibration file, that means the name
                        of the line list.
  @return   int 0 if Ok, -1 otherwise.
  @doc

  This function generates a default ini file for the wavelength calibration.
  The generated file will have the requested name. If you do not want to
  provide names for the input/output/calib files, feed either NULL pointers
  or character strings starting with (char)0.
 */
/*--------------------------------------------------------------------------*/

/* Removed  generateWave_ini_file */

/*-------------------------------------------------------------------------*/
/**
  @name     parse_wave_ini_file
  @memo     Parse a ini_name.ini file and create a blackboard.
  @param    ini_name    Name of the ASCII file to parse.
  @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.
 */
/*--------------------------------------------------------------------------*/

wave_config *
sinfo_parse_cpl_input_wave ( cpl_parameterlist* cpl_cfg,
                             cpl_frameset* sof, cpl_frameset** raw )
{

    int  status=0;
    wave_config   * cfg= sinfo_wave_cfg_create();
    /*
     * Perform sanity checks, fill up the structure with what was
     * found in the ini file
     */

    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_qclog ( cfg, cpl_cfg );
    parse_section_frames ( cfg, cpl_cfg, sof, raw, &status );

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


/*---------------------------------------------------------------------------
   Functions:   parse_section_xxx()
   In           :       symbolic table read from ini file
   Out          :       void
   Job          :       update a wave_config structure from what can be
                            found in the ini file.
   Notice       :       all of these functions update a status integer to
                        indicate if an error occurred, or leave it as it is if
                        everything went Ok.

        parse_section_general()
        parse_section_findlines()
        parse_section_wavecalib()
        parse_section_wavemap()
        parse_section_fitslits()

 ---------------------------------------------------------------------------*/



static void
parse_section_frames ( wave_config * cfg,cpl_parameterlist* cpl_cfg, cpl_frameset* sof,
                       cpl_frameset** raw, int* status )
{
    cpl_frame* frame   = NULL;
    char spat_res[FILE_NAME_SZ];
    char lamp_status[FILE_NAME_SZ];
    char band[FILE_NAME_SZ];
    int ins_set=0;
    int nraw=0;

    wcal* w=sinfo_wcal_new();
    int check=0;

    sinfo_extract_raw_frames_type ( sof,raw,PRO_WAVE_LAMP_STACKED );
    nraw=cpl_frameset_get_size ( *raw );
    if ( nraw==0 )
    {
        sinfo_extract_raw_frames_type ( sof,raw,PRO_WAVE_NS_STACKED );
    }
    nraw=cpl_frameset_get_size ( *raw );
    if ( nraw==0 )
    {
        sinfo_extract_raw_frames_type ( sof,raw,PRO_WAVE_SLITPOS_STACKED );
    }

    nraw=cpl_frameset_get_size ( *raw );
    if ( nraw==0 )
    {
        sinfo_msg ( "Frame %s or %s or %s not found!",
                        PRO_WAVE_LAMP_STACKED,PRO_WAVE_NS_STACKED,PRO_WAVE_SLITPOS_STACKED );
        ( *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,PRO_WAVE_LAMP_STACKED ) )
    {
        frame = cpl_frameset_find ( sof,PRO_WAVE_LAMP_STACKED );
        strcpy ( cfg -> inFrame,cpl_frame_get_filename ( frame ) );
    }
    else if ( NULL != cpl_frameset_find ( sof,PRO_WAVE_NS_STACKED ) )
    {
        frame = cpl_frameset_find ( sof,PRO_WAVE_NS_STACKED );
        strcpy ( cfg -> inFrame,cpl_frame_get_filename ( frame ) );
    }
    else if ( NULL != cpl_frameset_find ( sof,PRO_WAVE_SLITPOS_STACKED ) )
    {
        frame = cpl_frameset_find ( sof,PRO_WAVE_SLITPOS_STACKED );
        strcpy ( cfg -> inFrame,cpl_frame_get_filename ( frame ) );
    }
    else
    {
        sinfo_msg_error ( "Frame %s or %s not found! Exit!",
                        PRO_WAVE_LAMP_STACKED,PRO_WAVE_NS_STACKED );
        ( *status ) ++;
        return;
    }


    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 ) );
        cpl_table* 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;
        cpl_parameter* p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.half_width" );
        if ( sinfo_parameter_get_default_flag ( p ) == 0 )
        {
            /*         cpl_msg_info(cpl_func, "param sinfoni.wavecal.half_width - using value from DRS [%i]", w->hw);*/
            cfg -> halfWidth =         w->hw;
        }
        else
        {
            /*         cpl_msg_info(cpl_func, "param sinfoni.wavecal.half_width - using value from command line [%g]", cfg -> halfWidth);   */
        }

        p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.fwhm" );
        if ( sinfo_parameter_get_default_flag ( p ) == 0 )
        {
            cfg -> fwhm =              w->fwhm;
            /*         cpl_msg_info(cpl_func, "param sinfoni.wavecal.fwhm - using value from DRS [%g]", cfg -> fwhm);  */
        }
        else
        {
            /*         cpl_msg_info(cpl_func, "param sinfoni.wavecal.fwhm - using value from command line [%g]", cfg -> fwhm);     */
        }
        p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.min_amplitude" );
        if ( sinfo_parameter_get_default_flag ( p ) == 0 )
        {
            cfg -> minAmplitude =      w->min_amp;
            /*         cpl_msg_info(cpl_func, "param sinfoni.wavecal.min_amplitude - using value from DRS [%g]", cfg -> minAmplitude);         */
        }
        else
        {
            /*         cpl_msg_info(cpl_func, "param sinfoni.wavecal.min_amplitude - using value from command line [%g]", cfg -> minAmplitude);     */
        }
        /*
		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 =              w->low_pos;
        cfg -> hiPos =              w->hig_pos;
        /* cfg -> pixel_tolerance =    w->pixel_tol; */
        /*
		    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_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 );
        ( *status ) ++;
        return;
    }


    if ( NULL != cpl_frameset_find ( sof,REF_LINE_OH ) )
    {
        frame = cpl_frameset_find ( sof,REF_LINE_OH );
        strcpy ( cfg -> lineList,cpl_frame_get_filename ( frame ) );
    }
    else 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 );
        ( *status ) ++;
        return;
    }


    if ( NULL != cpl_frameset_find ( sof,PRO_SLIT_POS_GUESS ) )
    {
        frame = cpl_frameset_find ( sof,PRO_SLIT_POS_GUESS );
        strcpy ( cfg -> slitposGuessName,cpl_frame_get_filename ( frame ) );
    }
    else
    {
        sinfo_msg ( "Frame %s not found!", PRO_SLIT_POS_GUESS );
    }

    if ( cfg -> writeParInd ==0 )
    {
        if ( NULL != cpl_frameset_find ( sof,PRO_WAVE_PAR_LIST ) )
        {
            frame = cpl_frameset_find ( sof,PRO_WAVE_PAR_LIST );
            strcpy ( cfg ->  paramsList,cpl_frame_get_filename ( frame ) );
        }
        else
        {
            sinfo_msg ( "Frame %s not found!", PRO_WAVE_PAR_LIST );
            ( *status ) ++;
            return   ;
        }

    }
    else
    {

        strcpy ( cfg -> paramsList, WAVECAL_FIT_PARAMS_OUT_FILENAME );
        sinfo_msg ( "cfg -> paramsList %s not given\n",cfg -> paramsList );

    }



    if ( cfg -> calibIndicator ==  0 )
    {
        if ( NULL != cpl_frameset_find ( sof,PRO_WAVE_COEF_SLIT ) )
        {
            frame = cpl_frameset_find ( sof,PRO_WAVE_COEF_SLIT );
            strcpy ( cfg -> coeffsName,cpl_frame_get_filename ( frame ) );
        }
        else
        {
            sinfo_msg_error ( "Frame %s not found! Exit!", PRO_WAVE_COEF_SLIT );
            ( *status ) ++;
            return;
        }
    }
    else
    {

        strcpy ( cfg -> coeffsName, WAVECAL_COEFF_SLIT_OUT_FILENAME );
        sinfo_msg ( "cfg -> coeffsName %s not given\n",cfg -> coeffsName );

    }

    strcpy ( cfg -> outName, WAVECAL_OUT_FILENAME );
    strcpy ( cfg -> slitposName, WAVECAL_SLIT_POS_OUT_FILENAME );

    return;
}


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

    cpl_parameter* p;

    p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.calib_indicator" );
    cfg -> calibIndicator = cpl_parameter_get_bool ( p );

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

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

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

    return ;
}

static void
parse_section_wavecalib ( wave_config * cfg,cpl_parameterlist* cpl_cfg )
{
    cpl_parameter* p;

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

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

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

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

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

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

    p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.write_coeffs_ind" );
    cfg -> writeCoeffsInd = cpl_parameter_get_bool ( p );

    p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.write_par_ind" );
    cfg -> writeParInd = cpl_parameter_get_bool ( p );

    cfg -> nslitlets = NSLITLETS;

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

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

}

static void
parse_section_wavemap ( wave_config * cfg,cpl_parameterlist* cpl_cfg )
{
    cpl_parameter* p;

    p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.wave_map_ind" );
    cfg -> wavemapInd = cpl_parameter_get_bool ( p );

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


}

static void
parse_section_fitslits ( wave_config * cfg,cpl_parameterlist* cpl_cfg )
{

    cpl_parameter* p;

    p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.slit_pos_indicator" );
    cfg -> slitposIndicator = cpl_parameter_get_bool ( p );

    p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.fit_boltz_indicator" );
    cfg -> fitBoltzIndicator = cpl_parameter_get_bool ( p );

    p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.fit_edge_indicator" );
    cfg -> fitEdgeIndicator = cpl_parameter_get_bool ( p );

    p = cpl_parameterlist_find ( cpl_cfg, "sinfoni.wavecal.estimate_indicator" );
    cfg -> estimateIndicator = cpl_parameter_get_bool ( p );

    cfg -> loPos =  750;
    cfg -> hiPos =  1000;

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

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

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

    /* input CDB
	p = cpl_parameterlist_find(cpl_cfg, "sinfoni.wavecal.slit_pos_guess_name");
	strcpy(cfg -> slitposGuessName, cpl_parameter_get_default_string(p));
     */

}

static void
parse_section_qclog ( wave_config * cfg, cpl_parameterlist* cpl_cfg )
{
    cpl_parameter* p;

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


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


}

void
sinfo_wavecal_free ( wave_config ** cfg )
{
    if ( *cfg != NULL )
    {
        sinfo_wave_cfg_destroy ( *cfg );
        *cfg=NULL;
    }
    return;

}


/**@}*/
