/*                                                                          *
 *   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: 2011-09-14 11:37:12 $
 * $Revision: 1.3 $
 */

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

/*-------------------------------------------------------------------------*/
/**
 * @defgroup test_xsh_geom_ifu  Test geom_ifu result
 * @ingroup unit_tests
 * 
 */
/*-------------------------------------------------------------------------*/
/**@{*/

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

#include <tests.h>

#include <xsh_data_pre.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <xsh_data_instrument.h>
#include <xsh_data_the_map.h>
#include <xsh_data_localization.h>
#include <xsh_data_spectralformat.h>
#include <xsh_data_spectrum.h>
#include <xsh_utils_table.h>

#include <xsh_drl.h>
#include <xsh_pfits.h>

#include <xsh_badpixelmap.h>

#include <cpl.h>
#include <math.h>

#include <getopt.h>

/*--------------------------------------------------------------------------
  Defines
  --------------------------------------------------------------------------*/

#define MODULE_ID "XSH_BUILD_CUBE"

/*--------------------------------------------------------------------------
  Implementation
  --------------------------------------------------------------------------*/
enum {
 SLITBIN_OPT, CENTER_IFU_OPT, DEBUG_OPT, HELP_OPT
};

static struct option long_options[] = {
  {"slit-bin", required_argument, 0, SLITBIN_OPT},
  {"center-ifu", required_argument, 0, CENTER_IFU_OPT},
  {"debug", required_argument, 0, DEBUG_OPT},
  {"help", 0, 0, HELP_OPT},
  {0, 0, 0, 0}
};

static void Help( void )
{
  puts( "Unitary test of xsh_build_cube");
  puts( "Usage: test_xsh_build_cube [options] <sof>");

  puts( "Options" ) ;
  puts( " --slit-bin=<n>     : Binning on slit");
  puts( " --center-ifu=<n>   : If n=1 center cube at 0 arcsec");
  puts( " --debug=<n>        : Level of debug LOW | MEDIUM | HIGH [MEDIUM]" );
  puts( " --help             : What you see" ) ;
  puts( "\nInput Files" ) ;
  puts( " 1. SOF [ORDER_TAB_EDGES_IFU_arm, OFFSET_TAB_DOWN_IFU_arm, OFFSET_TAB_CEN_IFU_arm, OFFSET_TAB_UP_IFU_arm]");
  TEST_END();
  exit(0);
}

static void HandleOptions( int argc, char **argv, double *slit_bin, int *ifu_center)
{
  int opt ;
  int option_index = 0;
  while (( opt = getopt_long (argc, argv, "debug:help",
    long_options, &option_index)) != EOF ){

    switch ( opt ) {
    case SLITBIN_OPT:
      *slit_bin = atof(optarg);
      break;
    case CENTER_IFU_OPT:
      *ifu_center = atoi(optarg);
      break;    
    case DEBUG_OPT:
      if ( strcmp( optarg, "LOW")==0){
        xsh_debug_level_set( XSH_DEBUG_LEVEL_LOW);
      }
      else if ( strcmp( optarg, "HIGH")==0){
        xsh_debug_level_set( XSH_DEBUG_LEVEL_HIGH);
      }
      break;
    case HELP_OPT:
      Help();
      break;
    default:
      break;
    }
  }
  return;
}

static void create_gaussian_profile( int nslit, double slitmin, double slitcen, 
  double slit_bin, double height, double sigma, double offset, const char* filename,
  cpl_vector **x_vect, cpl_vector **y_vect)
{
  int i;
  FILE *file = NULL;

  XSH_ASSURE_NOT_NULL( x_vect);
  XSH_ASSURE_NOT_NULL( y_vect);

  *x_vect = cpl_vector_new( nslit);
  *y_vect = cpl_vector_new( nslit);

  /* create gaussian profile */
  for(i=0; i<nslit; i++){
    double s,z,val;
    s = slitmin+i*slit_bin;
    z = (s-slitcen)/(sigma*XSH_MATH_SQRT_2);
    val = height*exp(-(z*z))+offset;
    cpl_vector_set( *x_vect, i, s);
    cpl_vector_set( *y_vect, i, val);
  } 
      
  file = fopen( filename, "w+");
  fprintf( file, "#i j x y\n");

  for( i=0; i<nslit; i++){
    double x, y;
  
    x = cpl_vector_get( *x_vect, i);
    y = cpl_vector_get( *y_vect, i);
    fprintf( file, "%d %d %f %f\n", i,nslit-1-i, x, y);
  }
  fclose( file);

  cleanup:
    if (cpl_error_get_code() != CPL_ERROR_NONE){
      xsh_free_vector( x_vect);
      xsh_free_vector( y_vect);
    }
    return;
}
/**
  @brief
    Unit test of xsh_build_cube
  @return
    0 if success

*/
int main( int argc, char **argv)
{
  /* Declarations */
  int ret = 0 ;

  xsh_instrument* instrument = NULL;

  const char *sof_name = NULL;
  cpl_frameset *set = NULL;
  cpl_frame *slitmap_frame = NULL;
  cpl_frameset *offsettab_frameset = NULL;
  int i, size;
  double sdown=0, sup=0, sldown=0, slup=0;
  double slit_bin = 0.15;
  double slitmin_tab[3];
  int nslit_tab[3];
  double slitcen_tab[3];
  double sigma = 1, height = 1, offset=0;
  cpl_vector *downx_vect = NULL;
  cpl_vector *downy_vect = NULL;
  cpl_vector *cenx_vect = NULL;
  cpl_vector *ceny_vect = NULL;
  cpl_vector *upx_vect = NULL;
  cpl_vector *upy_vect = NULL;
  cpl_vector *yvect_tab[3];
  double lmin=100, lmax=105, lstep=1;
  xsh_spectrum *spectrum = NULL;
  double smin, smax, sstep;
  double *flux = NULL;
  int s,l, k, sizes, sizel;
  cpl_frameset *merge2d_frameset = NULL;
  cpl_frame *cube_frame = NULL;
  int ifu_center = 0;

  /* Initialize libraries */
  TESTS_INIT(MODULE_ID);
  cpl_msg_set_level(CPL_MSG_DEBUG);
  xsh_debug_level_set(XSH_DEBUG_LEVEL_MEDIUM);

  HandleOptions( argc, argv, &slit_bin, &ifu_center);

  if ( (argc - optind) >=1 ) {
    sof_name = argv[optind];
  }
  else {
    Help();
    exit(0);
  }

  /* Create frameset from sof */
  check( set = sof_to_frameset( sof_name));
  /* Validate frame set */
  check( instrument = xsh_dfs_set_groups( set));
  check( slitmap_frame = xsh_find_slitmap( set, instrument));
  check( offsettab_frameset = xsh_find_offset_tab_ifu( set, instrument)); 

  size = cpl_frameset_get_size( offsettab_frameset);

  xsh_msg( "Slit binning  : %f", slit_bin);
  xsh_msg( "Ifu center    : %d", ifu_center);
  xsh_msg( "Slit map      : %s" , cpl_frame_get_filename( slitmap_frame));
  for( i=0; i< size; i++){
    cpl_frame *offsettab_frame = NULL;

    offsettab_frame = cpl_frameset_get_frame( offsettab_frameset, i);
    xsh_msg( "Offset tab %s %s", cpl_frame_get_filename( offsettab_frame), 
      cpl_frame_get_tag(  offsettab_frame));
  }
  /* get slit edges */
  xsh_get_slit_edges( slitmap_frame, &sdown, &sup, &sldown, &slup, instrument);

  xsh_msg("Estimate by FLAT slitlets");
  xsh_msg("DOWN %f --> %f", sdown, sldown);
  xsh_msg("CEN  %f --> %f", sldown, slup);
  xsh_msg("UP   %f --> %f", slup, sup);

  xsh_compute_slitlet_limits( offsettab_frameset, sdown,
    sldown, slup, sup, slit_bin, slitmin_tab, nslit_tab, slitcen_tab);

  sigma = (nslit_tab[0]/10)*slit_bin;
  height = 10*sigma;
  offset = 0;
 
  create_gaussian_profile( nslit_tab[0], slitmin_tab[0], slitcen_tab[0],
    slit_bin, height, sigma, offset, "gauss_down.dat", &downx_vect,
    &downy_vect);
  yvect_tab[0] = downy_vect;
  create_gaussian_profile( nslit_tab[1], slitmin_tab[1], slitcen_tab[1],
    slit_bin, height, sigma, offset, "gauss_cen.dat", &cenx_vect,
    &ceny_vect);
  yvect_tab[1] = ceny_vect;
  create_gaussian_profile( nslit_tab[2], slitmin_tab[2], slitcen_tab[2],
    slit_bin, height, sigma, offset, "gauss_up.dat", &upx_vect,
    &upy_vect);
  yvect_tab[2] = upy_vect;

  /* create merge2d from profile */
  merge2d_frameset = cpl_frameset_new();

  for( k=0; k<3; k++){
    char mergename[256];
    cpl_frame *frame = NULL;

    smin = slitmin_tab[k];
    sstep = slit_bin;
    smax = slitmin_tab[k]+(nslit_tab[k]-1)*slit_bin;

    check( spectrum = xsh_spectrum_2D_create( lmin, lmax, lstep,
      smin, smax, sstep));
    check( flux = xsh_spectrum_get_flux( spectrum));
    check( sizel = xsh_spectrum_get_size_lambda( spectrum));
    check( sizes = xsh_spectrum_get_size_slit( spectrum));
    for( s=0; s< sizes; s++){
      for( l=0; l<sizel; l++){
        flux[l+s*sizel] = cpl_vector_get( yvect_tab[k], s);
      }
    }
    sprintf( mergename, "merge2d_%d.fits", k);

    check( cpl_propertylist_update_double( spectrum->flux_header, "ESO DET OUT1 RON", 10));
    check( cpl_propertylist_update_double( spectrum->flux_header, "ESO DET OUT1 CONAD", 10));
    check( cpl_propertylist_update_double( spectrum->flux_header, "ESO DET OUT1 GAIN", 10));
    check( cpl_propertylist_update_double( spectrum->flux_header, "ESO DET CHIP1 PSZX", 10));
    check( cpl_propertylist_update_double( spectrum->flux_header, "ESO DET CHIP1 PSZY", 10));

    check( cpl_propertylist_update_double( spectrum->flux_header, "ESO PRO RECT LAMBDA MIN", lmin));
    check( cpl_propertylist_update_double( spectrum->flux_header, "ESO PRO RECT LAMBDA MAX", lmax));
    check( cpl_propertylist_update_double( spectrum->flux_header,"ESO PRO RECT BIN LAMBDA", lstep));


    frame = xsh_spectrum_save( spectrum, mergename,
      "MERGE_2D");
    cpl_frame_set_tag( frame, "MERGE_2D");
    xsh_spectrum_free( &spectrum);
    cpl_frameset_insert( merge2d_frameset, frame);
  }
 
  check( cube_frame = xsh_cube( merge2d_frameset, instrument,
    "TEST"));

  cleanup:
     if (cpl_error_get_code() != CPL_ERROR_NONE) {
      xsh_error_dump(CPL_MSG_ERROR);
      ret = 1;
    }
    xsh_free_frame( &cube_frame);
    xsh_free_frameset( &merge2d_frameset);
    xsh_free_frameset( &set);
    xsh_instrument_free( &instrument);
    TEST_END();
    return ret;
}
/**@}*/


