/*                                                                          *
 *   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-07 16:51:34 $
 * $Revision: 1.13 $
 */

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

/*-------------------------------------------------------------------------*/
/**
  @defgroup test_xsh_opt_extract  Test Object optimal extraction
  @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_rec.h>
#include <xsh_data_localization.h>
#include <xsh_data_spectrum.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_LAMBDA_ERR"

enum {
  MIN_ORDER_OPT, MAX_ORDER_OPT, DEBUG_OPT, HELP_OPT
};

static struct option long_options[] = {
  {"order-min", required_argument, 0, MIN_ORDER_OPT},
  {"order-max", required_argument, 0, MAX_ORDER_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_lambda_err");
  puts( "Usage: test_xsh_lambda_err [options] <input_files>");

  puts( "Options" ) ;
  puts( " --order-min=<n>    : Minimum abs order" );
  puts( " --order-max=<n>    : Maximum abs order" );
  puts( " --debug=<n>        : Level of debug LOW | MEDIUM | HIGH [MEDIUM]" );
  puts( " --help             : What you see" ) ;
  puts( "\nInput Files" ) ;
  puts( "The input files argument MUST be in this order:" ) ;
  puts( " 1. Science frame in PRE format" ) ;
  puts( " 2. Localization table" );
  puts( " 3. SOF [SPECTRAL_FORMAT, WAVEMAP, SLITMAP]\n" ) ;
  TEST_END();
}

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

  while (( opt = getopt_long (argc, argv, "oversample:box-hsize:chunk-size",
    long_options, &option_index)) != EOF ){

    switch ( opt ) {
    case MIN_ORDER_OPT:
      sscanf( optarg, "%64d", order_min);
      break;
    case MAX_ORDER_OPT:
      sscanf( optarg, "%64d", order_max);
      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:
      Help();
      exit(-1);
    }
  }
  return;
}

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

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

*/
int main( int argc, char **argv)
{
  int ret;
  /* Declarations */
  xsh_instrument* instrument = NULL;
  const char *sof_name = NULL;
  cpl_frameset *set = NULL;
 
  const char* sci_name = NULL;
  const char* loc_name = NULL;
  int order_min = -1;
  int order_max = -1;
  int rec_min_index = -1;
  int rec_max_index = -1;
  int iorder = 0;

  cpl_propertylist *header = NULL;
  const char* pcatg = NULL;
  xsh_order_list* order_list = NULL;
  xsh_pre *pre = NULL;
  float *pre_flux = NULL;
  float *pre_errs = NULL;

  cpl_image *wavemap = NULL;
  cpl_image *slitmap = NULL;
  float* wavemap_data = NULL;
  float* slitmap_data = NULL;
  int nx;
  xsh_rec_list *rec_list = NULL;
  xsh_localization *loc_list = NULL;
  double obj_slit;
  xsh_spectrum *spectrum = NULL;

  char name[256];
  FILE *file = NULL;
  char *pch = NULL;
  const char *prefix = NULL;

  cpl_frame *sci_frame = NULL;
  cpl_frame *loc_frame = NULL;
  cpl_frame *orderlist_frame = NULL;
  cpl_frame *wavemap_frame = NULL;
  cpl_frame *slitmap_frame = NULL;
  cpl_frame *spectralformat_frame = NULL;

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

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

  if ( (argc - optind) >= 3 ) {
    sci_name = argv[optind];
    loc_name = argv[optind+1];
    sof_name = argv[optind+2];
  }
  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( spectralformat_frame = xsh_find_spectral_format( set, instrument));
  check( orderlist_frame = xsh_find_order_tab_edges( set, instrument));
  check( wavemap_frame = xsh_find_wavemap( set, instrument));
  check( slitmap_frame = xsh_find_slitmap( set, instrument));

  TESTS_XSH_FRAME_CREATE( sci_frame, "OBJECT_SLIT_STARE_arm", sci_name);
  TESTS_XSH_FRAME_CREATE( loc_frame, "LOCALIZATION_arm", loc_name);
  /* USE load function */
  xsh_msg("SCI            : %s",
    cpl_frame_get_filename( sci_frame));
  xsh_msg("LOCALIZATION   : %s",
    cpl_frame_get_filename( loc_frame));
  xsh_msg("ORDERLIST      : %s",
    cpl_frame_get_filename( orderlist_frame));
  xsh_msg("SPECTRALFORMAT : %s",
    cpl_frame_get_filename( spectralformat_frame)); 
  xsh_msg("WAVEMAP        : %s",
    cpl_frame_get_filename( wavemap_frame));
  xsh_msg("SLITMAP        : %s",
    cpl_frame_get_filename( slitmap_frame));

  pch=strrchr( sci_name,'/');
  if ( pch == NULL){
    prefix = sci_name;
  }
  else{
    prefix = pch+1;
  }

  check( order_list = xsh_order_list_load ( orderlist_frame, instrument));

  if ( order_min != -1) {
    check( rec_min_index = xsh_order_list_get_index_by_absorder( order_list,
      order_min));
    xsh_msg("Order min %d => index %d", order_min, rec_min_index);
  }
  else{
    rec_min_index = 0;
  }

  if ( order_max != -1) {
    check( rec_max_index = xsh_order_list_get_index_by_absorder( order_list,
      order_max));
    xsh_msg("Order max %d => index %d", order_max, rec_max_index);
  }
  else{
    rec_max_index = order_list->size-1;
    xsh_msg("Doing all %d orders", order_list->size);
  }
  /* load wavemap */
  check( wavemap = cpl_image_load( cpl_frame_get_filename(  wavemap_frame),
    CPL_TYPE_FLOAT, 0, 0));
  check( slitmap = cpl_image_load( cpl_frame_get_filename(  slitmap_frame),
    CPL_TYPE_FLOAT, 0, 0));

  check( nx = cpl_image_get_size_x( wavemap));
  check( wavemap_data = cpl_image_get_data_float( wavemap));
  check( slitmap_data = cpl_image_get_data_float( slitmap));

  check( loc_list = xsh_localization_load( loc_frame));
  obj_slit = cpl_polynomial_eval_1d( loc_list->cenpoly,
    600, NULL);

  xsh_msg("Localization center is around %f arcsec", obj_slit);

  check( header = cpl_propertylist_load( sci_name, 0));
  pcatg = xsh_pfits_get_pcatg( header);

  if (strstr( pcatg, "ORDER2D") != NULL){
    double slit_step=0;
    int nslit=0, s=0;
    float *slitdata=NULL; 

    xsh_msg("Rectified frame");
    check( rec_list = xsh_rec_list_load( sci_frame, instrument));
    check( nslit = xsh_rec_list_get_nslit( rec_list, 0));
    check( slitdata = xsh_rec_list_get_slit( rec_list, 0));
    check( slit_step = xsh_pfits_get_rectify_bin_space( header));
    s = (int) xsh_round_double( (obj_slit-slitdata[0]) / slit_step);
    xsh_msg("s index %d/%d", s, nslit);

    for( iorder=rec_min_index; iorder<= rec_max_index; iorder++){
      int nlambda=0;
      double *lambdadata = NULL;
      float *flux = NULL, *errs = NULL;
      int abs_order=0;
      int ilambda;

      check( nlambda = xsh_rec_list_get_nlambda( rec_list, iorder));
      check( abs_order = xsh_rec_list_get_order( rec_list, iorder));
      check( lambdadata = xsh_rec_list_get_lambda( rec_list, iorder));
      check( flux = xsh_rec_list_get_data1( rec_list, iorder));
      check( errs = xsh_rec_list_get_errs1( rec_list, iorder));

      sprintf( name, "%s_lambda_err_%d.dat", prefix, abs_order);

      xsh_msg("Name %s", name);

      file = fopen( name, "w");

      fprintf( file, "#lambda flux err sn\n");

      for( ilambda =0; ilambda < nlambda; ilambda++){
        double lambda_v;
        double flux_v, err_v;
        double sn; 
        
        lambda_v = lambdadata[ilambda];
        flux_v = flux[ilambda+nlambda*s];
        err_v = errs[ilambda+nlambda*s];
        sn = flux_v/err_v;
        fprintf( file, "%f %f %f %f\n", lambda_v, flux_v, err_v,
          sn);
      }
      fclose( file);
    }
  
  }
  else if( strstr( pcatg, "MERGE2D") != NULL){
    xsh_msg("Merge frame");
    double *flux = NULL;
    double *errs = NULL;
    int s, ilambda;

    check( spectrum = xsh_spectrum_load( sci_frame));
    s = (int) round( (obj_slit-spectrum->slit_min) / spectrum->slit_step);
    xsh_msg("s index %d/%d", s, spectrum->size_slit);
    check( flux = xsh_spectrum_get_flux( spectrum));
    check( errs = xsh_spectrum_get_errs(spectrum));
    sprintf( name, "%s_lambda_err.dat", prefix);
    file = fopen( name,"w");
    fprintf( file, "#lambda flux err sn\n");

    for(ilambda=0; ilambda< spectrum->size_lambda; ilambda++){
      double lambda_v;
      double flux_v, err_v;
      double sn;

      lambda_v = spectrum->lambda_min+ilambda*spectrum->lambda_step;
      flux_v = flux[ilambda+s*spectrum->size_lambda];
      err_v = errs[ilambda+s*spectrum->size_lambda];
      sn = flux_v/err_v;
      fprintf( file, "%f %f %f %f\n", lambda_v, flux_v, err_v, sn);
    }
    fclose( file);
  }
  else{
    /* load image */
    check( pre = xsh_pre_load( sci_frame, instrument));
    check( pre_errs = cpl_image_get_data_float( pre->errs));
    check( pre_flux = cpl_image_get_data_float( pre->data));

    xsh_msg("Work with frame in PRE format binning: %dx%d", pre->binx, pre->biny);

    check( xsh_order_list_set_bin_x( order_list, pre->binx));
    check( xsh_order_list_set_bin_y( order_list, pre->biny)); 

    xsh_msg("Generate files");
    for( iorder=rec_min_index; iorder<= rec_max_index; iorder++){
      int abs_order, start_y, end_y;
      int y, x;

      check( start_y = xsh_order_list_get_starty( order_list, iorder));
      check( end_y = xsh_order_list_get_endy( order_list, iorder));
      abs_order = order_list->list[iorder].absorder;

      sprintf( name, "%s_lambda_err_%d.dat", prefix, abs_order);

      file = fopen( name, "w");
      fprintf( file, "#lambda flux err sn\n");

      for(y=start_y; y <= end_y; y++){
        double lambda;
        double slit;
        double err, flux;
        double sn;
        double diff=12;
        int xlow, xup, xnear=0;

        check( xlow = xsh_order_list_eval_int( order_list,
          order_list->list[iorder].edglopoly, y));
        check( xup = xsh_order_list_eval_int( order_list,
          order_list->list[iorder].edguppoly, y));

        for( x=xlow-1; x < xup; x++){
          slit = slitmap_data[x+(y-1)*nx];
         if ( fabs( slit-obj_slit) < diff){
            if ( wavemap_data[x+(y-1)*nx] > 0){
              diff = fabs( slit-obj_slit);
              xnear = x;
            }
          }
        }
        lambda = wavemap_data[xnear+(y-1)*nx];
        if (lambda > 0){
          err = pre_errs[xnear+(y-1)*nx];
          flux = pre_flux[xnear+(y-1)*nx];
          sn = flux/err;
          fprintf( file, "%f %f %f %f\n", lambda, flux, err, sn);
        }
        else {
          xsh_msg("Skipping Lambda %f for x %d y %d", lambda, xnear, y);
        }
      }
      fclose( file);
    }
  }

  cleanup:
    if (cpl_error_get_code() != CPL_ERROR_NONE) {
      xsh_error_dump(CPL_MSG_ERROR);
      ret = 1;
    }
    if(file != NULL) {
      fclose( file);
    }
    xsh_order_list_free( &order_list);
    xsh_pre_free( &pre);
    xsh_free_image( &wavemap);
    xsh_free_image( &slitmap);
    xsh_free_propertylist( &header);
    xsh_rec_list_free( &rec_list);
    xsh_localization_free( &loc_list);
    xsh_free_frame( &sci_frame);
    xsh_free_frame( &loc_frame);
    xsh_spectrum_free( &spectrum);
    xsh_free_frameset( &set);
    xsh_instrument_free( &instrument);
  
    TEST_END();
    return ret;
}

/**@}*/
