/*                                                                            *
 *   This file is part of the ESO X-shooter Pipeline                          *
 *   Copyright (C) 2006 European Southern Observatory                         *
 *                                                                            *
 *   This library 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     *
 *                                                                            */

/*
 * $Author: amodigli $
 * $Date: 2012-12-02 09:08:49 $
 * $Revision: 1.4 $
 */

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

/*----------------------------------------------------------------------------*/
/**
 * @defgroup xsh_compute_slice_dist  Compute Slice Offsets (xsh_geom_ifu)
 * @ingroup drl_functions
 *
 * Function ...
 */
/*----------------------------------------------------------------------------*/
/**@{*/

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

#include <math.h>
#include <xsh_drl.h>

#include <xsh_utils_table.h>
#include <xsh_badpixelmap.h>
#include <xsh_data_pre.h>
#include <xsh_dfs.h>
#include <xsh_pfits.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <xsh_fit.h>
#include <xsh_data_instrument.h>
#include <xsh_data_localization.h>
#include <xsh_data_spectrum.h>
#include <xsh_dfs.h>
#include <cpl.h>

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

/*-----------------------------------------------------------------------------
  Implementation
  ----------------------------------------------------------------------------*/




/*---------------------------------------------------------------------------*/
/**
    @brief 
      Mark telluric in spectrum
    @param[in,out] s1d_frame
      1D spectrum
    @param[in] tellmask_frame
      Mask of telluric
    
*/
/*---------------------------------------------------------------------------*/
void xsh_mark_tell( cpl_frame *s1d_frame, cpl_frame *tellmask_frame)
{
  xsh_spectrum *s1d = NULL;
  int *qual = NULL;
  int size;
  cpl_vector *tellmask_vect = NULL;
  int tellmask_size, i;
  const char *s1d_name = NULL;
  const char *tag = NULL;
  cpl_frame *result = NULL;
  
  XSH_ASSURE_NOT_NULL( s1d_frame);
  
  check( tag = cpl_frame_get_tag( s1d_frame));
  check( s1d_name = cpl_frame_get_filename( s1d_frame));
  
  check( s1d = xsh_spectrum_load( s1d_frame));
  check( qual = xsh_spectrum_get_qual( s1d));
  check( size = xsh_spectrum_get_size( s1d));
  
  if ( tellmask_frame != NULL){
    const char* tellmask_name = NULL;
    
    check( tellmask_name = cpl_frame_get_filename( tellmask_frame));
    xsh_msg("Use telluric mask %s", tellmask_name);
    
    check( tellmask_vect = cpl_vector_load( tellmask_name, 0));
    check( tellmask_size = cpl_vector_get_size( tellmask_vect));

    XSH_ASSURE_NOT_ILLEGAL( tellmask_size == size);
    
    for( i=0; i< size; i++){
      double mask_val;
      
      mask_val = cpl_vector_get( tellmask_vect, i);
      
      if ( mask_val > 0){
        qual[i] |= QFLAG_TELLURIC_UNCORRECTED;
      }
    }
    check( result = xsh_spectrum_save( s1d, s1d_name, tag));
  }
  else{
    xsh_msg("No telluric mask");
  }
  
  cleanup:   
    xsh_free_frame( &result);
    xsh_spectrum_free( &s1d);
    xsh_free_vector( &tellmask_vect);
}
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/**
   @brief 
     Compute the shift in slit between reference wavelength and others for
     all the slitlets
   @param[in] s1d_frame
     Reference wavelength
   @pram[in] tellist_frame
     List of telluric intervals
   @param[in] filter_hsize
     Tables containing for wavelength the position of object center on the slit
   @param[in] threshold
     Tables containing a preceding shift ifu tab. This table will be sum to 
     the new
   @return Telluric mask
*/
/*---------------------------------------------------------------------------*/
cpl_frame* xsh_compute_absorp( cpl_frame *s1d_frame, cpl_frame *telllist_frame,
  int filter_hsize, double threshold, xsh_instrument* instr)
{
  cpl_frame *result = NULL;
  xsh_spectrum *s1d = NULL;
  double *flux_data = NULL;
  cpl_vector *flux_vect = NULL;
  cpl_vector *smooth_vect = NULL;
  double *diff_data = NULL;
  cpl_vector *diff_vect = NULL;
  cpl_vector *std_vect = NULL;
  cpl_vector *std_box_vect = NULL;
  cpl_vector *tellmask = NULL;
  int i, size = 0; 
  double wmin=0, wstep=0;
  
  char mask_name[256];
  char tag[16];
  
  int *tellflag = NULL;
  const char* tellist_name = NULL;
  cpl_table *tellist_table = NULL;

  XSH_ASSURE_NOT_NULL( s1d_frame);
  XSH_ASSURE_NOT_NULL( instr);
  
  xsh_msg( "Compute absorp");
  
  XSH_REGDEBUG("File %s list %s filter %d threshold %f", cpl_frame_get_filename( s1d_frame),
     cpl_frame_get_filename( telllist_frame), filter_hsize, threshold);

  check( s1d = xsh_spectrum_load( s1d_frame));
  
  wmin = s1d->lambda_min;
  wstep = s1d->lambda_step;
  
  size = xsh_spectrum_get_size_lambda( s1d);
  check( flux_data = xsh_spectrum_get_flux( s1d));
  check( flux_vect = cpl_vector_wrap( size, flux_data));
  
  check( smooth_vect = cpl_vector_filter_median_create( flux_vect, 
    filter_hsize));
  check( diff_vect = cpl_vector_new( size));
  
  for( i=0; i< size; i++){
    double smooth_val, dval;
    
    smooth_val = cpl_vector_get( smooth_vect, i);
    dval = (flux_data[i]-smooth_val)/smooth_val;
    cpl_vector_set( diff_vect, i, dval);
  }

  
  check( std_vect = cpl_vector_new( size));
  check( diff_data = cpl_vector_get_data( diff_vect));
  
  for(i=0; i< (size-2*filter_hsize-1); i++){
    double dval;
    
    std_box_vect = cpl_vector_wrap( filter_hsize*2+1, diff_data+i-filter_hsize);
    dval = cpl_vector_get_stdev( std_box_vect);
    cpl_vector_set( std_vect, i, dval);
    xsh_unwrap_vector( &std_box_vect);
  }
  
  tellmask = cpl_vector_new( size);
  
  XSH_CALLOC( tellflag, int , size);
  
  /* load telluric list table */
  if ( telllist_frame != NULL){
    int it=0, table_size;
    double slit=0.0;
    double r1, r2;
    double factor_min, factor_max;
 

    check( tellist_name = cpl_frame_get_filename( telllist_frame));
    XSH_TABLE_LOAD( tellist_table, tellist_name);
    
    table_size = cpl_table_get_nrow( tellist_table);
    
    check( xsh_sort_table_1( tellist_table, LSTART_COLUMN_NAME, CPL_FALSE));
    
    if ( xsh_instrument_get_arm( instr) == XSH_ARM_UVB){
      r1 = GUESS_TELL_MASK_RESOLUTION_UVB;
    }
    else if ( xsh_instrument_get_arm( instr) == XSH_ARM_VIS){
      r1 = GUESS_TELL_MASK_RESOLUTION_VIS;
    }
    else{
      r1 = GUESS_TELL_MASK_RESOLUTION_NIR;
    }
    check( slit = xsh_pfits_get_slit_width( s1d->flux_header, instr));
    check ( r2 = xsh_resolution_get( instr, slit));
    factor_min = (r2-1)/(r1-1)*r1/r2;
    factor_max = (r2+1)/(r1+1)*r1/r2;
    i=0; 
    while( i< size){
      double wave, wtellmin, wtellmax;
      int good;
      
      tellflag[i] = 1;
      wave = wmin+i*wstep;
      check( wtellmin =  cpl_table_get_float( tellist_table, LSTART_COLUMN_NAME,
        it, &good));
      check( wtellmax =  cpl_table_get_float( tellist_table, LEND_COLUMN_NAME,
        it, &good));
      //xsh_msg("wave %f IT %d wtell [%f,%f]", wave, it, wtellmin, wtellmax);
      wtellmin *= factor_min;
      wtellmax *= factor_max;
      //xsh_msg("With resolution correction: wave %f IT %d wtell [%f,%f]", wave, it, wtellmin, wtellmax);

      if ( wave >= wtellmin){   
        if ( wave <= wtellmax){
	  tellflag[i] = 0;
	  i++;
	}
	else{
	  if ( it < table_size-1){
	    it++;
	  }
	  else{
	    i++;
	  }
	}  
      }
      else{
        i++;
      }
    }      
  }


  /* flag telluric */
  for(i=0; i< size; i++){
    //double wave;
    double noise;
    int flag;
    
    //wave = wmin+i*wstep;
    noise = cpl_vector_get( std_vect, i);
    flag = tellflag[i];
    
    /* detect telluric */
    if ( flag == 0 && noise > threshold){
      cpl_vector_set( tellmask, i,1.0);
    }
    else{
      cpl_vector_set( tellmask, i,0.0);
    }
  }
  
    
  {
    FILE* debug_file = NULL;
    
    debug_file = fopen( "out.dat", "w+");
    
    fprintf( debug_file, "#lambda flux smooth diff flag is_tell\n");
  
    for(i=0; i< size; i++){
      double mask_val;
      
      mask_val = cpl_vector_get( tellmask, i);
      fprintf( debug_file, "%f %f %f %f %f %d\n", wmin+wstep*i, flux_data[i],
        cpl_vector_get( smooth_vect, i), cpl_vector_get( std_vect, i), 
	mask_val*100, tellflag[i]*100);
    }
    fclose(debug_file);
  }
  
  
  /* save mask */

  sprintf( mask_name, "TELL_MASK.fits");
  sprintf(tag, "%s_%s", XSH_TELL_MASK, xsh_instrument_arm_tostring( instr));
 
  check( cpl_vector_save( tellmask, mask_name, XSH_PRE_QUAL_BPP,
    s1d->flux_header,  CPL_IO_CREATE));
  result = cpl_frame_new ();
 
  check( cpl_frame_set_filename ( result, mask_name));
  check( cpl_frame_set_tag( result,tag));
  check( cpl_frame_set_type( result, CPL_FRAME_TYPE_IMAGE));
  check( cpl_frame_set_group ( result, CPL_FRAME_GROUP_PRODUCT)) ;

  check( cpl_frame_set_level( result, CPL_FRAME_LEVEL_TEMPORARY));
  xsh_add_temporary_file( mask_name);


  cleanup:
    if ( cpl_error_get_code() != CPL_ERROR_NONE ) {
      xsh_free_frame( &result);
    }
    XSH_FREE( tellflag);
    xsh_unwrap_vector( &flux_vect);
    xsh_spectrum_free( &s1d);
    xsh_free_vector( &smooth_vect);
    xsh_free_vector( &diff_vect);
    xsh_free_vector( &std_vect);
    xsh_free_vector( &tellmask);
    XSH_TABLE_FREE( tellist_table);
    return result;
}
/*---------------------------------------------------------------------------*/
/**@}*/
