/*                                                                          *
 *   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: 2013-05-14 07:02:49 $
 * $Revision: 1.41 $
 */

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

/*-------------------------------------------------------------------------*/
/**
 * @defgroup test_xsh_remove_crh_single  Test Remove Crh Multi function(s)
 * @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_spectrum.h>
#include <xsh_data_localization.h>
#include <xsh_drl.h>
#include <xsh_pfits.h>
#include <xsh_parameters.h>
#include <xsh_badpixelmap.h>

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

#include <string.h>
#include <getopt.h>

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

#define MODULE_ID "XSH_LOCALIZE_OBJ"

enum {
  NBCHUNK_OPT, TRESHOLD_OPT, DEG_POLY_OPT, METHOD_OPT, SLIT_POS_OPT,
  SLIT_HHEIGHT_OPT, KAPPA_OPT, NITER_OPT, SKYMASK_OPT, HELP_OPT
} ;

static struct option long_options[] = {
  {"nbchunk", required_argument, 0,  NBCHUNK_OPT},
  {"threshold", required_argument, 0, TRESHOLD_OPT},
  {"deg_poly", required_argument, 0, DEG_POLY_OPT},
  {"method", required_argument, 0, METHOD_OPT},
  {"slit_position", required_argument, 0, SLIT_POS_OPT},
  {"slit_hheight", required_argument, 0,  SLIT_HHEIGHT_OPT},
  {"kappa", required_argument, 0,  KAPPA_OPT},
  {"niter", required_argument, 0,  NITER_OPT},
  {"skymask", required_argument, 0,  SKYMASK_OPT},
  {"help", 0, 0, HELP_OPT},
  {0, 0, 0, 0}
};

static void Help( void )
{
  puts( "Unitary test of Localization");
  puts( "Usage: test_xsh_localize_obj [options] REC_FRAME [LOC_TABLE]");

  puts( "Options" ) ;
  puts( " --help             : What you see" ) ;
  puts( " --method=          : MANUAL | AUTO | GAUSSIAN [GAUSSIAN]");
  puts( "  MANUAL options");
  puts( "   --slit_position=<n>: (MANUAL only) the reference slit position in arcsec [0]");
  puts( "   --slit_hheight=<n> : (MANUAL only) the half size of slit height in arcsec [0.5]");
  puts( "  AUTO or GAUSSIAN options");
  puts( "   --deg_poly=<n>     : (AUTO, GAUSSIAN) polynomial degree of fit [0]");
  puts( "   --niter=<n>        : (AUTO, GAUSSIAN)  Number of iterations for sigma clipping[3]");
  puts( "   --kappa=<n>        : (AUTO, GAUSSIAN)  Kappa for sigma clipping [1.0]");
  puts( "   --nbchunk=<n>      : (AUTO, GAUSSIAN)  Number of chunk [10]");
  puts( "   --skymask=<file>   : (AUTO, GAUSSIAN)  Sky mask file");
  puts( "  AUTO options");
  puts( "   --threshold=<n>    : (AUTO) Threshold to find edges [10]");
  puts( "\nInput Files" ) ;
  puts( "The input files argument MUST be in this order:" ) ;
  puts( " 1. DRL rectified 2D frame tag DRL_ORDER2D" ) ;
  puts( " 2. (optional] Localization table" );
  TEST_END();
}


static void HandleOptions( int argc, char **argv, 
  xsh_localize_obj_param *loc_par, char **skymask_name)
{
  int opt ;
  int option_index = 0;

  while (( opt = getopt_long (argc, argv, 
    "nbchunk:threshold:deg_poly:method:slit_position:slit_hheight",
    long_options, &option_index)) != EOF ){
  
    switch ( opt ) {
    case  NBCHUNK_OPT:
      loc_par->loc_chunk_nb = atoi(optarg);
      break ; 
    case TRESHOLD_OPT:
      loc_par->loc_thresh = atof(optarg);
      break ;
    case DEG_POLY_OPT:
      loc_par->loc_deg_poly = atoi(optarg);
      break;
    case METHOD_OPT:
      if ( strcmp(optarg, LOCALIZE_METHOD_PRINT(LOC_MANUAL_METHOD)) == 0){
        loc_par->method = LOC_MANUAL_METHOD;
      }
      else if ( strcmp(optarg, LOCALIZE_METHOD_PRINT(LOC_MAXIMUM_METHOD)) == 0){
        loc_par->method = LOC_MAXIMUM_METHOD;
      }
      else if ( strcmp(optarg, LOCALIZE_METHOD_PRINT(LOC_GAUSSIAN_METHOD)) == 0){
        loc_par->method = LOC_GAUSSIAN_METHOD;
      }
      else{
        xsh_msg("WRONG method %s", optarg);
        exit(-1);
      }
      break;

    case SLIT_POS_OPT:
      loc_par->slit_position = atof( optarg);
      break ;
    case SLIT_HHEIGHT_OPT:
      loc_par->slit_hheight = atof( optarg);
      break;
    case KAPPA_OPT:
      loc_par->kappa = atof( optarg);
      break;
    case NITER_OPT:
      loc_par->niter = atoi( optarg);
      break;
    case SKYMASK_OPT:
      loc_par->use_skymask = TRUE;
      *skymask_name = optarg;
      break;

    default: 
      Help(); exit(-1);
    }
  }
  return;
}




static void analyse_localization( cpl_frame *merge_frame, cpl_frame* loc_frame, 
  xsh_instrument* instr);

/*--------------------------------------------------------------------------
  Implementation
  --------------------------------------------------------------------------*/
static void analyse_localization( cpl_frame* rec_frame, cpl_frame* loc_frame,
   xsh_instrument* instr)
{
  const char* rec_name = NULL;
  cpl_frame* merge_frame = NULL;
  const char* loc_name = NULL;
  xsh_localization *loc_list = NULL;
  xsh_spectrum *spectrum = NULL;
  int ilambda;
  FILE *loc_regfile = NULL ;
  FILE *loc_datfile = NULL;
  int merge_par = 0;
  //const int decode_bp=2147483647;
  XSH_ASSURE_NOT_NULL( rec_frame);
  XSH_ASSURE_NOT_NULL( loc_frame);

  check( rec_name = cpl_frame_get_filename( rec_frame));
  check( loc_name = cpl_frame_get_filename( loc_frame));

  xsh_msg("---Dump the localization");
  printf("DRL RECTIFY frame : %s\n", rec_name);
  printf("LOCALIZE    frame : %s\n", loc_name);

  check( merge_frame =  xsh_merge_ord( rec_frame, instr, merge_par,
                                       "TEST_MERGE"));
  
  check( spectrum = xsh_spectrum_load( merge_frame));
  check( loc_list = xsh_localization_load( loc_frame));

  loc_regfile = fopen( "LOCALIZATION.reg", "w");
  fprintf(loc_regfile, "# Region file format: DS9 version 4.0\n"\
    "#red center, blue low, green up\n"\
    "global color=red font=\"helvetica 4 normal\""\
    "select=1 highlite=1 edit=1 move=1 delete=1 include=1 fixed=0"\
    " source=1\nwcs\n");

  loc_datfile = fopen( "LOCALIZATION.dat", "w");
  fprintf( loc_datfile, "#lambda slow scen sup\n");

  for( ilambda=0; ilambda < spectrum->size_lambda; ilambda++){
    double slit_cen = 0.0, slit_low= 0.0, slit_up = 0.0;
    double lambda;

    lambda = spectrum->lambda_min+ilambda*spectrum->lambda_step; 
    check( slit_cen = cpl_polynomial_eval_1d( loc_list->cenpoly, 
      lambda, NULL));
    check( slit_low = cpl_polynomial_eval_1d( loc_list->edglopoly,
      lambda, NULL));
    check( slit_up = cpl_polynomial_eval_1d( loc_list->edguppoly,
      lambda, NULL));
    fprintf( loc_regfile, "point(%f,%f) "\
      "#point=cross color=red font=\"helvetica 4 normal\"\n", lambda, slit_cen);
    fprintf( loc_regfile, "point(%f,%f) "\
      "#point=cross color=blue font=\"helvetica 4 normal\"\n", lambda, slit_low);
    fprintf( loc_regfile, "point(%f,%f) "\
      "#point=cross color=green font=\"helvetica 4 normal\"\n", lambda, slit_up);
    fprintf( loc_datfile, "%f %f %f %f\n", lambda, slit_low, slit_cen, slit_up);
  }

  xsh_msg( "Produce ds9 region file : LOCALIZATION.reg");
  xsh_msg( "Produce data file : LOCALIZATION.dat");
  xsh_msg(" Produce MERGE frame : %s", cpl_frame_get_filename( merge_frame));

  cleanup:
  if(loc_regfile != NULL) {
    fclose( loc_regfile);
  }

  if(loc_datfile != NULL) {
    fclose( loc_datfile);
  }
    xsh_free_frame( &merge_frame);
    xsh_spectrum_free( &spectrum);
    xsh_localization_free( &loc_list);

    return;
}

/**
  @brief
    Unit test of xsh_localize_obj
  @return
    0 if success

*/
int main( int argc, char **argv)
{
  /* Declarations */
  int ret = 0 ;
  xsh_instrument* instrument = NULL;
  xsh_localize_obj_param loc_obj = 
    { 10, 0.1, 1, 0., LOC_MANUAL_METHOD, 0.0, 0.5, 3,3, FALSE};
  char* rec_name = NULL;
  cpl_frame *rec_frame = NULL;
 
  const char *tag = NULL;
  char* loc_name = NULL;
  cpl_frame* loc_frame = NULL; 
  cpl_propertylist *plist = NULL;
  XSH_ARM arm = XSH_ARM_UNDEFINED;
  char * skymask_name = NULL;
  cpl_frame *skymask_frame = NULL;
  const int decode_bp=2147483647;
  /* Initialize libraries */
  TESTS_INIT(MODULE_ID);

  cpl_msg_set_level(CPL_MSG_DEBUG);
  xsh_debug_level_set(XSH_DEBUG_LEVEL_MEDIUM);

  loc_obj.kappa = 1.0;
  loc_obj.niter = 3;
  loc_obj.method=LOC_GAUSSIAN_METHOD;
  loc_obj.loc_deg_poly = 0;
  loc_obj.loc_chunk_nb = 10;

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

  if ( (argc - optind) > 0 ) {
    rec_name = argv[optind];
    if ((argc - optind) > 1){
      loc_name = argv[optind+1];
    }
  }
  else {
    Help();
    exit( 0);
  }
  
  check( plist = cpl_propertylist_load( rec_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");
  xsh_instrument_set_decode_bp( instrument, decode_bp ) ;
  tag = XSH_GET_TAG_FROM_ARM( XSH_MERGE2D, instrument);

  TESTS_XSH_FRAME_CREATE( rec_frame, tag, rec_name);
  
  xsh_msg("---Input Frames");
  xsh_msg("DRL RECTIFY frame : %s tag %s", rec_name, tag);
  
  if (loc_name == NULL){
    xsh_msg( "---Localize parameters");
    xsh_msg( "  --method %s ", LOCALIZE_METHOD_PRINT(loc_obj.method));
    if ( loc_obj.method == LOC_MANUAL_METHOD){
      xsh_msg("  slit_position : %f",loc_obj.slit_position);
      xsh_msg("  slit_hheight : %f",loc_obj.slit_hheight);
    }
    else {
      if (loc_obj.method == LOC_MAXIMUM_METHOD){
        xsh_msg("  threshold : %f",loc_obj.loc_thresh);
      }
      xsh_msg("  nb_chunks : %d",loc_obj.loc_chunk_nb);
      xsh_msg("  deg_poly  : %d",loc_obj.loc_deg_poly);
      xsh_msg("  kappa     : %f", loc_obj.kappa);
      xsh_msg("  niter     : %d", loc_obj.niter);
      if ( loc_obj.use_skymask == TRUE){
        xsh_msg("  skymask     : %s", skymask_name);
        tag = XSH_GET_TAG_FROM_ARM( XSH_SKY_LINE_LIST, instrument);
        TESTS_XSH_FRAME_CREATE( skymask_frame, tag, skymask_name);
      }
    }
    check( loc_frame = xsh_localize_obj( rec_frame, skymask_frame, instrument, &loc_obj,
      NULL, "LOCALIZE_TABLE.fits"));
  }
  else{
    XSH_ASSURE_NOT_NULL (loc_name);
    tag = XSH_GET_TAG_FROM_ARM( XSH_LOCALIZATION, instrument);
    TESTS_XSH_FRAME_CREATE( loc_frame, tag, loc_name);
  }

  /* Create REGION FILES for rectify */
  check( analyse_localization( rec_frame, loc_frame, instrument)); 

  cleanup:
    xsh_free_frame( &loc_frame);
    xsh_free_frame( & rec_frame);
    xsh_free_frame( &skymask_frame);
    xsh_instrument_free( &instrument);
    xsh_free_propertylist( &plist);    

    if (cpl_error_get_code() != CPL_ERROR_NONE) {
      xsh_error_dump(CPL_MSG_ERROR);
      ret=1;
    }
    TEST_END();
    return ret ;
}

/**@}*/
