/*                                                                            *
 *   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-04-02 07:36:38 $
 * $Revision: 1.28 $
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*--------------------------------------------------------------------------*/
/**
 * @defgroup test_xsh_detect_arclines Test Detect Arc Lines
 * @ingroup unit_tests
 *
 */
/*--------------------------------------------------------------------------*/
/**@{*/

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

#include <xsh_data_instrument.h>
#include <xsh_pfits.h>
#include <xsh_drl_check.h>
#include <xsh_msg.h>
#include <xsh_utils.h>
#include <tests.h>
#include <cpl.h>
#include <math.h>
#include <stdlib.h>
#include <getopt.h>
#include <xsh_cpl_size.h>

/*---------------------------------------------------------------------------
                            Defines
 ---------------------------------------------------------------------------*/
#define MODULE_ID "XSH_SUBTRACT_SKY_SINGLE"

#define SYNTAX "Test the xsh_subtract_sky_single function\n"\
  "usage :\n  test_xsh_subtract_sky_single [<opt>] SCI_FRAME ORDER_TABLE SLITMAP WAVEMAP [LOCALIZATION} \n" \
  "SCI_FRAME    => Science frame NOCOSMIC and flat field [DIV_FF]\n"\
  "ORDER_TABLE  => Order table frame\n"\
  "SLITMAP      => Slit Map Frame\n"\
  "WAVEMAP      =>  Wave Map frame\n"\
  "LOCALIZATION => Localization frame (optional)\n\n"\
  "Options:\n"\
  " --nbkpts=<nn>  : Number of break points (default 100)\n"\
  " --method=<n>   : 0 => BSPLINE 1 => MEDIAN [BSPLINE]\n"\
  " --pos1=<n>     : Sky position 1 [0]\n"\
  " --hheight1=<n> : Sky half height 1 [0]\n"\
  " --pos2=<n>     : Sky position 2 [0]\n"\
  " --hheight2=<n> : Sky half height 2 [0]\n"\
  " --debug=<n>        : Level of debug LOW | MEDIUM | HIGH [MEDIUM]\n"\
  "The output file (after subtraction) is 'SUBTRACTED_FLUX.fits'\n"


static const char * Options = "?" ;

enum {
  NBKPTS_OPT,
  METHOD_OPT,
  POS1_OPT,
  HHEIGHT1_OPT,
  POS2_OPT,
  HHEIGHT2_OPT,
  DEBUG_OPT
} ;

static struct option LongOptions[] = {
  {"nbkpts", required_argument, 0, NBKPTS_OPT},
  {"method", required_argument, 0, METHOD_OPT},
  {"pos1", required_argument, 0, POS1_OPT},
  {"hheight1", required_argument, 0, HHEIGHT1_OPT},
  {"pos2", required_argument, 0, POS2_OPT},
  {"hheight2", required_argument, 0, HHEIGHT2_OPT},
  {"debug", required_argument, 0, DEBUG_OPT},
  {NULL, 0, 0, 0}
} ;

static void HandleOptions( int argc, char ** argv, xsh_subtract_sky_single_param* sky_par)
{
  int opt ;
  int option_index = 0;

  while( (opt = getopt_long( argc, argv, Options,
			     LongOptions, &option_index )) != EOF )
    switch( opt ) {
    case NBKPTS_OPT:
      sscanf( optarg, "%64d", &(sky_par->nbkpts1) ) ;
      break ;
    case METHOD_OPT:
      sscanf( optarg, "%64d", &(sky_par->method));
      break ;
    case POS1_OPT:
      sky_par->pos1 = atof( optarg);
      break ;
    case HHEIGHT1_OPT:
      sky_par->hheight1 = atof(optarg);
      break ;
    case POS2_OPT:
      sky_par->pos2 = atof( optarg);
      break ;
    case HHEIGHT2_OPT:
      sky_par->hheight2 = atof(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;
    default:
      printf( SYNTAX);
      exit( 0 ) ;
    }
}

static void get_max_pos( cpl_frame * frame, xsh_instrument * instrument )
{
  cpl_size x = 0, y = 0 ;
  xsh_pre * pre = NULL ;
  double max = 0 ;

  /* Load pre frame */
  pre = xsh_pre_load( frame, instrument ) ;
  max = cpl_image_get_max( pre->data ) ;
  cpl_image_get_maxpos( pre->data, &x, &y ) ;
  xsh_msg( "Maximum value: %lf at %" CPL_SIZE_FORMAT ",%" CPL_SIZE_FORMAT "", max, x, y ) ;
  xsh_pre_free( &pre ) ;
}

/*--------------------------------------------------------------------------*/
/**
  @brief    Unit test of XSH_DETECT_ARCLINES
  @return   0 if tests passed successfully

  Test the Data Reduction Library function XSH_DETECT_ARCLINES
 */
/*--------------------------------------------------------------------------*/

int main(int argc, char** argv)
{
  cpl_frame * sci_frame = NULL ;
  cpl_frame * order_frame = NULL ;
  cpl_frame * slitmap_frame = NULL ;
  cpl_frame * wavemap_frame= NULL ;
  cpl_frame * local_frame = NULL ;
  cpl_frame * sky_line_list_frame = NULL ;

  char * sci_name = NULL, * order_name = NULL, * slitmap_name = NULL,
    * wavemap_name = NULL, * local_name = NULL , * sky_line_list_name = NULL;

  xsh_instrument * instrument = NULL ;
  cpl_frame * sky_spectrum = NULL ;
  cpl_frame * sky_spectrum_eso = NULL ;
  //cpl_frame *sky_frame_ima = NULL;

  cpl_frame * result = NULL ;
  xsh_subtract_sky_single_param sky_par = {1000, 1000,7,20, 5., -1, -1, 
					   BSPLINE_METHOD,FINE, 7, 1.5, 
                                           0.,0.,0.,0.}; 
  int nb_frames = 0 ;
  char * tag ;
  XSH_ARM arm = XSH_ARM_UNDEFINED;
  cpl_propertylist *plist = NULL;
  int ret=0;
  const int decode_bp=2144337919;
  TESTS_INIT(MODULE_ID);
  cpl_msg_set_level(CPL_MSG_DEBUG);
  xsh_debug_level_set(XSH_DEBUG_LEVEL_MEDIUM);

  /* init parameters */
  sky_par.slit_edges_mask = 0.5;
  sky_par.median_hsize = 20;
  sky_par.nbkpts1 = 3000;
  sky_par.nbkpts2 = 3000;
  sky_par.bezier_spline_order = 4;
  sky_par.niter = 1;
  sky_par.ron = -1;
  sky_par.kappa = 5;
  sky_par.gain = -1;
  sky_par.bspline_sampling = FINE;
  sky_par.pos1 = 0.0;
  sky_par.hheight1 = 0.0;
  sky_par.pos2 = 0.0;
  sky_par.hheight2 = 0.0;

  /* Analyse parameters */
  HandleOptions( argc, argv, &sky_par );

  xsh_msg( "Nb of breakpts = %d", sky_par.nbkpts1);

  /* Retrieve arguments */
  nb_frames = argc - optind;
  xsh_msg( "Nb of inputs = %d", nb_frames);
  if ( nb_frames >= 4 ) {
    sci_name = argv[optind] ;
    order_name = argv[optind+1] ;
    slitmap_name = argv[optind+2] ;
    wavemap_name = argv[optind+3] ;
    if ( nb_frames >= 5 )
       sky_line_list_name = argv[optind+4] ;
    if ( nb_frames == 6 )
      local_name = argv[optind+5] ;

  }
  else{
    xsh_msg( "Not enough Input Frames\n" ) ;
    printf(SYNTAX);
    TEST_END();
    exit(0);
  }

  xsh_msg("Sci frame : %s", sci_name);
  xsh_msg("Order frame : %s", order_name);
  xsh_msg("Slit map frame : %s",slitmap_name);
  xsh_msg("Wave map frame : %s",wavemap_name);
  if (local_name != NULL){
    xsh_msg("Localization frame : %s", local_name);
  }
  if (sky_line_list_name != NULL){
     xsh_msg("Ref sky line list frame : %s", sky_line_list_name);
   }
  xsh_msg("---Parameters");
  xsh_msg("method          : %s", SKY_METHOD_PRINT(sky_par.method));
  xsh_msg("slit edges mask : %f", sky_par.slit_edges_mask);

  xsh_msg("position1 : %f hheight1 : %f", sky_par.pos1, sky_par.hheight1);
  xsh_msg("position2 : %f hheight2 : %f", sky_par.pos2, sky_par.hheight2);

  if (sky_par.method == MEDIAN_METHOD){
    xsh_msg("median half size : %d", sky_par.median_hsize);
  } 
  check( plist = cpl_propertylist_load( sci_name, 0));
  check( arm = xsh_pfits_get_arm( plist));

  TESTS_XSH_INSTRUMENT_CREATE( instrument, XSH_MODE_SLIT, arm, 
    XSH_LAMP_UNDEFINED, "xsh_scired_slit_stare");


  /* This generates SEG fault
  if(instrument->arm == XSH_ARM_NIR) {
     if(xsh_instrument_nir_is_JH(sci_frame,instrument)) {

        instrument->config->order_min=13;
        instrument->config->order_max=26;
        instrument->config->orders=14;
     }
   }
*/

  /* load frames */
  tag = XSH_GET_TAG_FROM_ARM(XSH_OBJECT_SLIT_STARE, instrument) ;
  TESTS_XSH_FRAME_CREATE( sci_frame, tag, sci_name ) ;
  /* Find maximum in frame */
  get_max_pos( sci_frame, instrument ) ;
  xsh_instrument_set_decode_bp( instrument, decode_bp ) ;
  tag = XSH_GET_TAG_FROM_LAMP(XSH_ORDER_TAB_EDGES,instrument) ;
  TESTS_XSH_FRAME_CREATE( order_frame, tag, order_name ) ;
  cpl_frame_set_group( order_frame, CPL_FRAME_GROUP_CALIB ) ;

  tag = XSH_GET_TAG_FROM_ARM(XSH_SLIT_MAP,instrument) ;
  TESTS_XSH_FRAME_CREATE( slitmap_frame, tag, slitmap_name ) ;
  cpl_frame_set_group( slitmap_frame, CPL_FRAME_GROUP_CALIB ) ;

  tag = XSH_GET_TAG_FROM_ARM(XSH_WAVE_MAP,instrument) ;
  TESTS_XSH_FRAME_CREATE( wavemap_frame, tag, wavemap_name ) ;
  cpl_frame_set_group( wavemap_frame, CPL_FRAME_GROUP_CALIB ) ;

  if ( local_name != NULL ) {
    tag = XSH_GET_TAG_FROM_ARM(XSH_LOCALIZATION,instrument) ;
    TESTS_XSH_FRAME_CREATE( local_frame, tag, local_name ) ;
    cpl_frame_set_group( local_frame, CPL_FRAME_GROUP_CALIB ) ;
  }

  if ( sky_line_list_name != NULL ) {
     tag = XSH_GET_TAG_FROM_ARM(XSH_SKY_LINE_LIST,instrument) ;
     TESTS_XSH_FRAME_CREATE( sky_line_list_frame, tag, sky_line_list_name ) ;
     cpl_frame_set_group( sky_line_list_frame, CPL_FRAME_GROUP_CALIB ) ;
   }

  check(result = xsh_subtract_sky_single( sci_frame, order_frame,
					  slitmap_frame, wavemap_frame,
					  local_frame, sky_line_list_frame, 
                                          NULL,NULL,instrument,
					  sky_par.nbkpts1, &sky_par,
                                          &sky_spectrum,&sky_spectrum_eso,
					  "test",1));


/*
  tag = "SKY_MODEL";
  sky_frame_ima= xsh_save_sky_model( sci_frame, result, tag);
*/

  cleanup:
    xsh_instrument_free( &instrument);
    xsh_free_frame( &sci_frame);
    xsh_free_frame( &order_frame);
    xsh_free_frame( &slitmap_frame);
    xsh_free_frame( &wavemap_frame);
    xsh_free_frame( &local_frame);
    xsh_free_frame( &sky_spectrum);
    xsh_free_frame( &sky_spectrum_eso);
    xsh_free_frame( &result);
    xsh_free_propertylist( &plist);

    if ( cpl_error_get_code() != CPL_ERROR_NONE ) {
      xsh_msg( "ERROR in xsh_subtract_sky_single" ) ;
      xsh_error_dump( CPL_MSG_ERROR);
      ret=1;
    }
    TEST_END();
    return ret;
}
